diff -Nru corsix-th-0.30/agg/authors corsix-th-0.62/agg/authors --- corsix-th-0.30/agg/authors 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/authors 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) diff -Nru corsix-th-0.30/agg/ChangeLog corsix-th-0.62/agg/ChangeLog --- corsix-th-0.30/agg/ChangeLog 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/ChangeLog 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -Visit http://antigrain.com/news \ No newline at end of file diff -Nru corsix-th-0.30/agg/copying corsix-th-0.62/agg/copying --- corsix-th-0.30/agg/copying 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/copying 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -The Anti-Grain Geometry Project -A high quality rendering engine for C++ -http://antigrain.com - -Anti-Grain Geometry has dual licensing model. The Modified BSD -License was first added in version v2.4 just for convenience. -It is a simple, permissive non-copyleft free software license, -compatible with the GNU GPL. It's well proven and recognizable. -See http://www.fsf.org/licensing/licenses/index_html#ModifiedBSD -for details. - -Note that the Modified BSD license DOES NOT restrict your rights -if you choose the Anti-Grain Geometry Public License. - - - - -Anti-Grain Geometry Public License -==================================================== - -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) - -Permission to copy, use, modify, sell and distribute this software -is granted provided this copyright notice appears in all copies. -This software is provided "as is" without express or implied -warranty, and with no claim as to its suitability for any purpose. - - - - - -Modified BSD License -==================================================== -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - diff -Nru corsix-th-0.30/agg/include/agg_alpha_mask_u8.h corsix-th-0.62/agg/include/agg_alpha_mask_u8.h --- corsix-th-0.30/agg/include/agg_alpha_mask_u8.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_alpha_mask_u8.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,499 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// scanline_u8 class -// -//---------------------------------------------------------------------------- -#ifndef AGG_ALPHA_MASK_U8_INCLUDED -#define AGG_ALPHA_MASK_U8_INCLUDED - -#include -#include "agg_basics.h" -#include "agg_rendering_buffer.h" - -namespace agg -{ - //===================================================one_component_mask_u8 - struct one_component_mask_u8 - { - static unsigned calculate(const int8u* p) { return *p; } - }; - - - //=====================================================rgb_to_gray_mask_u8 - template - struct rgb_to_gray_mask_u8 - { - static unsigned calculate(const int8u* p) - { - return (p[R]*77 + p[G]*150 + p[B]*29) >> 8; - } - }; - - //==========================================================alpha_mask_u8 - template - class alpha_mask_u8 - { - public: - typedef int8u cover_type; - typedef alpha_mask_u8 self_type; - enum cover_scale_e - { - cover_shift = 8, - cover_none = 0, - cover_full = 255 - }; - - alpha_mask_u8() : m_rbuf(0) {} - explicit alpha_mask_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {} - - void attach(rendering_buffer& rbuf) { m_rbuf = &rbuf; } - - MaskF& mask_function() { return m_mask_function; } - const MaskF& mask_function() const { return m_mask_function; } - - - //-------------------------------------------------------------------- - cover_type pixel(int x, int y) const - { - if(x >= 0 && y >= 0 && - x < (int)m_rbuf->width() && - y < (int)m_rbuf->height()) - { - return (cover_type)m_mask_function.calculate( - m_rbuf->row_ptr(y) + x * Step + Offset); - } - return 0; - } - - //-------------------------------------------------------------------- - cover_type combine_pixel(int x, int y, cover_type val) const - { - if(x >= 0 && y >= 0 && - x < (int)m_rbuf->width() && - y < (int)m_rbuf->height()) - { - return (cover_type)((cover_full + val * - m_mask_function.calculate( - m_rbuf->row_ptr(y) + x * Step + Offset)) >> - cover_shift); - } - return 0; - } - - - //-------------------------------------------------------------------- - void fill_hspan(int x, int y, cover_type* dst, int num_pix) const - { - int xmax = m_rbuf->width() - 1; - int ymax = m_rbuf->height() - 1; - - int count = num_pix; - cover_type* covers = dst; - - if(y < 0 || y > ymax) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - - if(x < 0) - { - count += x; - if(count <= 0) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - memset(covers, 0, -x * sizeof(cover_type)); - covers -= x; - x = 0; - } - - if(x + count > xmax) - { - int rest = x + count - xmax - 1; - count -= rest; - if(count <= 0) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - memset(covers + count, 0, rest * sizeof(cover_type)); - } - - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; - do - { - *covers++ = (cover_type)m_mask_function.calculate(mask); - mask += Step; - } - while(--count); - } - - - //-------------------------------------------------------------------- - void combine_hspan(int x, int y, cover_type* dst, int num_pix) const - { - int xmax = m_rbuf->width() - 1; - int ymax = m_rbuf->height() - 1; - - int count = num_pix; - cover_type* covers = dst; - - if(y < 0 || y > ymax) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - - if(x < 0) - { - count += x; - if(count <= 0) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - memset(covers, 0, -x * sizeof(cover_type)); - covers -= x; - x = 0; - } - - if(x + count > xmax) - { - int rest = x + count - xmax - 1; - count -= rest; - if(count <= 0) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - memset(covers + count, 0, rest * sizeof(cover_type)); - } - - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; - do - { - *covers = (cover_type)((cover_full + (*covers) * - m_mask_function.calculate(mask)) >> - cover_shift); - ++covers; - mask += Step; - } - while(--count); - } - - //-------------------------------------------------------------------- - void fill_vspan(int x, int y, cover_type* dst, int num_pix) const - { - int xmax = m_rbuf->width() - 1; - int ymax = m_rbuf->height() - 1; - - int count = num_pix; - cover_type* covers = dst; - - if(x < 0 || x > xmax) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - - if(y < 0) - { - count += y; - if(count <= 0) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - memset(covers, 0, -y * sizeof(cover_type)); - covers -= y; - y = 0; - } - - if(y + count > ymax) - { - int rest = y + count - ymax - 1; - count -= rest; - if(count <= 0) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - memset(covers + count, 0, rest * sizeof(cover_type)); - } - - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; - do - { - *covers++ = (cover_type)m_mask_function.calculate(mask); - mask += m_rbuf->stride(); - } - while(--count); - } - - //-------------------------------------------------------------------- - void combine_vspan(int x, int y, cover_type* dst, int num_pix) const - { - int xmax = m_rbuf->width() - 1; - int ymax = m_rbuf->height() - 1; - - int count = num_pix; - cover_type* covers = dst; - - if(x < 0 || x > xmax) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - - if(y < 0) - { - count += y; - if(count <= 0) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - memset(covers, 0, -y * sizeof(cover_type)); - covers -= y; - y = 0; - } - - if(y + count > ymax) - { - int rest = y + count - ymax - 1; - count -= rest; - if(count <= 0) - { - memset(dst, 0, num_pix * sizeof(cover_type)); - return; - } - memset(covers + count, 0, rest * sizeof(cover_type)); - } - - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; - do - { - *covers = (cover_type)((cover_full + (*covers) * - m_mask_function.calculate(mask)) >> - cover_shift); - ++covers; - mask += m_rbuf->stride(); - } - while(--count); - } - - - private: - alpha_mask_u8(const self_type&); - const self_type& operator = (const self_type&); - - rendering_buffer* m_rbuf; - MaskF m_mask_function; - }; - - - typedef alpha_mask_u8<1, 0> alpha_mask_gray8; //----alpha_mask_gray8 - - typedef alpha_mask_u8<3, 0> alpha_mask_rgb24r; //----alpha_mask_rgb24r - typedef alpha_mask_u8<3, 1> alpha_mask_rgb24g; //----alpha_mask_rgb24g - typedef alpha_mask_u8<3, 2> alpha_mask_rgb24b; //----alpha_mask_rgb24b - - typedef alpha_mask_u8<3, 2> alpha_mask_bgr24r; //----alpha_mask_bgr24r - typedef alpha_mask_u8<3, 1> alpha_mask_bgr24g; //----alpha_mask_bgr24g - typedef alpha_mask_u8<3, 0> alpha_mask_bgr24b; //----alpha_mask_bgr24b - - typedef alpha_mask_u8<4, 0> alpha_mask_rgba32r; //----alpha_mask_rgba32r - typedef alpha_mask_u8<4, 1> alpha_mask_rgba32g; //----alpha_mask_rgba32g - typedef alpha_mask_u8<4, 2> alpha_mask_rgba32b; //----alpha_mask_rgba32b - typedef alpha_mask_u8<4, 3> alpha_mask_rgba32a; //----alpha_mask_rgba32a - - typedef alpha_mask_u8<4, 1> alpha_mask_argb32r; //----alpha_mask_argb32r - typedef alpha_mask_u8<4, 2> alpha_mask_argb32g; //----alpha_mask_argb32g - typedef alpha_mask_u8<4, 3> alpha_mask_argb32b; //----alpha_mask_argb32b - typedef alpha_mask_u8<4, 0> alpha_mask_argb32a; //----alpha_mask_argb32a - - typedef alpha_mask_u8<4, 2> alpha_mask_bgra32r; //----alpha_mask_bgra32r - typedef alpha_mask_u8<4, 1> alpha_mask_bgra32g; //----alpha_mask_bgra32g - typedef alpha_mask_u8<4, 0> alpha_mask_bgra32b; //----alpha_mask_bgra32b - typedef alpha_mask_u8<4, 3> alpha_mask_bgra32a; //----alpha_mask_bgra32a - - typedef alpha_mask_u8<4, 3> alpha_mask_abgr32r; //----alpha_mask_abgr32r - typedef alpha_mask_u8<4, 2> alpha_mask_abgr32g; //----alpha_mask_abgr32g - typedef alpha_mask_u8<4, 1> alpha_mask_abgr32b; //----alpha_mask_abgr32b - typedef alpha_mask_u8<4, 0> alpha_mask_abgr32a; //----alpha_mask_abgr32a - - typedef alpha_mask_u8<3, 0, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_rgb24gray; //----alpha_mask_rgb24gray - typedef alpha_mask_u8<3, 0, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_bgr24gray; //----alpha_mask_bgr24gray - typedef alpha_mask_u8<4, 0, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_rgba32gray; //----alpha_mask_rgba32gray - typedef alpha_mask_u8<4, 1, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_argb32gray; //----alpha_mask_argb32gray - typedef alpha_mask_u8<4, 0, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_bgra32gray; //----alpha_mask_bgra32gray - typedef alpha_mask_u8<4, 1, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_abgr32gray; //----alpha_mask_abgr32gray - - - - //==========================================================amask_no_clip_u8 - template - class amask_no_clip_u8 - { - public: - typedef int8u cover_type; - typedef amask_no_clip_u8 self_type; - enum cover_scale_e - { - cover_shift = 8, - cover_none = 0, - cover_full = 255 - }; - - amask_no_clip_u8() : m_rbuf(0) {} - explicit amask_no_clip_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {} - - void attach(rendering_buffer& rbuf) { m_rbuf = &rbuf; } - - MaskF& mask_function() { return m_mask_function; } - const MaskF& mask_function() const { return m_mask_function; } - - - //-------------------------------------------------------------------- - cover_type pixel(int x, int y) const - { - return (cover_type)m_mask_function.calculate( - m_rbuf->row_ptr(y) + x * Step + Offset); - } - - - //-------------------------------------------------------------------- - cover_type combine_pixel(int x, int y, cover_type val) const - { - return (cover_type)((cover_full + val * - m_mask_function.calculate( - m_rbuf->row_ptr(y) + x * Step + Offset)) >> - cover_shift); - } - - - //-------------------------------------------------------------------- - void fill_hspan(int x, int y, cover_type* dst, int num_pix) const - { - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; - do - { - *dst++ = (cover_type)m_mask_function.calculate(mask); - mask += Step; - } - while(--num_pix); - } - - - - //-------------------------------------------------------------------- - void combine_hspan(int x, int y, cover_type* dst, int num_pix) const - { - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; - do - { - *dst = (cover_type)((cover_full + (*dst) * - m_mask_function.calculate(mask)) >> - cover_shift); - ++dst; - mask += Step; - } - while(--num_pix); - } - - - //-------------------------------------------------------------------- - void fill_vspan(int x, int y, cover_type* dst, int num_pix) const - { - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; - do - { - *dst++ = (cover_type)m_mask_function.calculate(mask); - mask += m_rbuf->stride(); - } - while(--num_pix); - } - - - //-------------------------------------------------------------------- - void combine_vspan(int x, int y, cover_type* dst, int num_pix) const - { - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; - do - { - *dst = (cover_type)((cover_full + (*dst) * - m_mask_function.calculate(mask)) >> - cover_shift); - ++dst; - mask += m_rbuf->stride(); - } - while(--num_pix); - } - - private: - amask_no_clip_u8(const self_type&); - const self_type& operator = (const self_type&); - - rendering_buffer* m_rbuf; - MaskF m_mask_function; - }; - - - typedef amask_no_clip_u8<1, 0> amask_no_clip_gray8; //----amask_no_clip_gray8 - - typedef amask_no_clip_u8<3, 0> amask_no_clip_rgb24r; //----amask_no_clip_rgb24r - typedef amask_no_clip_u8<3, 1> amask_no_clip_rgb24g; //----amask_no_clip_rgb24g - typedef amask_no_clip_u8<3, 2> amask_no_clip_rgb24b; //----amask_no_clip_rgb24b - - typedef amask_no_clip_u8<3, 2> amask_no_clip_bgr24r; //----amask_no_clip_bgr24r - typedef amask_no_clip_u8<3, 1> amask_no_clip_bgr24g; //----amask_no_clip_bgr24g - typedef amask_no_clip_u8<3, 0> amask_no_clip_bgr24b; //----amask_no_clip_bgr24b - - typedef amask_no_clip_u8<4, 0> amask_no_clip_rgba32r; //----amask_no_clip_rgba32r - typedef amask_no_clip_u8<4, 1> amask_no_clip_rgba32g; //----amask_no_clip_rgba32g - typedef amask_no_clip_u8<4, 2> amask_no_clip_rgba32b; //----amask_no_clip_rgba32b - typedef amask_no_clip_u8<4, 3> amask_no_clip_rgba32a; //----amask_no_clip_rgba32a - - typedef amask_no_clip_u8<4, 1> amask_no_clip_argb32r; //----amask_no_clip_argb32r - typedef amask_no_clip_u8<4, 2> amask_no_clip_argb32g; //----amask_no_clip_argb32g - typedef amask_no_clip_u8<4, 3> amask_no_clip_argb32b; //----amask_no_clip_argb32b - typedef amask_no_clip_u8<4, 0> amask_no_clip_argb32a; //----amask_no_clip_argb32a - - typedef amask_no_clip_u8<4, 2> amask_no_clip_bgra32r; //----amask_no_clip_bgra32r - typedef amask_no_clip_u8<4, 1> amask_no_clip_bgra32g; //----amask_no_clip_bgra32g - typedef amask_no_clip_u8<4, 0> amask_no_clip_bgra32b; //----amask_no_clip_bgra32b - typedef amask_no_clip_u8<4, 3> amask_no_clip_bgra32a; //----amask_no_clip_bgra32a - - typedef amask_no_clip_u8<4, 3> amask_no_clip_abgr32r; //----amask_no_clip_abgr32r - typedef amask_no_clip_u8<4, 2> amask_no_clip_abgr32g; //----amask_no_clip_abgr32g - typedef amask_no_clip_u8<4, 1> amask_no_clip_abgr32b; //----amask_no_clip_abgr32b - typedef amask_no_clip_u8<4, 0> amask_no_clip_abgr32a; //----amask_no_clip_abgr32a - - typedef amask_no_clip_u8<3, 0, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_rgb24gray; //----amask_no_clip_rgb24gray - typedef amask_no_clip_u8<3, 0, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_bgr24gray; //----amask_no_clip_bgr24gray - typedef amask_no_clip_u8<4, 0, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_rgba32gray; //----amask_no_clip_rgba32gray - typedef amask_no_clip_u8<4, 1, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_argb32gray; //----amask_no_clip_argb32gray - typedef amask_no_clip_u8<4, 0, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_bgra32gray; //----amask_no_clip_bgra32gray - typedef amask_no_clip_u8<4, 1, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_abgr32gray; //----amask_no_clip_abgr32gray - - -} - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_arc.h corsix-th-0.62/agg/include/agg_arc.h --- corsix-th-0.30/agg/include/agg_arc.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_arc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Arc vertex generator -// -//---------------------------------------------------------------------------- - -#ifndef AGG_ARC_INCLUDED -#define AGG_ARC_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - - //=====================================================================arc - // - // See Implementation agg_arc.cpp - // - class arc - { - public: - arc() : m_scale(1.0), m_initialized(false) {} - arc(double x, double y, - double rx, double ry, - double a1, double a2, - bool ccw=true); - - void init(double x, double y, - double rx, double ry, - double a1, double a2, - bool ccw=true); - - void approximation_scale(double s); - double approximation_scale() const { return m_scale; } - - void rewind(unsigned); - unsigned vertex(double* x, double* y); - - private: - void normalize(double a1, double a2, bool ccw); - - double m_x; - double m_y; - double m_rx; - double m_ry; - double m_angle; - double m_start; - double m_end; - double m_scale; - double m_da; - bool m_ccw; - bool m_initialized; - unsigned m_path_cmd; - }; - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_array.h corsix-th-0.62/agg/include/agg_array.h --- corsix-th-0.30/agg/include/agg_array.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_array.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1119 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_ARRAY_INCLUDED -#define AGG_ARRAY_INCLUDED - -#include -#include -#include "agg_basics.h" - -namespace agg -{ - - //-------------------------------------------------------pod_array_adaptor - template class pod_array_adaptor - { - public: - typedef T value_type; - pod_array_adaptor(T* array, unsigned size) : - m_array(array), m_size(size) {} - - unsigned size() const { return m_size; } - const T& operator [] (unsigned i) const { return m_array[i]; } - T& operator [] (unsigned i) { return m_array[i]; } - const T& at(unsigned i) const { return m_array[i]; } - T& at(unsigned i) { return m_array[i]; } - T value_at(unsigned i) const { return m_array[i]; } - - private: - T* m_array; - unsigned m_size; - }; - - - //---------------------------------------------------------pod_auto_array - template class pod_auto_array - { - public: - typedef T value_type; - typedef pod_auto_array self_type; - - pod_auto_array() {} - explicit pod_auto_array(const T* c) - { - memcpy(m_array, c, sizeof(T) * Size); - } - - const self_type& operator = (const T* c) - { - memcpy(m_array, c, sizeof(T) * Size); - return *this; - } - - static unsigned size() { return Size; } - const T& operator [] (unsigned i) const { return m_array[i]; } - T& operator [] (unsigned i) { return m_array[i]; } - const T& at(unsigned i) const { return m_array[i]; } - T& at(unsigned i) { return m_array[i]; } - T value_at(unsigned i) const { return m_array[i]; } - - private: - T m_array[Size]; - }; - - - //--------------------------------------------------------pod_auto_vector - template class pod_auto_vector - { - public: - typedef T value_type; - typedef pod_auto_vector self_type; - - pod_auto_vector() : m_size(0) {} - - void remove_all() { m_size = 0; } - void clear() { m_size = 0; } - void add(const T& v) { m_array[m_size++] = v; } - void push_back(const T& v) { m_array[m_size++] = v; } - void inc_size(unsigned size) { m_size += size; } - - unsigned size() const { return m_size; } - const T& operator [] (unsigned i) const { return m_array[i]; } - T& operator [] (unsigned i) { return m_array[i]; } - const T& at(unsigned i) const { return m_array[i]; } - T& at(unsigned i) { return m_array[i]; } - T value_at(unsigned i) const { return m_array[i]; } - - private: - T m_array[Size]; - unsigned m_size; - }; - - - //---------------------------------------------------------------pod_array - template class pod_array - { - public: - typedef T value_type; - typedef pod_array self_type; - - ~pod_array() { pod_allocator::deallocate(m_array, m_size); } - pod_array() : m_array(0), m_size(0) {} - - pod_array(unsigned size) : - m_array(pod_allocator::allocate(size)), - m_size(size) - {} - - pod_array(const self_type& v) : - m_array(pod_allocator::allocate(v.m_size)), - m_size(v.m_size) - { - memcpy(m_array, v.m_array, sizeof(T) * m_size); - } - - void resize(unsigned size) - { - if(size != m_size) - { - pod_allocator::deallocate(m_array, m_size); - m_array = pod_allocator::allocate(m_size = size); - } - } - const self_type& operator = (const self_type& v) - { - resize(v.size()); - memcpy(m_array, v.m_array, sizeof(T) * m_size); - return *this; - } - - unsigned size() const { return m_size; } - const T& operator [] (unsigned i) const { return m_array[i]; } - T& operator [] (unsigned i) { return m_array[i]; } - const T& at(unsigned i) const { return m_array[i]; } - T& at(unsigned i) { return m_array[i]; } - T value_at(unsigned i) const { return m_array[i]; } - - const T* data() const { return m_array; } - T* data() { return m_array; } - private: - T* m_array; - unsigned m_size; - }; - - - - //--------------------------------------------------------------pod_vector - // A simple class template to store Plain Old Data, a vector - // of a fixed size. The data is continous in memory - //------------------------------------------------------------------------ - template class pod_vector - { - public: - typedef T value_type; - - ~pod_vector() { pod_allocator::deallocate(m_array, m_capacity); } - pod_vector() : m_size(0), m_capacity(0), m_array(0) {} - pod_vector(unsigned cap, unsigned extra_tail=0); - - // Copying - pod_vector(const pod_vector&); - const pod_vector& operator = (const pod_vector&); - - // Set new capacity. All data is lost, size is set to zero. - void capacity(unsigned cap, unsigned extra_tail=0); - unsigned capacity() const { return m_capacity; } - - // Allocate n elements. All data is lost, - // but elements can be accessed in range 0...size-1. - void allocate(unsigned size, unsigned extra_tail=0); - - // Resize keeping the content. - void resize(unsigned new_size); - - void zero() - { - memset(m_array, 0, sizeof(T) * m_size); - } - - void add(const T& v) { m_array[m_size++] = v; } - void push_back(const T& v) { m_array[m_size++] = v; } - void insert_at(unsigned pos, const T& val); - void inc_size(unsigned size) { m_size += size; } - unsigned size() const { return m_size; } - unsigned byte_size() const { return m_size * sizeof(T); } - void serialize(int8u* ptr) const; - void deserialize(const int8u* data, unsigned byte_size); - const T& operator [] (unsigned i) const { return m_array[i]; } - T& operator [] (unsigned i) { return m_array[i]; } - const T& at(unsigned i) const { return m_array[i]; } - T& at(unsigned i) { return m_array[i]; } - T value_at(unsigned i) const { return m_array[i]; } - - const T* data() const { return m_array; } - T* data() { return m_array; } - - void remove_all() { m_size = 0; } - void clear() { m_size = 0; } - void cut_at(unsigned num) { if(num < m_size) m_size = num; } - - private: - unsigned m_size; - unsigned m_capacity; - T* m_array; - }; - - //------------------------------------------------------------------------ - template - void pod_vector::capacity(unsigned cap, unsigned extra_tail) - { - m_size = 0; - if(cap > m_capacity) - { - pod_allocator::deallocate(m_array, m_capacity); - m_capacity = cap + extra_tail; - m_array = m_capacity ? pod_allocator::allocate(m_capacity) : 0; - } - } - - //------------------------------------------------------------------------ - template - void pod_vector::allocate(unsigned size, unsigned extra_tail) - { - capacity(size, extra_tail); - m_size = size; - } - - - //------------------------------------------------------------------------ - template - void pod_vector::resize(unsigned new_size) - { - if(new_size > m_size) - { - if(new_size > m_capacity) - { - T* data = pod_allocator::allocate(new_size); - memcpy(data, m_array, m_size * sizeof(T)); - pod_allocator::deallocate(m_array, m_capacity); - m_array = data; - } - } - else - { - m_size = new_size; - } - } - - //------------------------------------------------------------------------ - template pod_vector::pod_vector(unsigned cap, unsigned extra_tail) : - m_size(0), - m_capacity(cap + extra_tail), - m_array(pod_allocator::allocate(m_capacity)) {} - - //------------------------------------------------------------------------ - template pod_vector::pod_vector(const pod_vector& v) : - m_size(v.m_size), - m_capacity(v.m_capacity), - m_array(v.m_capacity ? pod_allocator::allocate(v.m_capacity) : 0) - { - memcpy(m_array, v.m_array, sizeof(T) * v.m_size); - } - - //------------------------------------------------------------------------ - template const pod_vector& - pod_vector::operator = (const pod_vector&v) - { - allocate(v.m_size); - if(v.m_size) memcpy(m_array, v.m_array, sizeof(T) * v.m_size); - return *this; - } - - //------------------------------------------------------------------------ - template void pod_vector::serialize(int8u* ptr) const - { - if(m_size) memcpy(ptr, m_array, m_size * sizeof(T)); - } - - //------------------------------------------------------------------------ - template - void pod_vector::deserialize(const int8u* data, unsigned byte_size) - { - byte_size /= sizeof(T); - allocate(byte_size); - if(byte_size) memcpy(m_array, data, byte_size * sizeof(T)); - } - - //------------------------------------------------------------------------ - template - void pod_vector::insert_at(unsigned pos, const T& val) - { - if(pos >= m_size) - { - m_array[m_size] = val; - } - else - { - memmove(m_array + pos + 1, m_array + pos, (m_size - pos) * sizeof(T)); - m_array[pos] = val; - } - ++m_size; - } - - //---------------------------------------------------------------pod_bvector - // A simple class template to store Plain Old Data, similar to std::deque - // It doesn't reallocate memory but instead, uses blocks of data of size - // of (1 << S), that is, power of two. The data is NOT contiguous in memory, - // so the only valid access method is operator [] or curr(), prev(), next() - // - // There reallocs occure only when the pool of pointers to blocks needs - // to be extended (it happens very rarely). You can control the value - // of increment to reallocate the pointer buffer. See the second constructor. - // By default, the incremeent value equals (1 << S), i.e., the block size. - //------------------------------------------------------------------------ - template class pod_bvector - { - public: - enum block_scale_e - { - block_shift = S, - block_size = 1 << block_shift, - block_mask = block_size - 1 - }; - - typedef T value_type; - - ~pod_bvector(); - pod_bvector(); - pod_bvector(unsigned block_ptr_inc); - - // Copying - pod_bvector(const pod_bvector& v); - const pod_bvector& operator = (const pod_bvector& v); - - void remove_all() { m_size = 0; } - void clear() { m_size = 0; } - void free_all() { free_tail(0); } - void free_tail(unsigned size); - void add(const T& val); - void push_back(const T& val) { add(val); } - void modify_last(const T& val); - void remove_last(); - - int allocate_continuous_block(unsigned num_elements); - - void add_array(const T* ptr, unsigned num_elem) - { - while(num_elem--) - { - add(*ptr++); - } - } - - template void add_data(DataAccessor& data) - { - while(data.size()) - { - add(*data); - ++data; - } - } - - void cut_at(unsigned size) - { - if(size < m_size) m_size = size; - } - - unsigned size() const { return m_size; } - - const T& operator [] (unsigned i) const - { - return m_blocks[i >> block_shift][i & block_mask]; - } - - T& operator [] (unsigned i) - { - return m_blocks[i >> block_shift][i & block_mask]; - } - - const T& at(unsigned i) const - { - return m_blocks[i >> block_shift][i & block_mask]; - } - - T& at(unsigned i) - { - return m_blocks[i >> block_shift][i & block_mask]; - } - - T value_at(unsigned i) const - { - return m_blocks[i >> block_shift][i & block_mask]; - } - - const T& curr(unsigned idx) const - { - return (*this)[idx]; - } - - T& curr(unsigned idx) - { - return (*this)[idx]; - } - - const T& prev(unsigned idx) const - { - return (*this)[(idx + m_size - 1) % m_size]; - } - - T& prev(unsigned idx) - { - return (*this)[(idx + m_size - 1) % m_size]; - } - - const T& next(unsigned idx) const - { - return (*this)[(idx + 1) % m_size]; - } - - T& next(unsigned idx) - { - return (*this)[(idx + 1) % m_size]; - } - - const T& last() const - { - return (*this)[m_size - 1]; - } - - T& last() - { - return (*this)[m_size - 1]; - } - - unsigned byte_size() const; - void serialize(int8u* ptr) const; - void deserialize(const int8u* data, unsigned byte_size); - void deserialize(unsigned start, const T& empty_val, - const int8u* data, unsigned byte_size); - - template - void deserialize(ByteAccessor data) - { - remove_all(); - unsigned elem_size = data.size() / sizeof(T); - - for(unsigned i = 0; i < elem_size; ++i) - { - int8u* ptr = (int8u*)data_ptr(); - for(unsigned j = 0; j < sizeof(T); ++j) - { - *ptr++ = *data; - ++data; - } - ++m_size; - } - } - - template - void deserialize(unsigned start, const T& empty_val, ByteAccessor data) - { - while(m_size < start) - { - add(empty_val); - } - - unsigned elem_size = data.size() / sizeof(T); - for(unsigned i = 0; i < elem_size; ++i) - { - int8u* ptr; - if(start + i < m_size) - { - ptr = (int8u*)(&((*this)[start + i])); - } - else - { - ptr = (int8u*)data_ptr(); - ++m_size; - } - for(unsigned j = 0; j < sizeof(T); ++j) - { - *ptr++ = *data; - ++data; - } - } - } - - const T* block(unsigned nb) const { return m_blocks[nb]; } - - private: - void allocate_block(unsigned nb); - T* data_ptr(); - - unsigned m_size; - unsigned m_num_blocks; - unsigned m_max_blocks; - T** m_blocks; - unsigned m_block_ptr_inc; - }; - - - //------------------------------------------------------------------------ - template pod_bvector::~pod_bvector() - { - if(m_num_blocks) - { - T** blk = m_blocks + m_num_blocks - 1; - while(m_num_blocks--) - { - pod_allocator::deallocate(*blk, block_size); - --blk; - } - } - pod_allocator::deallocate(m_blocks, m_max_blocks); - } - - - //------------------------------------------------------------------------ - template - void pod_bvector::free_tail(unsigned size) - { - if(size < m_size) - { - unsigned nb = (size + block_mask) >> block_shift; - while(m_num_blocks > nb) - { - pod_allocator::deallocate(m_blocks[--m_num_blocks], block_size); - } - if(m_num_blocks == 0) - { - pod_allocator::deallocate(m_blocks, m_max_blocks); - m_blocks = 0; - m_max_blocks = 0; - } - m_size = size; - } - } - - - //------------------------------------------------------------------------ - template pod_bvector::pod_bvector() : - m_size(0), - m_num_blocks(0), - m_max_blocks(0), - m_blocks(0), - m_block_ptr_inc(block_size) - { - } - - - //------------------------------------------------------------------------ - template - pod_bvector::pod_bvector(unsigned block_ptr_inc) : - m_size(0), - m_num_blocks(0), - m_max_blocks(0), - m_blocks(0), - m_block_ptr_inc(block_ptr_inc) - { - } - - - //------------------------------------------------------------------------ - template - pod_bvector::pod_bvector(const pod_bvector& v) : - m_size(v.m_size), - m_num_blocks(v.m_num_blocks), - m_max_blocks(v.m_max_blocks), - m_blocks(v.m_max_blocks ? - pod_allocator::allocate(v.m_max_blocks) : - 0), - m_block_ptr_inc(v.m_block_ptr_inc) - { - unsigned i; - for(i = 0; i < v.m_num_blocks; ++i) - { - m_blocks[i] = pod_allocator::allocate(block_size); - memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T)); - } - } - - - //------------------------------------------------------------------------ - template - const pod_bvector& - pod_bvector::operator = (const pod_bvector& v) - { - unsigned i; - for(i = m_num_blocks; i < v.m_num_blocks; ++i) - { - allocate_block(i); - } - for(i = 0; i < v.m_num_blocks; ++i) - { - memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T)); - } - m_size = v.m_size; - return *this; - } - - - //------------------------------------------------------------------------ - template - void pod_bvector::allocate_block(unsigned nb) - { - if(nb >= m_max_blocks) - { - T** new_blocks = pod_allocator::allocate(m_max_blocks + m_block_ptr_inc); - - if(m_blocks) - { - memcpy(new_blocks, - m_blocks, - m_num_blocks * sizeof(T*)); - - pod_allocator::deallocate(m_blocks, m_max_blocks); - } - m_blocks = new_blocks; - m_max_blocks += m_block_ptr_inc; - } - m_blocks[nb] = pod_allocator::allocate(block_size); - m_num_blocks++; - } - - - - //------------------------------------------------------------------------ - template - inline T* pod_bvector::data_ptr() - { - unsigned nb = m_size >> block_shift; - if(nb >= m_num_blocks) - { - allocate_block(nb); - } - return m_blocks[nb] + (m_size & block_mask); - } - - - - //------------------------------------------------------------------------ - template - inline void pod_bvector::add(const T& val) - { - *data_ptr() = val; - ++m_size; - } - - - //------------------------------------------------------------------------ - template - inline void pod_bvector::remove_last() - { - if(m_size) --m_size; - } - - - //------------------------------------------------------------------------ - template - void pod_bvector::modify_last(const T& val) - { - remove_last(); - add(val); - } - - - //------------------------------------------------------------------------ - template - int pod_bvector::allocate_continuous_block(unsigned num_elements) - { - if(num_elements < block_size) - { - data_ptr(); // Allocate initial block if necessary - unsigned rest = block_size - (m_size & block_mask); - unsigned index; - if(num_elements <= rest) - { - // The rest of the block is good, we can use it - //----------------- - index = m_size; - m_size += num_elements; - return index; - } - - // New block - //--------------- - m_size += rest; - data_ptr(); - index = m_size; - m_size += num_elements; - return index; - } - return -1; // Impossible to allocate - } - - - //------------------------------------------------------------------------ - template - unsigned pod_bvector::byte_size() const - { - return m_size * sizeof(T); - } - - - //------------------------------------------------------------------------ - template - void pod_bvector::serialize(int8u* ptr) const - { - unsigned i; - for(i = 0; i < m_size; i++) - { - memcpy(ptr, &(*this)[i], sizeof(T)); - ptr += sizeof(T); - } - } - - //------------------------------------------------------------------------ - template - void pod_bvector::deserialize(const int8u* data, unsigned byte_size) - { - remove_all(); - byte_size /= sizeof(T); - for(unsigned i = 0; i < byte_size; ++i) - { - T* ptr = data_ptr(); - memcpy(ptr, data, sizeof(T)); - ++m_size; - data += sizeof(T); - } - } - - - // Replace or add a number of elements starting from "start" position - //------------------------------------------------------------------------ - template - void pod_bvector::deserialize(unsigned start, const T& empty_val, - const int8u* data, unsigned byte_size) - { - while(m_size < start) - { - add(empty_val); - } - - byte_size /= sizeof(T); - for(unsigned i = 0; i < byte_size; ++i) - { - if(start + i < m_size) - { - memcpy(&((*this)[start + i]), data, sizeof(T)); - } - else - { - T* ptr = data_ptr(); - memcpy(ptr, data, sizeof(T)); - ++m_size; - } - data += sizeof(T); - } - } - - - //---------------------------------------------------------block_allocator - // Allocator for arbitrary POD data. Most usable in different cache - // systems for efficient memory allocations. - // Memory is allocated with blocks of fixed size ("block_size" in - // the constructor). If required size exceeds the block size the allocator - // creates a new block of the required size. However, the most efficient - // use is when the average reqired size is much less than the block size. - //------------------------------------------------------------------------ - class block_allocator - { - struct block_type - { - int8u* data; - unsigned size; - }; - - public: - void remove_all() - { - if(m_num_blocks) - { - block_type* blk = m_blocks + m_num_blocks - 1; - while(m_num_blocks--) - { - pod_allocator::deallocate(blk->data, blk->size); - --blk; - } - pod_allocator::deallocate(m_blocks, m_max_blocks); - } - m_num_blocks = 0; - m_max_blocks = 0; - m_blocks = 0; - m_buf_ptr = 0; - m_rest = 0; - } - - ~block_allocator() - { - remove_all(); - } - - block_allocator(unsigned block_size, unsigned block_ptr_inc=256-8) : - m_block_size(block_size), - m_block_ptr_inc(block_ptr_inc), - m_num_blocks(0), - m_max_blocks(0), - m_blocks(0), - m_buf_ptr(0), - m_rest(0) - { - } - - - int8u* allocate(unsigned size, unsigned alignment=1) - { - if(size == 0) return 0; - if(size <= m_rest) - { - int8u* ptr = m_buf_ptr; - if(alignment > 1) - { - unsigned align = - (alignment - unsigned((size_t)ptr) % alignment) % alignment; - - size += align; - ptr += align; - if(size <= m_rest) - { - m_rest -= size; - m_buf_ptr += size; - return ptr; - } - allocate_block(size); - return allocate(size - align, alignment); - } - m_rest -= size; - m_buf_ptr += size; - return ptr; - } - allocate_block(size + alignment - 1); - return allocate(size, alignment); - } - - - private: - void allocate_block(unsigned size) - { - if(size < m_block_size) size = m_block_size; - if(m_num_blocks >= m_max_blocks) - { - block_type* new_blocks = - pod_allocator::allocate(m_max_blocks + m_block_ptr_inc); - - if(m_blocks) - { - memcpy(new_blocks, - m_blocks, - m_num_blocks * sizeof(block_type)); - pod_allocator::deallocate(m_blocks, m_max_blocks); - } - m_blocks = new_blocks; - m_max_blocks += m_block_ptr_inc; - } - - m_blocks[m_num_blocks].size = size; - m_blocks[m_num_blocks].data = - m_buf_ptr = - pod_allocator::allocate(size); - - m_num_blocks++; - m_rest = size; - } - - unsigned m_block_size; - unsigned m_block_ptr_inc; - unsigned m_num_blocks; - unsigned m_max_blocks; - block_type* m_blocks; - int8u* m_buf_ptr; - unsigned m_rest; - }; - - - - - - - - - //------------------------------------------------------------------------ - enum quick_sort_threshold_e - { - quick_sort_threshold = 9 - }; - - - //-----------------------------------------------------------swap_elements - template inline void swap_elements(T& a, T& b) - { - T temp = a; - a = b; - b = temp; - } - - - //--------------------------------------------------------------quick_sort - template - void quick_sort(Array& arr, Less less) - { - if(arr.size() < 2) return; - - typename Array::value_type* e1; - typename Array::value_type* e2; - - int stack[80]; - int* top = stack; - int limit = arr.size(); - int base = 0; - - for(;;) - { - int len = limit - base; - - int i; - int j; - int pivot; - - if(len > quick_sort_threshold) - { - // we use base + len/2 as the pivot - pivot = base + len / 2; - swap_elements(arr[base], arr[pivot]); - - i = base + 1; - j = limit - 1; - - // now ensure that *i <= *base <= *j - e1 = &(arr[j]); - e2 = &(arr[i]); - if(less(*e1, *e2)) swap_elements(*e1, *e2); - - e1 = &(arr[base]); - e2 = &(arr[i]); - if(less(*e1, *e2)) swap_elements(*e1, *e2); - - e1 = &(arr[j]); - e2 = &(arr[base]); - if(less(*e1, *e2)) swap_elements(*e1, *e2); - - for(;;) - { - do i++; while( less(arr[i], arr[base]) ); - do j--; while( less(arr[base], arr[j]) ); - - if( i > j ) - { - break; - } - - swap_elements(arr[i], arr[j]); - } - - swap_elements(arr[base], arr[j]); - - // now, push the largest sub-array - if(j - base > limit - i) - { - top[0] = base; - top[1] = j; - base = i; - } - else - { - top[0] = i; - top[1] = limit; - limit = j; - } - top += 2; - } - else - { - // the sub-array is small, perform insertion sort - j = base; - i = j + 1; - - for(; i < limit; j = i, i++) - { - for(; less(*(e1 = &(arr[j + 1])), *(e2 = &(arr[j]))); j--) - { - swap_elements(*e1, *e2); - if(j == base) - { - break; - } - } - } - if(top > stack) - { - top -= 2; - base = top[0]; - limit = top[1]; - } - else - { - break; - } - } - } - } - - - - - //------------------------------------------------------remove_duplicates - // Remove duplicates from a sorted array. It doesn't cut the - // tail of the array, it just returns the number of remaining elements. - //----------------------------------------------------------------------- - template - unsigned remove_duplicates(Array& arr, Equal equal) - { - if(arr.size() < 2) return arr.size(); - - unsigned i, j; - for(i = 1, j = 1; i < arr.size(); i++) - { - typename Array::value_type& e = arr[i]; - if(!equal(e, arr[i - 1])) - { - arr[j++] = e; - } - } - return j; - } - - //--------------------------------------------------------invert_container - template void invert_container(Array& arr) - { - int i = 0; - int j = arr.size() - 1; - while(i < j) - { - swap_elements(arr[i++], arr[j--]); - } - } - - //------------------------------------------------------binary_search_pos - template - unsigned binary_search_pos(const Array& arr, const Value& val, Less less) - { - if(arr.size() == 0) return 0; - - unsigned beg = 0; - unsigned end = arr.size() - 1; - - if(less(val, arr[0])) return 0; - if(less(arr[end], val)) return end + 1; - - while(end - beg > 1) - { - unsigned mid = (end + beg) >> 1; - if(less(val, arr[mid])) end = mid; - else beg = mid; - } - - //if(beg <= 0 && less(val, arr[0])) return 0; - //if(end >= arr.size() - 1 && less(arr[end], val)) ++end; - - return end; - } - - //----------------------------------------------------------range_adaptor - template class range_adaptor - { - public: - typedef typename Array::value_type value_type; - - range_adaptor(Array& array, unsigned start, unsigned size) : - m_array(array), m_start(start), m_size(size) - {} - - unsigned size() const { return m_size; } - const value_type& operator [] (unsigned i) const { return m_array[m_start + i]; } - value_type& operator [] (unsigned i) { return m_array[m_start + i]; } - const value_type& at(unsigned i) const { return m_array[m_start + i]; } - value_type& at(unsigned i) { return m_array[m_start + i]; } - value_type value_at(unsigned i) const { return m_array[m_start + i]; } - - private: - Array& m_array; - unsigned m_start; - unsigned m_size; - }; - - //---------------------------------------------------------------int_less - inline bool int_less(int a, int b) { return a < b; } - - //------------------------------------------------------------int_greater - inline bool int_greater(int a, int b) { return a > b; } - - //----------------------------------------------------------unsigned_less - inline bool unsigned_less(unsigned a, unsigned b) { return a < b; } - - //-------------------------------------------------------unsigned_greater - inline bool unsigned_greater(unsigned a, unsigned b) { return a > b; } -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_arrowhead.h corsix-th-0.62/agg/include/agg_arrowhead.h --- corsix-th-0.30/agg/include/agg_arrowhead.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_arrowhead.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Simple arrowhead/arrowtail generator -// -//---------------------------------------------------------------------------- -#ifndef AGG_ARROWHEAD_INCLUDED -#define AGG_ARROWHEAD_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //===============================================================arrowhead - // - // See implementation agg_arrowhead.cpp - // - class arrowhead - { - public: - arrowhead(); - - void head(double d1, double d2, double d3, double d4) - { - m_head_d1 = d1; - m_head_d2 = d2; - m_head_d3 = d3; - m_head_d4 = d4; - m_head_flag = true; - } - - void head() { m_head_flag = true; } - void no_head() { m_head_flag = false; } - - void tail(double d1, double d2, double d3, double d4) - { - m_tail_d1 = d1; - m_tail_d2 = d2; - m_tail_d3 = d3; - m_tail_d4 = d4; - m_tail_flag = true; - } - - void tail() { m_tail_flag = true; } - void no_tail() { m_tail_flag = false; } - - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - double m_head_d1; - double m_head_d2; - double m_head_d3; - double m_head_d4; - double m_tail_d1; - double m_tail_d2; - double m_tail_d3; - double m_tail_d4; - bool m_head_flag; - bool m_tail_flag; - double m_coord[16]; - unsigned m_cmd[8]; - unsigned m_curr_id; - unsigned m_curr_coord; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_basics.h corsix-th-0.62/agg/include/agg_basics.h --- corsix-th-0.30/agg/include/agg_basics.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_basics.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,530 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_BASICS_INCLUDED -#define AGG_BASICS_INCLUDED - -#include -#include "agg_config.h" - -//---------------------------------------------------------AGG_CUSTOM_ALLOCATOR -#ifdef AGG_CUSTOM_ALLOCATOR -#include "agg_allocator.h" -#else -namespace agg -{ - // The policy of all AGG containers and memory allocation strategy - // in general is that no allocated data requires explicit construction. - // It means that the allocator can be really simple; you can even - // replace new/delete to malloc/free. The constructors and destructors - // won't be called in this case, however everything will remain working. - // The second argument of deallocate() is the size of the allocated - // block. You can use this information if you wish. - //------------------------------------------------------------pod_allocator - template struct pod_allocator - { - static T* allocate(unsigned num) { return new T [num]; } - static void deallocate(T* ptr, unsigned) { delete [] ptr; } - }; - - // Single object allocator. It's also can be replaced with your custom - // allocator. The difference is that it can only allocate a single - // object and the constructor and destructor must be called. - // In AGG there is no need to allocate an array of objects with - // calling their constructors (only single ones). So that, if you - // replace these new/delete to malloc/free make sure that the in-place - // new is called and take care of calling the destructor too. - //------------------------------------------------------------obj_allocator - template struct obj_allocator - { - static T* allocate() { return new T; } - static void deallocate(T* ptr) { delete ptr; } - }; -} -#endif - - -//-------------------------------------------------------- Default basic types -// -// If the compiler has different capacity of the basic types you can redefine -// them via the compiler command line or by generating agg_config.h that is -// empty by default. -// -#ifndef AGG_INT8 -#define AGG_INT8 signed char -#endif - -#ifndef AGG_INT8U -#define AGG_INT8U unsigned char -#endif - -#ifndef AGG_INT16 -#define AGG_INT16 short -#endif - -#ifndef AGG_INT16U -#define AGG_INT16U unsigned short -#endif - -#ifndef AGG_INT32 -#define AGG_INT32 int -#endif - -#ifndef AGG_INT32U -#define AGG_INT32U unsigned -#endif - -#ifndef AGG_INT64 -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define AGG_INT64 signed __int64 -#else -#define AGG_INT64 signed long long -#endif -#endif - -#ifndef AGG_INT64U -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define AGG_INT64U unsigned __int64 -#else -#define AGG_INT64U unsigned long long -#endif -#endif - -//------------------------------------------------ Some fixes for MS Visual C++ -#if defined(_MSC_VER) -#pragma warning(disable:4786) // Identifier was truncated... -#endif - -#if defined(_MSC_VER) -#define AGG_INLINE __forceinline -#else -#define AGG_INLINE inline -#endif - -namespace agg -{ - //------------------------------------------------------------------------- - typedef AGG_INT8 int8; //----int8 - typedef AGG_INT8U int8u; //----int8u - typedef AGG_INT16 int16; //----int16 - typedef AGG_INT16U int16u; //----int16u - typedef AGG_INT32 int32; //----int32 - typedef AGG_INT32U int32u; //----int32u - typedef AGG_INT64 int64; //----int64 - typedef AGG_INT64U int64u; //----int64u - -#if defined(AGG_FISTP) -#pragma warning(push) -#pragma warning(disable : 4035) //Disable warning "no return value" - AGG_INLINE int iround(double v) //-------iround - { - int t; - __asm fld qword ptr [v] - __asm fistp dword ptr [t] - __asm mov eax, dword ptr [t] - } - AGG_INLINE unsigned uround(double v) //-------uround - { - unsigned t; - __asm fld qword ptr [v] - __asm fistp dword ptr [t] - __asm mov eax, dword ptr [t] - } -#pragma warning(pop) - AGG_INLINE unsigned ufloor(double v) //-------ufloor - { - return unsigned(floor(v)); - } - AGG_INLINE unsigned uceil(double v) //--------uceil - { - return unsigned(ceil(v)); - } -#elif defined(AGG_QIFIST) - AGG_INLINE int iround(double v) - { - return int(v); - } - AGG_INLINE int uround(double v) - { - return unsigned(v); - } - AGG_INLINE unsigned ufloor(double v) - { - return unsigned(floor(v)); - } - AGG_INLINE unsigned uceil(double v) - { - return unsigned(ceil(v)); - } -#else - AGG_INLINE int iround(double v) - { - return int((v < 0.0) ? v - 0.5 : v + 0.5); - } - AGG_INLINE int uround(double v) - { - return unsigned(v + 0.5); - } - AGG_INLINE unsigned ufloor(double v) - { - return unsigned(v); - } - AGG_INLINE unsigned uceil(double v) - { - return unsigned(ceil(v)); - } -#endif - - //---------------------------------------------------------------saturation - template struct saturation - { - AGG_INLINE static int iround(double v) - { - if(v < double(-Limit)) return -Limit; - if(v > double( Limit)) return Limit; - return agg::iround(v); - } - }; - - //------------------------------------------------------------------mul_one - template struct mul_one - { - AGG_INLINE static unsigned mul(unsigned a, unsigned b) - { - register unsigned q = a * b + (1 << (Shift-1)); - return (q + (q >> Shift)) >> Shift; - } - }; - - //------------------------------------------------------------------------- - typedef unsigned char cover_type; //----cover_type - enum cover_scale_e - { - cover_shift = 8, //----cover_shift - cover_size = 1 << cover_shift, //----cover_size - cover_mask = cover_size - 1, //----cover_mask - cover_none = 0, //----cover_none - cover_full = cover_mask //----cover_full - }; - - //----------------------------------------------------poly_subpixel_scale_e - // These constants determine the subpixel accuracy, to be more precise, - // the number of bits of the fractional part of the coordinates. - // The possible coordinate capacity in bits can be calculated by formula: - // sizeof(int) * 8 - poly_subpixel_shift, i.e, for 32-bit integers and - // 8-bits fractional part the capacity is 24 bits. - enum poly_subpixel_scale_e - { - poly_subpixel_shift = 8, //----poly_subpixel_shift - poly_subpixel_scale = 1< struct rect_base - { - typedef T value_type; - typedef rect_base self_type; - T x1, y1, x2, y2; - - rect_base() {} - rect_base(T x1_, T y1_, T x2_, T y2_) : - x1(x1_), y1(y1_), x2(x2_), y2(y2_) {} - - void init(T x1_, T y1_, T x2_, T y2_) - { - x1 = x1_; y1 = y1_; x2 = x2_; y2 = y2_; - } - - const self_type& normalize() - { - T t; - if(x1 > x2) { t = x1; x1 = x2; x2 = t; } - if(y1 > y2) { t = y1; y1 = y2; y2 = t; } - return *this; - } - - bool clip(const self_type& r) - { - if(x2 > r.x2) x2 = r.x2; - if(y2 > r.y2) y2 = r.y2; - if(x1 < r.x1) x1 = r.x1; - if(y1 < r.y1) y1 = r.y1; - return x1 <= x2 && y1 <= y2; - } - - bool is_valid() const - { - return x1 <= x2 && y1 <= y2; - } - - bool hit_test(T x, T y) const - { - return (x >= x1 && x <= x2 && y >= y1 && y <= y2); - } - }; - - //-----------------------------------------------------intersect_rectangles - template - inline Rect intersect_rectangles(const Rect& r1, const Rect& r2) - { - Rect r = r1; - - // First process x2,y2 because the other order - // results in Internal Compiler Error under - // Microsoft Visual C++ .NET 2003 69462-335-0000007-18038 in - // case of "Maximize Speed" optimization option. - //----------------- - if(r.x2 > r2.x2) r.x2 = r2.x2; - if(r.y2 > r2.y2) r.y2 = r2.y2; - if(r.x1 < r2.x1) r.x1 = r2.x1; - if(r.y1 < r2.y1) r.y1 = r2.y1; - return r; - } - - - //---------------------------------------------------------unite_rectangles - template - inline Rect unite_rectangles(const Rect& r1, const Rect& r2) - { - Rect r = r1; - if(r.x2 < r2.x2) r.x2 = r2.x2; - if(r.y2 < r2.y2) r.y2 = r2.y2; - if(r.x1 > r2.x1) r.x1 = r2.x1; - if(r.y1 > r2.y1) r.y1 = r2.y1; - return r; - } - - typedef rect_base rect_i; //----rect_i - typedef rect_base rect_f; //----rect_f - typedef rect_base rect_d; //----rect_d - - //---------------------------------------------------------path_commands_e - enum path_commands_e - { - path_cmd_stop = 0, //----path_cmd_stop - path_cmd_move_to = 1, //----path_cmd_move_to - path_cmd_line_to = 2, //----path_cmd_line_to - path_cmd_curve3 = 3, //----path_cmd_curve3 - path_cmd_curve4 = 4, //----path_cmd_curve4 - path_cmd_curveN = 5, //----path_cmd_curveN - path_cmd_catrom = 6, //----path_cmd_catrom - path_cmd_ubspline = 7, //----path_cmd_ubspline - path_cmd_end_poly = 0x0F, //----path_cmd_end_poly - path_cmd_mask = 0x0F //----path_cmd_mask - }; - - //------------------------------------------------------------path_flags_e - enum path_flags_e - { - path_flags_none = 0, //----path_flags_none - path_flags_ccw = 0x10, //----path_flags_ccw - path_flags_cw = 0x20, //----path_flags_cw - path_flags_close = 0x40, //----path_flags_close - path_flags_mask = 0xF0 //----path_flags_mask - }; - - //---------------------------------------------------------------is_vertex - inline bool is_vertex(unsigned c) - { - return c >= path_cmd_move_to && c < path_cmd_end_poly; - } - - //--------------------------------------------------------------is_drawing - inline bool is_drawing(unsigned c) - { - return c >= path_cmd_line_to && c < path_cmd_end_poly; - } - - //-----------------------------------------------------------------is_stop - inline bool is_stop(unsigned c) - { - return c == path_cmd_stop; - } - - //--------------------------------------------------------------is_move_to - inline bool is_move_to(unsigned c) - { - return c == path_cmd_move_to; - } - - //--------------------------------------------------------------is_line_to - inline bool is_line_to(unsigned c) - { - return c == path_cmd_line_to; - } - - //----------------------------------------------------------------is_curve - inline bool is_curve(unsigned c) - { - return c == path_cmd_curve3 || c == path_cmd_curve4; - } - - //---------------------------------------------------------------is_curve3 - inline bool is_curve3(unsigned c) - { - return c == path_cmd_curve3; - } - - //---------------------------------------------------------------is_curve4 - inline bool is_curve4(unsigned c) - { - return c == path_cmd_curve4; - } - - //-------------------------------------------------------------is_end_poly - inline bool is_end_poly(unsigned c) - { - return (c & path_cmd_mask) == path_cmd_end_poly; - } - - //----------------------------------------------------------------is_close - inline bool is_close(unsigned c) - { - return (c & ~(path_flags_cw | path_flags_ccw)) == - (path_cmd_end_poly | path_flags_close); - } - - //------------------------------------------------------------is_next_poly - inline bool is_next_poly(unsigned c) - { - return is_stop(c) || is_move_to(c) || is_end_poly(c); - } - - //-------------------------------------------------------------------is_cw - inline bool is_cw(unsigned c) - { - return (c & path_flags_cw) != 0; - } - - //------------------------------------------------------------------is_ccw - inline bool is_ccw(unsigned c) - { - return (c & path_flags_ccw) != 0; - } - - //-------------------------------------------------------------is_oriented - inline bool is_oriented(unsigned c) - { - return (c & (path_flags_cw | path_flags_ccw)) != 0; - } - - //---------------------------------------------------------------is_closed - inline bool is_closed(unsigned c) - { - return (c & path_flags_close) != 0; - } - - //----------------------------------------------------------get_close_flag - inline unsigned get_close_flag(unsigned c) - { - return c & path_flags_close; - } - - //-------------------------------------------------------clear_orientation - inline unsigned clear_orientation(unsigned c) - { - return c & ~(path_flags_cw | path_flags_ccw); - } - - //---------------------------------------------------------get_orientation - inline unsigned get_orientation(unsigned c) - { - return c & (path_flags_cw | path_flags_ccw); - } - - //---------------------------------------------------------set_orientation - inline unsigned set_orientation(unsigned c, unsigned o) - { - return clear_orientation(c) | o; - } - - //--------------------------------------------------------------point_base - template struct point_base - { - typedef T value_type; - T x,y; - point_base() {} - point_base(T x_, T y_) : x(x_), y(y_) {} - }; - typedef point_base point_i; //-----point_i - typedef point_base point_f; //-----point_f - typedef point_base point_d; //-----point_d - - //-------------------------------------------------------------vertex_base - template struct vertex_base - { - typedef T value_type; - T x,y; - unsigned cmd; - vertex_base() {} - vertex_base(T x_, T y_, unsigned cmd_) : x(x_), y(y_), cmd(cmd_) {} - }; - typedef vertex_base vertex_i; //-----vertex_i - typedef vertex_base vertex_f; //-----vertex_f - typedef vertex_base vertex_d; //-----vertex_d - - //----------------------------------------------------------------row_info - template struct row_info - { - int x1, x2; - T* ptr; - row_info() {} - row_info(int x1_, int x2_, T* ptr_) : x1(x1_), x2(x2_), ptr(ptr_) {} - }; - - //----------------------------------------------------------const_row_info - template struct const_row_info - { - int x1, x2; - const T* ptr; - const_row_info() {} - const_row_info(int x1_, int x2_, const T* ptr_) : - x1(x1_), x2(x2_), ptr(ptr_) {} - }; - - //------------------------------------------------------------is_equal_eps - template inline bool is_equal_eps(T v1, T v2, T epsilon) - { - return fabs(v1 - v2) <= double(epsilon); - } - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_bezier_arc.h corsix-th-0.62/agg/include/agg_bezier_arc.h --- corsix-th-0.30/agg/include/agg_bezier_arc.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_bezier_arc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e., -// 4, 7, 10, or 13 vertices. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_BEZIER_ARC_INCLUDED -#define AGG_BEZIER_ARC_INCLUDED - -#include "agg_conv_transform.h" - -namespace agg -{ - - //----------------------------------------------------------------------- - void arc_to_bezier(double cx, double cy, double rx, double ry, - double start_angle, double sweep_angle, - double* curve); - - - //==============================================================bezier_arc - // - // See implemantaion agg_bezier_arc.cpp - // - class bezier_arc - { - public: - //-------------------------------------------------------------------- - bezier_arc() : m_vertex(26), m_num_vertices(0), m_cmd(path_cmd_line_to) {} - bezier_arc(double x, double y, - double rx, double ry, - double start_angle, - double sweep_angle) - { - init(x, y, rx, ry, start_angle, sweep_angle); - } - - //-------------------------------------------------------------------- - void init(double x, double y, - double rx, double ry, - double start_angle, - double sweep_angle); - - //-------------------------------------------------------------------- - void rewind(unsigned) - { - m_vertex = 0; - } - - //-------------------------------------------------------------------- - unsigned vertex(double* x, double* y) - { - if(m_vertex >= m_num_vertices) return path_cmd_stop; - *x = m_vertices[m_vertex]; - *y = m_vertices[m_vertex + 1]; - m_vertex += 2; - return (m_vertex == 2) ? path_cmd_move_to : m_cmd; - } - - // Supplemantary functions. num_vertices() actually returns doubled - // number of vertices. That is, for 1 vertex it returns 2. - //-------------------------------------------------------------------- - unsigned num_vertices() const { return m_num_vertices; } - const double* vertices() const { return m_vertices; } - double* vertices() { return m_vertices; } - - private: - unsigned m_vertex; - unsigned m_num_vertices; - double m_vertices[26]; - unsigned m_cmd; - }; - - - - //==========================================================bezier_arc_svg - // Compute an SVG-style bezier arc. - // - // Computes an elliptical arc from (x1, y1) to (x2, y2). The size and - // orientation of the ellipse are defined by two radii (rx, ry) - // and an x-axis-rotation, which indicates how the ellipse as a whole - // is rotated relative to the current coordinate system. The center - // (cx, cy) of the ellipse is calculated automatically to satisfy the - // constraints imposed by the other parameters. - // large-arc-flag and sweep-flag contribute to the automatic calculations - // and help determine how the arc is drawn. - class bezier_arc_svg - { - public: - //-------------------------------------------------------------------- - bezier_arc_svg() : m_arc(), m_radii_ok(false) {} - - bezier_arc_svg(double x1, double y1, - double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double x2, double y2) : - m_arc(), m_radii_ok(false) - { - init(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2); - } - - //-------------------------------------------------------------------- - void init(double x1, double y1, - double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double x2, double y2); - - //-------------------------------------------------------------------- - bool radii_ok() const { return m_radii_ok; } - - //-------------------------------------------------------------------- - void rewind(unsigned) - { - m_arc.rewind(0); - } - - //-------------------------------------------------------------------- - unsigned vertex(double* x, double* y) - { - return m_arc.vertex(x, y); - } - - // Supplemantary functions. num_vertices() actually returns doubled - // number of vertices. That is, for 1 vertex it returns 2. - //-------------------------------------------------------------------- - unsigned num_vertices() const { return m_arc.num_vertices(); } - const double* vertices() const { return m_arc.vertices(); } - double* vertices() { return m_arc.vertices(); } - - private: - bezier_arc m_arc; - bool m_radii_ok; - }; - - - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_bitset_iterator.h corsix-th-0.62/agg/include/agg_bitset_iterator.h --- corsix-th-0.30/agg/include/agg_bitset_iterator.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_bitset_iterator.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_BITSET_ITERATOR_INCLUDED -#define AGG_BITSET_ITERATOR_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - class bitset_iterator - { - public: - bitset_iterator(const int8u* bits, unsigned offset = 0) : - m_bits(bits + (offset >> 3)), - m_mask(0x80 >> (offset & 7)) - {} - - void operator ++ () - { - m_mask >>= 1; - if(m_mask == 0) - { - ++m_bits; - m_mask = 0x80; - } - } - - unsigned bit() const - { - return (*m_bits) & m_mask; - } - - private: - const int8u* m_bits; - int8u m_mask; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_blur.h corsix-th-0.62/agg/include/agg_blur.h --- corsix-th-0.30/agg/include/agg_blur.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_blur.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1294 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// The Stack Blur Algorithm was invented by Mario Klingemann, -// mario@quasimondo.com and described here: -// http://incubator.quasimondo.com/processing/fast_blur_deluxe.php -// (search phrase "Stackblur: Fast But Goodlooking"). -// The major improvement is that there's no more division table -// that was very expensive to create for large blur radii. Insted, -// for 8-bit per channel and radius not exceeding 254 the division is -// replaced by multiplication and shift. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_BLUR_INCLUDED -#define AGG_BLUR_INCLUDED - -#include "agg_array.h" -#include "agg_pixfmt_transposer.h" - -namespace agg -{ - - template struct stack_blur_tables - { - static int16u const g_stack_blur8_mul[255]; - static int8u const g_stack_blur8_shr[255]; - }; - - //------------------------------------------------------------------------ - template - int16u const stack_blur_tables::g_stack_blur8_mul[255] = - { - 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, - 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, - 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, - 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, - 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, - 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, - 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, - 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, - 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, - 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, - 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, - 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, - 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, - 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, - 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, - 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 - }; - - //------------------------------------------------------------------------ - template - int8u const stack_blur_tables::g_stack_blur8_shr[255] = - { - 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, - 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 - }; - - - - //==============================================================stack_blur - template class stack_blur - { - public: - typedef ColorT color_type; - typedef CalculatorT calculator_type; - - //-------------------------------------------------------------------- - template void blur_x(Img& img, unsigned radius) - { - if(radius < 1) return; - - unsigned x, y, xp, i; - unsigned stack_ptr; - unsigned stack_start; - - color_type pix; - color_type* stack_pix; - calculator_type sum; - calculator_type sum_in; - calculator_type sum_out; - - unsigned w = img.width(); - unsigned h = img.height(); - unsigned wm = w - 1; - unsigned div = radius * 2 + 1; - - unsigned div_sum = (radius + 1) * (radius + 1); - unsigned mul_sum = 0; - unsigned shr_sum = 0; - unsigned max_val = color_type::base_mask; - - if(max_val <= 255 && radius < 255) - { - mul_sum = stack_blur_tables::g_stack_blur8_mul[radius]; - shr_sum = stack_blur_tables::g_stack_blur8_shr[radius]; - } - - m_buf.allocate(w, 128); - m_stack.allocate(div, 32); - - for(y = 0; y < h; y++) - { - sum.clear(); - sum_in.clear(); - sum_out.clear(); - - pix = img.pixel(0, y); - for(i = 0; i <= radius; i++) - { - m_stack[i] = pix; - sum.add(pix, i + 1); - sum_out.add(pix); - } - for(i = 1; i <= radius; i++) - { - pix = img.pixel((i > wm) ? wm : i, y); - m_stack[i + radius] = pix; - sum.add(pix, radius + 1 - i); - sum_in.add(pix); - } - - stack_ptr = radius; - for(x = 0; x < w; x++) - { - if(mul_sum) sum.calc_pix(m_buf[x], mul_sum, shr_sum); - else sum.calc_pix(m_buf[x], div_sum); - - sum.sub(sum_out); - - stack_start = stack_ptr + div - radius; - if(stack_start >= div) stack_start -= div; - stack_pix = &m_stack[stack_start]; - - sum_out.sub(*stack_pix); - - xp = x + radius + 1; - if(xp > wm) xp = wm; - pix = img.pixel(xp, y); - - *stack_pix = pix; - - sum_in.add(pix); - sum.add(sum_in); - - ++stack_ptr; - if(stack_ptr >= div) stack_ptr = 0; - stack_pix = &m_stack[stack_ptr]; - - sum_out.add(*stack_pix); - sum_in.sub(*stack_pix); - } - img.copy_color_hspan(0, y, w, &m_buf[0]); - } - } - - //-------------------------------------------------------------------- - template void blur_y(Img& img, unsigned radius) - { - pixfmt_transposer img2(img); - blur_x(img2, radius); - } - - //-------------------------------------------------------------------- - template void blur(Img& img, unsigned radius) - { - blur_x(img, radius); - pixfmt_transposer img2(img); - blur_x(img2, radius); - } - - private: - pod_vector m_buf; - pod_vector m_stack; - }; - - //====================================================stack_blur_calc_rgba - template struct stack_blur_calc_rgba - { - typedef T value_type; - value_type r,g,b,a; - - AGG_INLINE void clear() - { - r = g = b = a = 0; - } - - template AGG_INLINE void add(const ArgT& v) - { - r += v.r; - g += v.g; - b += v.b; - a += v.a; - } - - template AGG_INLINE void add(const ArgT& v, unsigned k) - { - r += v.r * k; - g += v.g * k; - b += v.b * k; - a += v.a * k; - } - - template AGG_INLINE void sub(const ArgT& v) - { - r -= v.r; - g -= v.g; - b -= v.b; - a -= v.a; - } - - template AGG_INLINE void calc_pix(ArgT& v, unsigned div) - { - typedef typename ArgT::value_type value_type; - v.r = value_type(r / div); - v.g = value_type(g / div); - v.b = value_type(b / div); - v.a = value_type(a / div); - } - - template - AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr) - { - typedef typename ArgT::value_type value_type; - v.r = value_type((r * mul) >> shr); - v.g = value_type((g * mul) >> shr); - v.b = value_type((b * mul) >> shr); - v.a = value_type((a * mul) >> shr); - } - }; - - - //=====================================================stack_blur_calc_rgb - template struct stack_blur_calc_rgb - { - typedef T value_type; - value_type r,g,b; - - AGG_INLINE void clear() - { - r = g = b = 0; - } - - template AGG_INLINE void add(const ArgT& v) - { - r += v.r; - g += v.g; - b += v.b; - } - - template AGG_INLINE void add(const ArgT& v, unsigned k) - { - r += v.r * k; - g += v.g * k; - b += v.b * k; - } - - template AGG_INLINE void sub(const ArgT& v) - { - r -= v.r; - g -= v.g; - b -= v.b; - } - - template AGG_INLINE void calc_pix(ArgT& v, unsigned div) - { - typedef typename ArgT::value_type value_type; - v.r = value_type(r / div); - v.g = value_type(g / div); - v.b = value_type(b / div); - } - - template - AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr) - { - typedef typename ArgT::value_type value_type; - v.r = value_type((r * mul) >> shr); - v.g = value_type((g * mul) >> shr); - v.b = value_type((b * mul) >> shr); - } - }; - - - //====================================================stack_blur_calc_gray - template struct stack_blur_calc_gray - { - typedef T value_type; - value_type v; - - AGG_INLINE void clear() - { - v = 0; - } - - template AGG_INLINE void add(const ArgT& a) - { - v += a.v; - } - - template AGG_INLINE void add(const ArgT& a, unsigned k) - { - v += a.v * k; - } - - template AGG_INLINE void sub(const ArgT& a) - { - v -= a.v; - } - - template AGG_INLINE void calc_pix(ArgT& a, unsigned div) - { - typedef typename ArgT::value_type value_type; - a.v = value_type(v / div); - } - - template - AGG_INLINE void calc_pix(ArgT& a, unsigned mul, unsigned shr) - { - typedef typename ArgT::value_type value_type; - a.v = value_type((v * mul) >> shr); - } - }; - - - - //========================================================stack_blur_gray8 - template - void stack_blur_gray8(Img& img, unsigned rx, unsigned ry) - { - unsigned x, y, xp, yp, i; - unsigned stack_ptr; - unsigned stack_start; - - const int8u* src_pix_ptr; - int8u* dst_pix_ptr; - unsigned pix; - unsigned stack_pix; - unsigned sum; - unsigned sum_in; - unsigned sum_out; - - unsigned w = img.width(); - unsigned h = img.height(); - unsigned wm = w - 1; - unsigned hm = h - 1; - - unsigned div; - unsigned mul_sum; - unsigned shr_sum; - - pod_vector stack; - - if(rx > 0) - { - if(rx > 254) rx = 254; - div = rx * 2 + 1; - mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; - shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; - stack.allocate(div); - - for(y = 0; y < h; y++) - { - sum = sum_in = sum_out = 0; - - src_pix_ptr = img.pix_ptr(0, y); - pix = *src_pix_ptr; - for(i = 0; i <= rx; i++) - { - stack[i] = pix; - sum += pix * (i + 1); - sum_out += pix; - } - for(i = 1; i <= rx; i++) - { - if(i <= wm) src_pix_ptr += Img::pix_step; - pix = *src_pix_ptr; - stack[i + rx] = pix; - sum += pix * (rx + 1 - i); - sum_in += pix; - } - - stack_ptr = rx; - xp = rx; - if(xp > wm) xp = wm; - src_pix_ptr = img.pix_ptr(xp, y); - dst_pix_ptr = img.pix_ptr(0, y); - for(x = 0; x < w; x++) - { - *dst_pix_ptr = (sum * mul_sum) >> shr_sum; - dst_pix_ptr += Img::pix_step; - - sum -= sum_out; - - stack_start = stack_ptr + div - rx; - if(stack_start >= div) stack_start -= div; - sum_out -= stack[stack_start]; - - if(xp < wm) - { - src_pix_ptr += Img::pix_step; - pix = *src_pix_ptr; - ++xp; - } - - stack[stack_start] = pix; - - sum_in += pix; - sum += sum_in; - - ++stack_ptr; - if(stack_ptr >= div) stack_ptr = 0; - stack_pix = stack[stack_ptr]; - - sum_out += stack_pix; - sum_in -= stack_pix; - } - } - } - - if(ry > 0) - { - if(ry > 254) ry = 254; - div = ry * 2 + 1; - mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; - shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; - stack.allocate(div); - - int stride = img.stride(); - for(x = 0; x < w; x++) - { - sum = sum_in = sum_out = 0; - - src_pix_ptr = img.pix_ptr(x, 0); - pix = *src_pix_ptr; - for(i = 0; i <= ry; i++) - { - stack[i] = pix; - sum += pix * (i + 1); - sum_out += pix; - } - for(i = 1; i <= ry; i++) - { - if(i <= hm) src_pix_ptr += stride; - pix = *src_pix_ptr; - stack[i + ry] = pix; - sum += pix * (ry + 1 - i); - sum_in += pix; - } - - stack_ptr = ry; - yp = ry; - if(yp > hm) yp = hm; - src_pix_ptr = img.pix_ptr(x, yp); - dst_pix_ptr = img.pix_ptr(x, 0); - for(y = 0; y < h; y++) - { - *dst_pix_ptr = (sum * mul_sum) >> shr_sum; - dst_pix_ptr += stride; - - sum -= sum_out; - - stack_start = stack_ptr + div - ry; - if(stack_start >= div) stack_start -= div; - sum_out -= stack[stack_start]; - - if(yp < hm) - { - src_pix_ptr += stride; - pix = *src_pix_ptr; - ++yp; - } - - stack[stack_start] = pix; - - sum_in += pix; - sum += sum_in; - - ++stack_ptr; - if(stack_ptr >= div) stack_ptr = 0; - stack_pix = stack[stack_ptr]; - - sum_out += stack_pix; - sum_in -= stack_pix; - } - } - } - } - - - - //========================================================stack_blur_rgb24 - template - void stack_blur_rgb24(Img& img, unsigned rx, unsigned ry) - { - typedef typename Img::color_type color_type; - typedef typename Img::order_type order_type; - enum order_e - { - R = order_type::R, - G = order_type::G, - B = order_type::B - }; - - unsigned x, y, xp, yp, i; - unsigned stack_ptr; - unsigned stack_start; - - const int8u* src_pix_ptr; - int8u* dst_pix_ptr; - color_type* stack_pix_ptr; - - unsigned sum_r; - unsigned sum_g; - unsigned sum_b; - unsigned sum_in_r; - unsigned sum_in_g; - unsigned sum_in_b; - unsigned sum_out_r; - unsigned sum_out_g; - unsigned sum_out_b; - - unsigned w = img.width(); - unsigned h = img.height(); - unsigned wm = w - 1; - unsigned hm = h - 1; - - unsigned div; - unsigned mul_sum; - unsigned shr_sum; - - pod_vector stack; - - if(rx > 0) - { - if(rx > 254) rx = 254; - div = rx * 2 + 1; - mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; - shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; - stack.allocate(div); - - for(y = 0; y < h; y++) - { - sum_r = - sum_g = - sum_b = - sum_in_r = - sum_in_g = - sum_in_b = - sum_out_r = - sum_out_g = - sum_out_b = 0; - - src_pix_ptr = img.pix_ptr(0, y); - for(i = 0; i <= rx; i++) - { - stack_pix_ptr = &stack[i]; - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - sum_r += src_pix_ptr[R] * (i + 1); - sum_g += src_pix_ptr[G] * (i + 1); - sum_b += src_pix_ptr[B] * (i + 1); - sum_out_r += src_pix_ptr[R]; - sum_out_g += src_pix_ptr[G]; - sum_out_b += src_pix_ptr[B]; - } - for(i = 1; i <= rx; i++) - { - if(i <= wm) src_pix_ptr += Img::pix_width; - stack_pix_ptr = &stack[i + rx]; - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - sum_r += src_pix_ptr[R] * (rx + 1 - i); - sum_g += src_pix_ptr[G] * (rx + 1 - i); - sum_b += src_pix_ptr[B] * (rx + 1 - i); - sum_in_r += src_pix_ptr[R]; - sum_in_g += src_pix_ptr[G]; - sum_in_b += src_pix_ptr[B]; - } - - stack_ptr = rx; - xp = rx; - if(xp > wm) xp = wm; - src_pix_ptr = img.pix_ptr(xp, y); - dst_pix_ptr = img.pix_ptr(0, y); - for(x = 0; x < w; x++) - { - dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; - dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; - dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; - dst_pix_ptr += Img::pix_width; - - sum_r -= sum_out_r; - sum_g -= sum_out_g; - sum_b -= sum_out_b; - - stack_start = stack_ptr + div - rx; - if(stack_start >= div) stack_start -= div; - stack_pix_ptr = &stack[stack_start]; - - sum_out_r -= stack_pix_ptr->r; - sum_out_g -= stack_pix_ptr->g; - sum_out_b -= stack_pix_ptr->b; - - if(xp < wm) - { - src_pix_ptr += Img::pix_width; - ++xp; - } - - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - - sum_in_r += src_pix_ptr[R]; - sum_in_g += src_pix_ptr[G]; - sum_in_b += src_pix_ptr[B]; - sum_r += sum_in_r; - sum_g += sum_in_g; - sum_b += sum_in_b; - - ++stack_ptr; - if(stack_ptr >= div) stack_ptr = 0; - stack_pix_ptr = &stack[stack_ptr]; - - sum_out_r += stack_pix_ptr->r; - sum_out_g += stack_pix_ptr->g; - sum_out_b += stack_pix_ptr->b; - sum_in_r -= stack_pix_ptr->r; - sum_in_g -= stack_pix_ptr->g; - sum_in_b -= stack_pix_ptr->b; - } - } - } - - if(ry > 0) - { - if(ry > 254) ry = 254; - div = ry * 2 + 1; - mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; - shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; - stack.allocate(div); - - int stride = img.stride(); - for(x = 0; x < w; x++) - { - sum_r = - sum_g = - sum_b = - sum_in_r = - sum_in_g = - sum_in_b = - sum_out_r = - sum_out_g = - sum_out_b = 0; - - src_pix_ptr = img.pix_ptr(x, 0); - for(i = 0; i <= ry; i++) - { - stack_pix_ptr = &stack[i]; - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - sum_r += src_pix_ptr[R] * (i + 1); - sum_g += src_pix_ptr[G] * (i + 1); - sum_b += src_pix_ptr[B] * (i + 1); - sum_out_r += src_pix_ptr[R]; - sum_out_g += src_pix_ptr[G]; - sum_out_b += src_pix_ptr[B]; - } - for(i = 1; i <= ry; i++) - { - if(i <= hm) src_pix_ptr += stride; - stack_pix_ptr = &stack[i + ry]; - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - sum_r += src_pix_ptr[R] * (ry + 1 - i); - sum_g += src_pix_ptr[G] * (ry + 1 - i); - sum_b += src_pix_ptr[B] * (ry + 1 - i); - sum_in_r += src_pix_ptr[R]; - sum_in_g += src_pix_ptr[G]; - sum_in_b += src_pix_ptr[B]; - } - - stack_ptr = ry; - yp = ry; - if(yp > hm) yp = hm; - src_pix_ptr = img.pix_ptr(x, yp); - dst_pix_ptr = img.pix_ptr(x, 0); - for(y = 0; y < h; y++) - { - dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; - dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; - dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; - dst_pix_ptr += stride; - - sum_r -= sum_out_r; - sum_g -= sum_out_g; - sum_b -= sum_out_b; - - stack_start = stack_ptr + div - ry; - if(stack_start >= div) stack_start -= div; - - stack_pix_ptr = &stack[stack_start]; - sum_out_r -= stack_pix_ptr->r; - sum_out_g -= stack_pix_ptr->g; - sum_out_b -= stack_pix_ptr->b; - - if(yp < hm) - { - src_pix_ptr += stride; - ++yp; - } - - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - - sum_in_r += src_pix_ptr[R]; - sum_in_g += src_pix_ptr[G]; - sum_in_b += src_pix_ptr[B]; - sum_r += sum_in_r; - sum_g += sum_in_g; - sum_b += sum_in_b; - - ++stack_ptr; - if(stack_ptr >= div) stack_ptr = 0; - stack_pix_ptr = &stack[stack_ptr]; - - sum_out_r += stack_pix_ptr->r; - sum_out_g += stack_pix_ptr->g; - sum_out_b += stack_pix_ptr->b; - sum_in_r -= stack_pix_ptr->r; - sum_in_g -= stack_pix_ptr->g; - sum_in_b -= stack_pix_ptr->b; - } - } - } - } - - - - //=======================================================stack_blur_rgba32 - template - void stack_blur_rgba32(Img& img, unsigned rx, unsigned ry) - { - typedef typename Img::color_type color_type; - typedef typename Img::order_type order_type; - enum order_e - { - R = order_type::R, - G = order_type::G, - B = order_type::B, - A = order_type::A - }; - - unsigned x, y, xp, yp, i; - unsigned stack_ptr; - unsigned stack_start; - - const int8u* src_pix_ptr; - int8u* dst_pix_ptr; - color_type* stack_pix_ptr; - - unsigned sum_r; - unsigned sum_g; - unsigned sum_b; - unsigned sum_a; - unsigned sum_in_r; - unsigned sum_in_g; - unsigned sum_in_b; - unsigned sum_in_a; - unsigned sum_out_r; - unsigned sum_out_g; - unsigned sum_out_b; - unsigned sum_out_a; - - unsigned w = img.width(); - unsigned h = img.height(); - unsigned wm = w - 1; - unsigned hm = h - 1; - - unsigned div; - unsigned mul_sum; - unsigned shr_sum; - - pod_vector stack; - - if(rx > 0) - { - if(rx > 254) rx = 254; - div = rx * 2 + 1; - mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; - shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; - stack.allocate(div); - - for(y = 0; y < h; y++) - { - sum_r = - sum_g = - sum_b = - sum_a = - sum_in_r = - sum_in_g = - sum_in_b = - sum_in_a = - sum_out_r = - sum_out_g = - sum_out_b = - sum_out_a = 0; - - src_pix_ptr = img.pix_ptr(0, y); - for(i = 0; i <= rx; i++) - { - stack_pix_ptr = &stack[i]; - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - stack_pix_ptr->a = src_pix_ptr[A]; - sum_r += src_pix_ptr[R] * (i + 1); - sum_g += src_pix_ptr[G] * (i + 1); - sum_b += src_pix_ptr[B] * (i + 1); - sum_a += src_pix_ptr[A] * (i + 1); - sum_out_r += src_pix_ptr[R]; - sum_out_g += src_pix_ptr[G]; - sum_out_b += src_pix_ptr[B]; - sum_out_a += src_pix_ptr[A]; - } - for(i = 1; i <= rx; i++) - { - if(i <= wm) src_pix_ptr += Img::pix_width; - stack_pix_ptr = &stack[i + rx]; - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - stack_pix_ptr->a = src_pix_ptr[A]; - sum_r += src_pix_ptr[R] * (rx + 1 - i); - sum_g += src_pix_ptr[G] * (rx + 1 - i); - sum_b += src_pix_ptr[B] * (rx + 1 - i); - sum_a += src_pix_ptr[A] * (rx + 1 - i); - sum_in_r += src_pix_ptr[R]; - sum_in_g += src_pix_ptr[G]; - sum_in_b += src_pix_ptr[B]; - sum_in_a += src_pix_ptr[A]; - } - - stack_ptr = rx; - xp = rx; - if(xp > wm) xp = wm; - src_pix_ptr = img.pix_ptr(xp, y); - dst_pix_ptr = img.pix_ptr(0, y); - for(x = 0; x < w; x++) - { - dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; - dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; - dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; - dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum; - dst_pix_ptr += Img::pix_width; - - sum_r -= sum_out_r; - sum_g -= sum_out_g; - sum_b -= sum_out_b; - sum_a -= sum_out_a; - - stack_start = stack_ptr + div - rx; - if(stack_start >= div) stack_start -= div; - stack_pix_ptr = &stack[stack_start]; - - sum_out_r -= stack_pix_ptr->r; - sum_out_g -= stack_pix_ptr->g; - sum_out_b -= stack_pix_ptr->b; - sum_out_a -= stack_pix_ptr->a; - - if(xp < wm) - { - src_pix_ptr += Img::pix_width; - ++xp; - } - - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - stack_pix_ptr->a = src_pix_ptr[A]; - - sum_in_r += src_pix_ptr[R]; - sum_in_g += src_pix_ptr[G]; - sum_in_b += src_pix_ptr[B]; - sum_in_a += src_pix_ptr[A]; - sum_r += sum_in_r; - sum_g += sum_in_g; - sum_b += sum_in_b; - sum_a += sum_in_a; - - ++stack_ptr; - if(stack_ptr >= div) stack_ptr = 0; - stack_pix_ptr = &stack[stack_ptr]; - - sum_out_r += stack_pix_ptr->r; - sum_out_g += stack_pix_ptr->g; - sum_out_b += stack_pix_ptr->b; - sum_out_a += stack_pix_ptr->a; - sum_in_r -= stack_pix_ptr->r; - sum_in_g -= stack_pix_ptr->g; - sum_in_b -= stack_pix_ptr->b; - sum_in_a -= stack_pix_ptr->a; - } - } - } - - if(ry > 0) - { - if(ry > 254) ry = 254; - div = ry * 2 + 1; - mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; - shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; - stack.allocate(div); - - int stride = img.stride(); - for(x = 0; x < w; x++) - { - sum_r = - sum_g = - sum_b = - sum_a = - sum_in_r = - sum_in_g = - sum_in_b = - sum_in_a = - sum_out_r = - sum_out_g = - sum_out_b = - sum_out_a = 0; - - src_pix_ptr = img.pix_ptr(x, 0); - for(i = 0; i <= ry; i++) - { - stack_pix_ptr = &stack[i]; - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - stack_pix_ptr->a = src_pix_ptr[A]; - sum_r += src_pix_ptr[R] * (i + 1); - sum_g += src_pix_ptr[G] * (i + 1); - sum_b += src_pix_ptr[B] * (i + 1); - sum_a += src_pix_ptr[A] * (i + 1); - sum_out_r += src_pix_ptr[R]; - sum_out_g += src_pix_ptr[G]; - sum_out_b += src_pix_ptr[B]; - sum_out_a += src_pix_ptr[A]; - } - for(i = 1; i <= ry; i++) - { - if(i <= hm) src_pix_ptr += stride; - stack_pix_ptr = &stack[i + ry]; - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - stack_pix_ptr->a = src_pix_ptr[A]; - sum_r += src_pix_ptr[R] * (ry + 1 - i); - sum_g += src_pix_ptr[G] * (ry + 1 - i); - sum_b += src_pix_ptr[B] * (ry + 1 - i); - sum_a += src_pix_ptr[A] * (ry + 1 - i); - sum_in_r += src_pix_ptr[R]; - sum_in_g += src_pix_ptr[G]; - sum_in_b += src_pix_ptr[B]; - sum_in_a += src_pix_ptr[A]; - } - - stack_ptr = ry; - yp = ry; - if(yp > hm) yp = hm; - src_pix_ptr = img.pix_ptr(x, yp); - dst_pix_ptr = img.pix_ptr(x, 0); - for(y = 0; y < h; y++) - { - dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; - dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; - dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; - dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum; - dst_pix_ptr += stride; - - sum_r -= sum_out_r; - sum_g -= sum_out_g; - sum_b -= sum_out_b; - sum_a -= sum_out_a; - - stack_start = stack_ptr + div - ry; - if(stack_start >= div) stack_start -= div; - - stack_pix_ptr = &stack[stack_start]; - sum_out_r -= stack_pix_ptr->r; - sum_out_g -= stack_pix_ptr->g; - sum_out_b -= stack_pix_ptr->b; - sum_out_a -= stack_pix_ptr->a; - - if(yp < hm) - { - src_pix_ptr += stride; - ++yp; - } - - stack_pix_ptr->r = src_pix_ptr[R]; - stack_pix_ptr->g = src_pix_ptr[G]; - stack_pix_ptr->b = src_pix_ptr[B]; - stack_pix_ptr->a = src_pix_ptr[A]; - - sum_in_r += src_pix_ptr[R]; - sum_in_g += src_pix_ptr[G]; - sum_in_b += src_pix_ptr[B]; - sum_in_a += src_pix_ptr[A]; - sum_r += sum_in_r; - sum_g += sum_in_g; - sum_b += sum_in_b; - sum_a += sum_in_a; - - ++stack_ptr; - if(stack_ptr >= div) stack_ptr = 0; - stack_pix_ptr = &stack[stack_ptr]; - - sum_out_r += stack_pix_ptr->r; - sum_out_g += stack_pix_ptr->g; - sum_out_b += stack_pix_ptr->b; - sum_out_a += stack_pix_ptr->a; - sum_in_r -= stack_pix_ptr->r; - sum_in_g -= stack_pix_ptr->g; - sum_in_b -= stack_pix_ptr->b; - sum_in_a -= stack_pix_ptr->a; - } - } - } - } - - - - //===========================================================recursive_blur - template class recursive_blur - { - public: - typedef ColorT color_type; - typedef CalculatorT calculator_type; - typedef typename color_type::value_type value_type; - typedef typename calculator_type::value_type calc_type; - - //-------------------------------------------------------------------- - template void blur_x(Img& img, double radius) - { - if(radius < 0.62) return; - if(img.width() < 3) return; - - calc_type s = calc_type(radius * 0.5); - calc_type q = calc_type((s < 2.5) ? - 3.97156 - 4.14554 * sqrt(1 - 0.26891 * s) : - 0.98711 * s - 0.96330); - - calc_type q2 = calc_type(q * q); - calc_type q3 = calc_type(q2 * q); - - calc_type b0 = calc_type(1.0 / (1.578250 + - 2.444130 * q + - 1.428100 * q2 + - 0.422205 * q3)); - - calc_type b1 = calc_type( 2.44413 * q + - 2.85619 * q2 + - 1.26661 * q3); - - calc_type b2 = calc_type(-1.42810 * q2 + - -1.26661 * q3); - - calc_type b3 = calc_type(0.422205 * q3); - - calc_type b = calc_type(1 - (b1 + b2 + b3) * b0); - - b1 *= b0; - b2 *= b0; - b3 *= b0; - - int w = img.width(); - int h = img.height(); - int wm = w-1; - int x, y; - - m_sum1.allocate(w); - m_sum2.allocate(w); - m_buf.allocate(w); - - for(y = 0; y < h; y++) - { - calculator_type c; - c.from_pix(img.pixel(0, y)); - m_sum1[0].calc(b, b1, b2, b3, c, c, c, c); - c.from_pix(img.pixel(1, y)); - m_sum1[1].calc(b, b1, b2, b3, c, m_sum1[0], m_sum1[0], m_sum1[0]); - c.from_pix(img.pixel(2, y)); - m_sum1[2].calc(b, b1, b2, b3, c, m_sum1[1], m_sum1[0], m_sum1[0]); - - for(x = 3; x < w; ++x) - { - c.from_pix(img.pixel(x, y)); - m_sum1[x].calc(b, b1, b2, b3, c, m_sum1[x-1], m_sum1[x-2], m_sum1[x-3]); - } - - m_sum2[wm ].calc(b, b1, b2, b3, m_sum1[wm ], m_sum1[wm ], m_sum1[wm], m_sum1[wm]); - m_sum2[wm-1].calc(b, b1, b2, b3, m_sum1[wm-1], m_sum2[wm ], m_sum2[wm], m_sum2[wm]); - m_sum2[wm-2].calc(b, b1, b2, b3, m_sum1[wm-2], m_sum2[wm-1], m_sum2[wm], m_sum2[wm]); - m_sum2[wm ].to_pix(m_buf[wm ]); - m_sum2[wm-1].to_pix(m_buf[wm-1]); - m_sum2[wm-2].to_pix(m_buf[wm-2]); - - for(x = wm-3; x >= 0; --x) - { - m_sum2[x].calc(b, b1, b2, b3, m_sum1[x], m_sum2[x+1], m_sum2[x+2], m_sum2[x+3]); - m_sum2[x].to_pix(m_buf[x]); - } - img.copy_color_hspan(0, y, w, &m_buf[0]); - } - } - - //-------------------------------------------------------------------- - template void blur_y(Img& img, double radius) - { - pixfmt_transposer img2(img); - blur_x(img2, radius); - } - - //-------------------------------------------------------------------- - template void blur(Img& img, double radius) - { - blur_x(img, radius); - pixfmt_transposer img2(img); - blur_x(img2, radius); - } - - private: - agg::pod_vector m_sum1; - agg::pod_vector m_sum2; - agg::pod_vector m_buf; - }; - - - //=================================================recursive_blur_calc_rgba - template struct recursive_blur_calc_rgba - { - typedef T value_type; - typedef recursive_blur_calc_rgba self_type; - - value_type r,g,b,a; - - template - AGG_INLINE void from_pix(const ColorT& c) - { - r = c.r; - g = c.g; - b = c.b; - a = c.a; - } - - AGG_INLINE void calc(value_type b1, - value_type b2, - value_type b3, - value_type b4, - const self_type& c1, - const self_type& c2, - const self_type& c3, - const self_type& c4) - { - r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r; - g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g; - b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b; - a = b1*c1.a + b2*c2.a + b3*c3.a + b4*c4.a; - } - - template - AGG_INLINE void to_pix(ColorT& c) const - { - typedef typename ColorT::value_type cv_type; - c.r = (cv_type)uround(r); - c.g = (cv_type)uround(g); - c.b = (cv_type)uround(b); - c.a = (cv_type)uround(a); - } - }; - - - //=================================================recursive_blur_calc_rgb - template struct recursive_blur_calc_rgb - { - typedef T value_type; - typedef recursive_blur_calc_rgb self_type; - - value_type r,g,b; - - template - AGG_INLINE void from_pix(const ColorT& c) - { - r = c.r; - g = c.g; - b = c.b; - } - - AGG_INLINE void calc(value_type b1, - value_type b2, - value_type b3, - value_type b4, - const self_type& c1, - const self_type& c2, - const self_type& c3, - const self_type& c4) - { - r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r; - g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g; - b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b; - } - - template - AGG_INLINE void to_pix(ColorT& c) const - { - typedef typename ColorT::value_type cv_type; - c.r = (cv_type)uround(r); - c.g = (cv_type)uround(g); - c.b = (cv_type)uround(b); - } - }; - - - //================================================recursive_blur_calc_gray - template struct recursive_blur_calc_gray - { - typedef T value_type; - typedef recursive_blur_calc_gray self_type; - - value_type v; - - template - AGG_INLINE void from_pix(const ColorT& c) - { - v = c.v; - } - - AGG_INLINE void calc(value_type b1, - value_type b2, - value_type b3, - value_type b4, - const self_type& c1, - const self_type& c2, - const self_type& c3, - const self_type& c4) - { - v = b1*c1.v + b2*c2.v + b3*c3.v + b4*c4.v; - } - - template - AGG_INLINE void to_pix(ColorT& c) const - { - typedef typename ColorT::value_type cv_type; - c.v = (cv_type)uround(v); - } - }; - -} - - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_bounding_rect.h corsix-th-0.62/agg/include/agg_bounding_rect.h --- corsix-th-0.30/agg/include/agg_bounding_rect.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_bounding_rect.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// bounding_rect function template -// -//---------------------------------------------------------------------------- -#ifndef AGG_BOUNDING_RECT_INCLUDED -#define AGG_BOUNDING_RECT_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //-----------------------------------------------------------bounding_rect - template - bool bounding_rect(VertexSource& vs, GetId& gi, - unsigned start, unsigned num, - CoordT* x1, CoordT* y1, CoordT* x2, CoordT* y2) - { - unsigned i; - double x; - double y; - bool first = true; - - *x1 = CoordT(1); - *y1 = CoordT(1); - *x2 = CoordT(0); - *y2 = CoordT(0); - - for(i = 0; i < num; i++) - { - vs.rewind(gi[start + i]); - unsigned cmd; - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - if(is_vertex(cmd)) - { - if(first) - { - *x1 = CoordT(x); - *y1 = CoordT(y); - *x2 = CoordT(x); - *y2 = CoordT(y); - first = false; - } - else - { - if(CoordT(x) < *x1) *x1 = CoordT(x); - if(CoordT(y) < *y1) *y1 = CoordT(y); - if(CoordT(x) > *x2) *x2 = CoordT(x); - if(CoordT(y) > *y2) *y2 = CoordT(y); - } - } - } - } - return *x1 <= *x2 && *y1 <= *y2; - } - - - //-----------------------------------------------------bounding_rect_single - template - bool bounding_rect_single(VertexSource& vs, unsigned path_id, - CoordT* x1, CoordT* y1, CoordT* x2, CoordT* y2) - { - double x; - double y; - bool first = true; - - *x1 = CoordT(1); - *y1 = CoordT(1); - *x2 = CoordT(0); - *y2 = CoordT(0); - - vs.rewind(path_id); - unsigned cmd; - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - if(is_vertex(cmd)) - { - if(first) - { - *x1 = CoordT(x); - *y1 = CoordT(y); - *x2 = CoordT(x); - *y2 = CoordT(y); - first = false; - } - else - { - if(CoordT(x) < *x1) *x1 = CoordT(x); - if(CoordT(y) < *y1) *y1 = CoordT(y); - if(CoordT(x) > *x2) *x2 = CoordT(x); - if(CoordT(y) > *y2) *y2 = CoordT(y); - } - } - } - return *x1 <= *x2 && *y1 <= *y2; - } - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_bspline.h corsix-th-0.62/agg/include/agg_bspline.h --- corsix-th-0.30/agg/include/agg_bspline.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_bspline.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class bspline -// -//---------------------------------------------------------------------------- - -#ifndef AGG_BSPLINE_INCLUDED -#define AGG_BSPLINE_INCLUDED - -#include "agg_array.h" - -namespace agg -{ - //----------------------------------------------------------------bspline - // A very simple class of Bi-cubic Spline interpolation. - // First call init(num, x[], y[]) where num - number of source points, - // x, y - arrays of X and Y values respectively. Here Y must be a function - // of X. It means that all the X-coordinates must be arranged in the ascending - // order. - // Then call get(x) that calculates a value Y for the respective X. - // The class supports extrapolation, i.e. you can call get(x) where x is - // outside the given with init() X-range. Extrapolation is a simple linear - // function. - // - // See Implementation agg_bspline.cpp - //------------------------------------------------------------------------ - class bspline - { - public: - bspline(); - bspline(int num); - bspline(int num, const double* x, const double* y); - - void init(int num); - void add_point(double x, double y); - void prepare(); - - void init(int num, const double* x, const double* y); - - double get(double x) const; - double get_stateful(double x) const; - - private: - bspline(const bspline&); - const bspline& operator = (const bspline&); - - static void bsearch(int n, const double *x, double x0, int *i); - double extrapolation_left(double x) const; - double extrapolation_right(double x) const; - double interpolation(double x, int i) const; - - int m_max; - int m_num; - double* m_x; - double* m_y; - pod_array m_am; - mutable int m_last_idx; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_clip_liang_barsky.h corsix-th-0.62/agg/include/agg_clip_liang_barsky.h --- corsix-th-0.30/agg/include/agg_clip_liang_barsky.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_clip_liang_barsky.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,333 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Liang-Barsky clipping -// -//---------------------------------------------------------------------------- -#ifndef AGG_CLIP_LIANG_BARSKY_INCLUDED -#define AGG_CLIP_LIANG_BARSKY_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - enum clipping_flags_e - { - clipping_flags_x1_clipped = 4, - clipping_flags_x2_clipped = 1, - clipping_flags_y1_clipped = 8, - clipping_flags_y2_clipped = 2, - clipping_flags_x_clipped = clipping_flags_x1_clipped | clipping_flags_x2_clipped, - clipping_flags_y_clipped = clipping_flags_y1_clipped | clipping_flags_y2_clipped - }; - - //----------------------------------------------------------clipping_flags - // Determine the clipping code of the vertex according to the - // Cyrus-Beck line clipping algorithm - // - // | | - // 0110 | 0010 | 0011 - // | | - // -------+--------+-------- clip_box.y2 - // | | - // 0100 | 0000 | 0001 - // | | - // -------+--------+-------- clip_box.y1 - // | | - // 1100 | 1000 | 1001 - // | | - // clip_box.x1 clip_box.x2 - // - // - template - inline unsigned clipping_flags(T x, T y, const rect_base& clip_box) - { - return (x > clip_box.x2) | - ((y > clip_box.y2) << 1) | - ((x < clip_box.x1) << 2) | - ((y < clip_box.y1) << 3); - } - - //--------------------------------------------------------clipping_flags_x - template - inline unsigned clipping_flags_x(T x, const rect_base& clip_box) - { - return (x > clip_box.x2) | ((x < clip_box.x1) << 2); - } - - - //--------------------------------------------------------clipping_flags_y - template - inline unsigned clipping_flags_y(T y, const rect_base& clip_box) - { - return ((y > clip_box.y2) << 1) | ((y < clip_box.y1) << 3); - } - - - //-------------------------------------------------------clip_liang_barsky - template - inline unsigned clip_liang_barsky(T x1, T y1, T x2, T y2, - const rect_base& clip_box, - T* x, T* y) - { - const double nearzero = 1e-30; - - double deltax = x2 - x1; - double deltay = y2 - y1; - double xin; - double xout; - double yin; - double yout; - double tinx; - double tiny; - double toutx; - double touty; - double tin1; - double tin2; - double tout1; - unsigned np = 0; - - if(deltax == 0.0) - { - // bump off of the vertical - deltax = (x1 > clip_box.x1) ? -nearzero : nearzero; - } - - if(deltay == 0.0) - { - // bump off of the horizontal - deltay = (y1 > clip_box.y1) ? -nearzero : nearzero; - } - - if(deltax > 0.0) - { - // points to right - xin = clip_box.x1; - xout = clip_box.x2; - } - else - { - xin = clip_box.x2; - xout = clip_box.x1; - } - - if(deltay > 0.0) - { - // points up - yin = clip_box.y1; - yout = clip_box.y2; - } - else - { - yin = clip_box.y2; - yout = clip_box.y1; - } - - tinx = (xin - x1) / deltax; - tiny = (yin - y1) / deltay; - - if (tinx < tiny) - { - // hits x first - tin1 = tinx; - tin2 = tiny; - } - else - { - // hits y first - tin1 = tiny; - tin2 = tinx; - } - - if(tin1 <= 1.0) - { - if(0.0 < tin1) - { - *x++ = (T)xin; - *y++ = (T)yin; - ++np; - } - - if(tin2 <= 1.0) - { - toutx = (xout - x1) / deltax; - touty = (yout - y1) / deltay; - - tout1 = (toutx < touty) ? toutx : touty; - - if(tin2 > 0.0 || tout1 > 0.0) - { - if(tin2 <= tout1) - { - if(tin2 > 0.0) - { - if(tinx > tiny) - { - *x++ = (T)xin; - *y++ = (T)(y1 + tinx * deltay); - } - else - { - *x++ = (T)(x1 + tiny * deltax); - *y++ = (T)yin; - } - ++np; - } - - if(tout1 < 1.0) - { - if(toutx < touty) - { - *x++ = (T)xout; - *y++ = (T)(y1 + toutx * deltay); - } - else - { - *x++ = (T)(x1 + touty * deltax); - *y++ = (T)yout; - } - } - else - { - *x++ = x2; - *y++ = y2; - } - ++np; - } - else - { - if(tinx > tiny) - { - *x++ = (T)xin; - *y++ = (T)yout; - } - else - { - *x++ = (T)xout; - *y++ = (T)yin; - } - ++np; - } - } - } - } - return np; - } - - - //---------------------------------------------------------------------------- - template - bool clip_move_point(T x1, T y1, T x2, T y2, - const rect_base& clip_box, - T* x, T* y, unsigned flags) - { - T bound; - - if(flags & clipping_flags_x_clipped) - { - if(x1 == x2) - { - return false; - } - bound = (flags & clipping_flags_x1_clipped) ? clip_box.x1 : clip_box.x2; - *y = (T)(double(bound - x1) * (y2 - y1) / (x2 - x1) + y1); - *x = bound; - } - - flags = clipping_flags_y(*y, clip_box); - if(flags & clipping_flags_y_clipped) - { - if(y1 == y2) - { - return false; - } - bound = (flags & clipping_flags_y1_clipped) ? clip_box.y1 : clip_box.y2; - *x = (T)(double(bound - y1) * (x2 - x1) / (y2 - y1) + x1); - *y = bound; - } - return true; - } - - //-------------------------------------------------------clip_line_segment - // Returns: ret >= 4 - Fully clipped - // (ret & 1) != 0 - First point has been moved - // (ret & 2) != 0 - Second point has been moved - // - template - unsigned clip_line_segment(T* x1, T* y1, T* x2, T* y2, - const rect_base& clip_box) - { - unsigned f1 = clipping_flags(*x1, *y1, clip_box); - unsigned f2 = clipping_flags(*x2, *y2, clip_box); - unsigned ret = 0; - - if((f2 | f1) == 0) - { - // Fully visible - return 0; - } - - if((f1 & clipping_flags_x_clipped) != 0 && - (f1 & clipping_flags_x_clipped) == (f2 & clipping_flags_x_clipped)) - { - // Fully clipped - return 4; - } - - if((f1 & clipping_flags_y_clipped) != 0 && - (f1 & clipping_flags_y_clipped) == (f2 & clipping_flags_y_clipped)) - { - // Fully clipped - return 4; - } - - T tx1 = *x1; - T ty1 = *y1; - T tx2 = *x2; - T ty2 = *y2; - if(f1) - { - if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x1, y1, f1)) - { - return 4; - } - if(*x1 == *x2 && *y1 == *y2) - { - return 4; - } - ret |= 1; - } - if(f2) - { - if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x2, y2, f2)) - { - return 4; - } - if(*x1 == *x2 && *y1 == *y2) - { - return 4; - } - ret |= 2; - } - return ret; - } - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_color_gray.h corsix-th-0.62/agg/include/agg_color_gray.h --- corsix-th-0.30/agg/include/agg_color_gray.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_color_gray.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,414 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -// -// color types gray8, gray16 -// -//---------------------------------------------------------------------------- - -#ifndef AGG_COLOR_GRAY_INCLUDED -#define AGG_COLOR_GRAY_INCLUDED - -#include "agg_basics.h" -#include "agg_color_rgba.h" - -namespace agg -{ - - //===================================================================gray8 - struct gray8 - { - typedef int8u value_type; - typedef int32u calc_type; - typedef int32 long_type; - enum base_scale_e - { - base_shift = 8, - base_scale = 1 << base_shift, - base_mask = base_scale - 1 - }; - typedef gray8 self_type; - - value_type v; - value_type a; - - //-------------------------------------------------------------------- - gray8() {} - - //-------------------------------------------------------------------- - gray8(unsigned v_, unsigned a_=base_mask) : - v(int8u(v_)), a(int8u(a_)) {} - - //-------------------------------------------------------------------- - gray8(const self_type& c, unsigned a_) : - v(c.v), a(value_type(a_)) {} - - //-------------------------------------------------------------------- - gray8(const rgba& c) : - v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), - a((value_type)uround(c.a * double(base_mask))) {} - - //-------------------------------------------------------------------- - gray8(const rgba& c, double a_) : - v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), - a((value_type)uround(a_ * double(base_mask))) {} - - //-------------------------------------------------------------------- - gray8(const rgba8& c) : - v((c.r*77 + c.g*150 + c.b*29) >> 8), - a(c.a) {} - - //-------------------------------------------------------------------- - gray8(const rgba8& c, unsigned a_) : - v((c.r*77 + c.g*150 + c.b*29) >> 8), - a(a_) {} - - //-------------------------------------------------------------------- - void clear() - { - v = a = 0; - } - - //-------------------------------------------------------------------- - const self_type& transparent() - { - a = 0; - return *this; - } - - //-------------------------------------------------------------------- - void opacity(double a_) - { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = (value_type)uround(a_ * double(base_mask)); - } - - //-------------------------------------------------------------------- - double opacity() const - { - return double(a) / double(base_mask); - } - - - //-------------------------------------------------------------------- - const self_type& premultiply() - { - if(a == base_mask) return *this; - if(a == 0) - { - v = 0; - return *this; - } - v = value_type((calc_type(v) * a) >> base_shift); - return *this; - } - - //-------------------------------------------------------------------- - const self_type& premultiply(unsigned a_) - { - if(a == base_mask && a_ >= base_mask) return *this; - if(a == 0 || a_ == 0) - { - v = a = 0; - return *this; - } - calc_type v_ = (calc_type(v) * a_) / a; - v = value_type((v_ > a_) ? a_ : v_); - a = value_type(a_); - return *this; - } - - //-------------------------------------------------------------------- - const self_type& demultiply() - { - if(a == base_mask) return *this; - if(a == 0) - { - v = 0; - return *this; - } - calc_type v_ = (calc_type(v) * base_mask) / a; - v = value_type((v_ > base_mask) ? (value_type)base_mask : v_); - return *this; - } - - //-------------------------------------------------------------------- - self_type gradient(self_type c, double k) const - { - self_type ret; - calc_type ik = uround(k * base_scale); - ret.v = value_type(calc_type(v) + (((calc_type(c.v) - v) * ik) >> base_shift)); - ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); - return ret; - } - - //-------------------------------------------------------------------- - AGG_INLINE void add(const self_type& c, unsigned cover) - { - calc_type cv, ca; - if(cover == cover_mask) - { - if(c.a == base_mask) - { - *this = c; - } - else - { - cv = v + c.v; v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; - ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; - } - } - else - { - cv = v + ((c.v * cover + cover_mask/2) >> cover_shift); - ca = a + ((c.a * cover + cover_mask/2) >> cover_shift); - v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; - a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; - } - } - - //-------------------------------------------------------------------- - static self_type no_color() { return self_type(0,0); } - }; - - - //-------------------------------------------------------------gray8_pre - inline gray8 gray8_pre(unsigned v, unsigned a = gray8::base_mask) - { - return gray8(v,a).premultiply(); - } - inline gray8 gray8_pre(const gray8& c, unsigned a) - { - return gray8(c,a).premultiply(); - } - inline gray8 gray8_pre(const rgba& c) - { - return gray8(c).premultiply(); - } - inline gray8 gray8_pre(const rgba& c, double a) - { - return gray8(c,a).premultiply(); - } - inline gray8 gray8_pre(const rgba8& c) - { - return gray8(c).premultiply(); - } - inline gray8 gray8_pre(const rgba8& c, unsigned a) - { - return gray8(c,a).premultiply(); - } - - - - - //==================================================================gray16 - struct gray16 - { - typedef int16u value_type; - typedef int32u calc_type; - typedef int64 long_type; - enum base_scale_e - { - base_shift = 16, - base_scale = 1 << base_shift, - base_mask = base_scale - 1 - }; - typedef gray16 self_type; - - value_type v; - value_type a; - - //-------------------------------------------------------------------- - gray16() {} - - //-------------------------------------------------------------------- - gray16(unsigned v_, unsigned a_=base_mask) : - v(int16u(v_)), a(int16u(a_)) {} - - //-------------------------------------------------------------------- - gray16(const self_type& c, unsigned a_) : - v(c.v), a(value_type(a_)) {} - - //-------------------------------------------------------------------- - gray16(const rgba& c) : - v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), - a((value_type)uround(c.a * double(base_mask))) {} - - //-------------------------------------------------------------------- - gray16(const rgba& c, double a_) : - v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), - a((value_type)uround(a_ * double(base_mask))) {} - - //-------------------------------------------------------------------- - gray16(const rgba8& c) : - v(c.r*77 + c.g*150 + c.b*29), - a((value_type(c.a) << 8) | c.a) {} - - //-------------------------------------------------------------------- - gray16(const rgba8& c, unsigned a_) : - v(c.r*77 + c.g*150 + c.b*29), - a((value_type(a_) << 8) | c.a) {} - - //-------------------------------------------------------------------- - void clear() - { - v = a = 0; - } - - //-------------------------------------------------------------------- - const self_type& transparent() - { - a = 0; - return *this; - } - - //-------------------------------------------------------------------- - void opacity(double a_) - { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = (value_type)uround(a_ * double(base_mask)); - } - - //-------------------------------------------------------------------- - double opacity() const - { - return double(a) / double(base_mask); - } - - - //-------------------------------------------------------------------- - const self_type& premultiply() - { - if(a == base_mask) return *this; - if(a == 0) - { - v = 0; - return *this; - } - v = value_type((calc_type(v) * a) >> base_shift); - return *this; - } - - //-------------------------------------------------------------------- - const self_type& premultiply(unsigned a_) - { - if(a == base_mask && a_ >= base_mask) return *this; - if(a == 0 || a_ == 0) - { - v = a = 0; - return *this; - } - calc_type v_ = (calc_type(v) * a_) / a; - v = value_type((v_ > a_) ? a_ : v_); - a = value_type(a_); - return *this; - } - - //-------------------------------------------------------------------- - const self_type& demultiply() - { - if(a == base_mask) return *this; - if(a == 0) - { - v = 0; - return *this; - } - calc_type v_ = (calc_type(v) * base_mask) / a; - v = value_type((v_ > base_mask) ? base_mask : v_); - return *this; - } - - //-------------------------------------------------------------------- - self_type gradient(self_type c, double k) const - { - self_type ret; - calc_type ik = uround(k * base_scale); - ret.v = value_type(calc_type(v) + (((calc_type(c.v) - v) * ik) >> base_shift)); - ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); - return ret; - } - - //-------------------------------------------------------------------- - AGG_INLINE void add(const self_type& c, unsigned cover) - { - calc_type cv, ca; - if(cover == cover_mask) - { - if(c.a == base_mask) - { - *this = c; - } - else - { - cv = v + c.v; v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; - ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; - } - } - else - { - cv = v + ((c.v * cover + cover_mask/2) >> cover_shift); - ca = a + ((c.a * cover + cover_mask/2) >> cover_shift); - v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; - a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; - } - } - - //-------------------------------------------------------------------- - static self_type no_color() { return self_type(0,0); } - }; - - - //------------------------------------------------------------gray16_pre - inline gray16 gray16_pre(unsigned v, unsigned a = gray16::base_mask) - { - return gray16(v,a).premultiply(); - } - inline gray16 gray16_pre(const gray16& c, unsigned a) - { - return gray16(c,a).premultiply(); - } - inline gray16 gray16_pre(const rgba& c) - { - return gray16(c).premultiply(); - } - inline gray16 gray16_pre(const rgba& c, double a) - { - return gray16(c,a).premultiply(); - } - inline gray16 gray16_pre(const rgba8& c) - { - return gray16(c).premultiply(); - } - inline gray16 gray16_pre(const rgba8& c, unsigned a) - { - return gray16(c,a).premultiply(); - } - - -} - - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_color_rgba.h corsix-th-0.62/agg/include/agg_color_rgba.h --- corsix-th-0.30/agg/include/agg_color_rgba.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_color_rgba.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,743 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_COLOR_RGBA_INCLUDED -#define AGG_COLOR_RGBA_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - // Supported byte orders for RGB and RGBA pixel formats - //======================================================================= - struct order_rgb { enum rgb_e { R=0, G=1, B=2, rgb_tag }; }; //----order_rgb - struct order_bgr { enum bgr_e { B=0, G=1, R=2, rgb_tag }; }; //----order_bgr - struct order_rgba { enum rgba_e { R=0, G=1, B=2, A=3, rgba_tag }; }; //----order_rgba - struct order_argb { enum argb_e { A=0, R=1, G=2, B=3, rgba_tag }; }; //----order_argb - struct order_abgr { enum abgr_e { A=0, B=1, G=2, R=3, rgba_tag }; }; //----order_abgr - struct order_bgra { enum bgra_e { B=0, G=1, R=2, A=3, rgba_tag }; }; //----order_bgra - - //====================================================================rgba - struct rgba - { - typedef double value_type; - - double r; - double g; - double b; - double a; - - //-------------------------------------------------------------------- - rgba() {} - - //-------------------------------------------------------------------- - rgba(double r_, double g_, double b_, double a_=1.0) : - r(r_), g(g_), b(b_), a(a_) {} - - //-------------------------------------------------------------------- - rgba(const rgba& c, double a_) : r(c.r), g(c.g), b(c.b), a(a_) {} - - //-------------------------------------------------------------------- - void clear() - { - r = g = b = a = 0; - } - - //-------------------------------------------------------------------- - const rgba& transparent() - { - a = 0.0; - return *this; - } - - //-------------------------------------------------------------------- - const rgba& opacity(double a_) - { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = a_; - return *this; - } - - //-------------------------------------------------------------------- - double opacity() const - { - return a; - } - - //-------------------------------------------------------------------- - const rgba& premultiply() - { - r *= a; - g *= a; - b *= a; - return *this; - } - - //-------------------------------------------------------------------- - const rgba& premultiply(double a_) - { - if(a <= 0.0 || a_ <= 0.0) - { - r = g = b = a = 0.0; - return *this; - } - a_ /= a; - r *= a_; - g *= a_; - b *= a_; - a = a_; - return *this; - } - - //-------------------------------------------------------------------- - const rgba& demultiply() - { - if(a == 0) - { - r = g = b = 0; - return *this; - } - double a_ = 1.0 / a; - r *= a_; - g *= a_; - b *= a_; - return *this; - } - - - //-------------------------------------------------------------------- - rgba gradient(rgba c, double k) const - { - rgba ret; - ret.r = r + (c.r - r) * k; - ret.g = g + (c.g - g) * k; - ret.b = b + (c.b - b) * k; - ret.a = a + (c.a - a) * k; - return ret; - } - - //-------------------------------------------------------------------- - static rgba no_color() { return rgba(0,0,0,0); } - - //-------------------------------------------------------------------- - static rgba from_wavelength(double wl, double gamma = 1.0); - - //-------------------------------------------------------------------- - explicit rgba(double wavelen, double gamma=1.0) - { - *this = from_wavelength(wavelen, gamma); - } - - }; - - //----------------------------------------------------------------rgba_pre - inline rgba rgba_pre(double r, double g, double b, double a=1.0) - { - return rgba(r, g, b, a).premultiply(); - } - inline rgba rgba_pre(const rgba& c) - { - return rgba(c).premultiply(); - } - inline rgba rgba_pre(const rgba& c, double a) - { - return rgba(c, a).premultiply(); - } - - //------------------------------------------------------------------------ - inline rgba rgba::from_wavelength(double wl, double gamma) - { - rgba t(0.0, 0.0, 0.0); - - if(wl >= 380.0 && wl <= 440.0) - { - t.r = -1.0 * (wl - 440.0) / (440.0 - 380.0); - t.b = 1.0; - } - else - if(wl >= 440.0 && wl <= 490.0) - { - t.g = (wl - 440.0) / (490.0 - 440.0); - t.b = 1.0; - } - else - if(wl >= 490.0 && wl <= 510.0) - { - t.g = 1.0; - t.b = -1.0 * (wl - 510.0) / (510.0 - 490.0); - } - else - if(wl >= 510.0 && wl <= 580.0) - { - t.r = (wl - 510.0) / (580.0 - 510.0); - t.g = 1.0; - } - else - if(wl >= 580.0 && wl <= 645.0) - { - t.r = 1.0; - t.g = -1.0 * (wl - 645.0) / (645.0 - 580.0); - } - else - if(wl >= 645.0 && wl <= 780.0) - { - t.r = 1.0; - } - - double s = 1.0; - if(wl > 700.0) s = 0.3 + 0.7 * (780.0 - wl) / (780.0 - 700.0); - else if(wl < 420.0) s = 0.3 + 0.7 * (wl - 380.0) / (420.0 - 380.0); - - t.r = pow(t.r * s, gamma); - t.g = pow(t.g * s, gamma); - t.b = pow(t.b * s, gamma); - return t; - } - - - - - //===================================================================rgba8 - struct rgba8 - { - typedef int8u value_type; - typedef int32u calc_type; - typedef int32 long_type; - enum base_scale_e - { - base_shift = 8, - base_scale = 1 << base_shift, - base_mask = base_scale - 1 - }; - typedef rgba8 self_type; - - - value_type r; - value_type g; - value_type b; - value_type a; - - //-------------------------------------------------------------------- - rgba8() {} - - //-------------------------------------------------------------------- - rgba8(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) : - r(value_type(r_)), - g(value_type(g_)), - b(value_type(b_)), - a(value_type(a_)) {} - - //-------------------------------------------------------------------- - rgba8(const rgba& c, double a_) : - r((value_type)uround(c.r * double(base_mask))), - g((value_type)uround(c.g * double(base_mask))), - b((value_type)uround(c.b * double(base_mask))), - a((value_type)uround(a_ * double(base_mask))) {} - - //-------------------------------------------------------------------- - rgba8(const self_type& c, unsigned a_) : - r(c.r), g(c.g), b(c.b), a(value_type(a_)) {} - - //-------------------------------------------------------------------- - rgba8(const rgba& c) : - r((value_type)uround(c.r * double(base_mask))), - g((value_type)uround(c.g * double(base_mask))), - b((value_type)uround(c.b * double(base_mask))), - a((value_type)uround(c.a * double(base_mask))) {} - - //-------------------------------------------------------------------- - void clear() - { - r = g = b = a = 0; - } - - //-------------------------------------------------------------------- - const self_type& transparent() - { - a = 0; - return *this; - } - - //-------------------------------------------------------------------- - const self_type& opacity(double a_) - { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = (value_type)uround(a_ * double(base_mask)); - return *this; - } - - //-------------------------------------------------------------------- - double opacity() const - { - return double(a) / double(base_mask); - } - - //-------------------------------------------------------------------- - AGG_INLINE const self_type& premultiply() - { - if(a == base_mask) return *this; - if(a == 0) - { - r = g = b = 0; - return *this; - } - r = value_type((calc_type(r) * a) >> base_shift); - g = value_type((calc_type(g) * a) >> base_shift); - b = value_type((calc_type(b) * a) >> base_shift); - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE const self_type& premultiply(unsigned a_) - { - if(a == base_mask && a_ >= base_mask) return *this; - if(a == 0 || a_ == 0) - { - r = g = b = a = 0; - return *this; - } - calc_type r_ = (calc_type(r) * a_) / a; - calc_type g_ = (calc_type(g) * a_) / a; - calc_type b_ = (calc_type(b) * a_) / a; - r = value_type((r_ > a_) ? a_ : r_); - g = value_type((g_ > a_) ? a_ : g_); - b = value_type((b_ > a_) ? a_ : b_); - a = value_type(a_); - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE const self_type& demultiply() - { - if(a == base_mask) return *this; - if(a == 0) - { - r = g = b = 0; - return *this; - } - calc_type r_ = (calc_type(r) * base_mask) / a; - calc_type g_ = (calc_type(g) * base_mask) / a; - calc_type b_ = (calc_type(b) * base_mask) / a; - r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_); - g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_); - b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_); - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE self_type gradient(const self_type& c, double k) const - { - self_type ret; - calc_type ik = uround(k * base_scale); - ret.r = value_type(calc_type(r) + (((calc_type(c.r) - r) * ik) >> base_shift)); - ret.g = value_type(calc_type(g) + (((calc_type(c.g) - g) * ik) >> base_shift)); - ret.b = value_type(calc_type(b) + (((calc_type(c.b) - b) * ik) >> base_shift)); - ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); - return ret; - } - - //-------------------------------------------------------------------- - AGG_INLINE void add(const self_type& c, unsigned cover) - { - calc_type cr, cg, cb, ca; - if(cover == cover_mask) - { - if(c.a == base_mask) - { - *this = c; - } - else - { - cr = r + c.r; r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr; - cg = g + c.g; g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg; - cb = b + c.b; b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb; - ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; - } - } - else - { - cr = r + ((c.r * cover + cover_mask/2) >> cover_shift); - cg = g + ((c.g * cover + cover_mask/2) >> cover_shift); - cb = b + ((c.b * cover + cover_mask/2) >> cover_shift); - ca = a + ((c.a * cover + cover_mask/2) >> cover_shift); - r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr; - g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg; - b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb; - a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; - } - } - - //-------------------------------------------------------------------- - template - AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma) - { - r = gamma.dir(r); - g = gamma.dir(g); - b = gamma.dir(b); - } - - //-------------------------------------------------------------------- - template - AGG_INLINE void apply_gamma_inv(const GammaLUT& gamma) - { - r = gamma.inv(r); - g = gamma.inv(g); - b = gamma.inv(b); - } - - //-------------------------------------------------------------------- - static self_type no_color() { return self_type(0,0,0,0); } - - //-------------------------------------------------------------------- - static self_type from_wavelength(double wl, double gamma = 1.0) - { - return self_type(rgba::from_wavelength(wl, gamma)); - } - }; - - - //-------------------------------------------------------------rgba8_pre - inline rgba8 rgba8_pre(unsigned r, unsigned g, unsigned b, - unsigned a = rgba8::base_mask) - { - return rgba8(r,g,b,a).premultiply(); - } - inline rgba8 rgba8_pre(const rgba8& c) - { - return rgba8(c).premultiply(); - } - inline rgba8 rgba8_pre(const rgba8& c, unsigned a) - { - return rgba8(c,a).premultiply(); - } - inline rgba8 rgba8_pre(const rgba& c) - { - return rgba8(c).premultiply(); - } - inline rgba8 rgba8_pre(const rgba& c, double a) - { - return rgba8(c,a).premultiply(); - } - - - //-------------------------------------------------------------rgb8_packed - inline rgba8 rgb8_packed(unsigned v) - { - return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); - } - - //-------------------------------------------------------------bgr8_packed - inline rgba8 bgr8_packed(unsigned v) - { - return rgba8(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF); - } - - //------------------------------------------------------------argb8_packed - inline rgba8 argb8_packed(unsigned v) - { - return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF, v >> 24); - } - - //---------------------------------------------------------rgba8_gamma_dir - template - rgba8 rgba8_gamma_dir(rgba8 c, const GammaLUT& gamma) - { - return rgba8(gamma.dir(c.r), gamma.dir(c.g), gamma.dir(c.b), c.a); - } - - //---------------------------------------------------------rgba8_gamma_inv - template - rgba8 rgba8_gamma_inv(rgba8 c, const GammaLUT& gamma) - { - return rgba8(gamma.inv(c.r), gamma.inv(c.g), gamma.inv(c.b), c.a); - } - - - - - - //==================================================================rgba16 - struct rgba16 - { - typedef int16u value_type; - typedef int32u calc_type; - typedef int64 long_type; - enum base_scale_e - { - base_shift = 16, - base_scale = 1 << base_shift, - base_mask = base_scale - 1 - }; - typedef rgba16 self_type; - - value_type r; - value_type g; - value_type b; - value_type a; - - //-------------------------------------------------------------------- - rgba16() {} - - //-------------------------------------------------------------------- - rgba16(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) : - r(value_type(r_)), - g(value_type(g_)), - b(value_type(b_)), - a(value_type(a_)) {} - - //-------------------------------------------------------------------- - rgba16(const self_type& c, unsigned a_) : - r(c.r), g(c.g), b(c.b), a(value_type(a_)) {} - - //-------------------------------------------------------------------- - rgba16(const rgba& c) : - r((value_type)uround(c.r * double(base_mask))), - g((value_type)uround(c.g * double(base_mask))), - b((value_type)uround(c.b * double(base_mask))), - a((value_type)uround(c.a * double(base_mask))) {} - - //-------------------------------------------------------------------- - rgba16(const rgba& c, double a_) : - r((value_type)uround(c.r * double(base_mask))), - g((value_type)uround(c.g * double(base_mask))), - b((value_type)uround(c.b * double(base_mask))), - a((value_type)uround(a_ * double(base_mask))) {} - - //-------------------------------------------------------------------- - rgba16(const rgba8& c) : - r(value_type((value_type(c.r) << 8) | c.r)), - g(value_type((value_type(c.g) << 8) | c.g)), - b(value_type((value_type(c.b) << 8) | c.b)), - a(value_type((value_type(c.a) << 8) | c.a)) {} - - //-------------------------------------------------------------------- - rgba16(const rgba8& c, unsigned a_) : - r(value_type((value_type(c.r) << 8) | c.r)), - g(value_type((value_type(c.g) << 8) | c.g)), - b(value_type((value_type(c.b) << 8) | c.b)), - a(value_type(( a_ << 8) | c.a)) {} - - //-------------------------------------------------------------------- - void clear() - { - r = g = b = a = 0; - } - - //-------------------------------------------------------------------- - const self_type& transparent() - { - a = 0; - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE const self_type& opacity(double a_) - { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = (value_type)uround(a_ * double(base_mask)); - return *this; - } - - //-------------------------------------------------------------------- - double opacity() const - { - return double(a) / double(base_mask); - } - - //-------------------------------------------------------------------- - AGG_INLINE const self_type& premultiply() - { - if(a == base_mask) return *this; - if(a == 0) - { - r = g = b = 0; - return *this; - } - r = value_type((calc_type(r) * a) >> base_shift); - g = value_type((calc_type(g) * a) >> base_shift); - b = value_type((calc_type(b) * a) >> base_shift); - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE const self_type& premultiply(unsigned a_) - { - if(a == base_mask && a_ >= base_mask) return *this; - if(a == 0 || a_ == 0) - { - r = g = b = a = 0; - return *this; - } - calc_type r_ = (calc_type(r) * a_) / a; - calc_type g_ = (calc_type(g) * a_) / a; - calc_type b_ = (calc_type(b) * a_) / a; - r = value_type((r_ > a_) ? a_ : r_); - g = value_type((g_ > a_) ? a_ : g_); - b = value_type((b_ > a_) ? a_ : b_); - a = value_type(a_); - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE const self_type& demultiply() - { - if(a == base_mask) return *this; - if(a == 0) - { - r = g = b = 0; - return *this; - } - calc_type r_ = (calc_type(r) * base_mask) / a; - calc_type g_ = (calc_type(g) * base_mask) / a; - calc_type b_ = (calc_type(b) * base_mask) / a; - r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_); - g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_); - b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_); - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE self_type gradient(const self_type& c, double k) const - { - self_type ret; - calc_type ik = uround(k * base_scale); - ret.r = value_type(calc_type(r) + (((calc_type(c.r) - r) * ik) >> base_shift)); - ret.g = value_type(calc_type(g) + (((calc_type(c.g) - g) * ik) >> base_shift)); - ret.b = value_type(calc_type(b) + (((calc_type(c.b) - b) * ik) >> base_shift)); - ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); - return ret; - } - - //-------------------------------------------------------------------- - AGG_INLINE void add(const self_type& c, unsigned cover) - { - calc_type cr, cg, cb, ca; - if(cover == cover_mask) - { - if(c.a == base_mask) - { - *this = c; - } - else - { - cr = r + c.r; r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr; - cg = g + c.g; g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg; - cb = b + c.b; b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb; - ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; - } - } - else - { - cr = r + ((c.r * cover + cover_mask) >> cover_shift); - cg = g + ((c.g * cover + cover_mask) >> cover_shift); - cb = b + ((c.b * cover + cover_mask) >> cover_shift); - ca = a + ((c.a * cover + cover_mask) >> cover_shift); - r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr; - g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg; - b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb; - a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; - } - } - - //-------------------------------------------------------------------- - template - AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma) - { - r = gamma.dir(r); - g = gamma.dir(g); - b = gamma.dir(b); - } - - //-------------------------------------------------------------------- - template - AGG_INLINE void apply_gamma_inv(const GammaLUT& gamma) - { - r = gamma.inv(r); - g = gamma.inv(g); - b = gamma.inv(b); - } - - //-------------------------------------------------------------------- - static self_type no_color() { return self_type(0,0,0,0); } - - //-------------------------------------------------------------------- - static self_type from_wavelength(double wl, double gamma = 1.0) - { - return self_type(rgba::from_wavelength(wl, gamma)); - } - }; - - - - //--------------------------------------------------------------rgba16_pre - inline rgba16 rgba16_pre(unsigned r, unsigned g, unsigned b, - unsigned a = rgba16::base_mask) - { - return rgba16(r,g,b,a).premultiply(); - } - inline rgba16 rgba16_pre(const rgba16& c, unsigned a) - { - return rgba16(c,a).premultiply(); - } - inline rgba16 rgba16_pre(const rgba& c) - { - return rgba16(c).premultiply(); - } - inline rgba16 rgba16_pre(const rgba& c, double a) - { - return rgba16(c,a).premultiply(); - } - inline rgba16 rgba16_pre(const rgba8& c) - { - return rgba16(c).premultiply(); - } - inline rgba16 rgba16_pre(const rgba8& c, unsigned a) - { - return rgba16(c,a).premultiply(); - } - - - //------------------------------------------------------rgba16_gamma_dir - template - rgba16 rgba16_gamma_dir(rgba16 c, const GammaLUT& gamma) - { - return rgba16(gamma.dir(c.r), gamma.dir(c.g), gamma.dir(c.b), c.a); - } - - //------------------------------------------------------rgba16_gamma_inv - template - rgba16 rgba16_gamma_inv(rgba16 c, const GammaLUT& gamma) - { - return rgba16(gamma.inv(c.r), gamma.inv(c.g), gamma.inv(c.b), c.a); - } - - -} - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_config.h corsix-th-0.62/agg/include/agg_config.h --- corsix-th-0.30/agg/include/agg_config.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_config.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -#ifndef AGG_CONFIG_INCLUDED -#define AGG_CONFIG_INCLUDED - -// This file can be used to redefine certain data types. - -//--------------------------------------- -// 1. Default basic types such as: -// -// AGG_INT8 -// AGG_INT8U -// AGG_INT16 -// AGG_INT16U -// AGG_INT32 -// AGG_INT32U -// AGG_INT64 -// AGG_INT64U -// -// Just replace this file with new defines if necessary. -// For example, if your compiler doesn't have a 64 bit integer type -// you can still use AGG if you define the follows: -// -// #define AGG_INT64 int -// #define AGG_INT64U unsigned -// -// It will result in overflow in 16 bit-per-component image/pattern resampling -// but it won't result any crash and the rest of the library will remain -// fully functional. - - -//--------------------------------------- -// 2. Default rendering_buffer type. Can be: -// -// Provides faster access for massive pixel operations, -// such as blur, image filtering: -// #define AGG_RENDERING_BUFFER row_ptr_cache -// -// Provides cheaper creation and destruction (no mem allocs): -// #define AGG_RENDERING_BUFFER row_accessor -// -// You can still use both of them simultaneouslyin your applications -// This #define is used only for default rendering_buffer type, -// in short hand typedefs like pixfmt_rgba32. - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_adaptor_vcgen.h corsix-th-0.62/agg/include/agg_conv_adaptor_vcgen.h --- corsix-th-0.30/agg/include/agg_conv_adaptor_vcgen.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_adaptor_vcgen.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_ADAPTOR_VCGEN_INCLUDED -#define AGG_CONV_ADAPTOR_VCGEN_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - //------------------------------------------------------------null_markers - struct null_markers - { - void remove_all() {} - void add_vertex(double, double, unsigned) {} - void prepare_src() {} - - void rewind(unsigned) {} - unsigned vertex(double*, double*) { return path_cmd_stop; } - }; - - - //------------------------------------------------------conv_adaptor_vcgen - template class conv_adaptor_vcgen - { - enum status - { - initial, - accumulate, - generate - }; - - public: - explicit conv_adaptor_vcgen(VertexSource& source) : - m_source(&source), - m_status(initial) - {} - void attach(VertexSource& source) { m_source = &source; } - - Generator& generator() { return m_generator; } - const Generator& generator() const { return m_generator; } - - Markers& markers() { return m_markers; } - const Markers& markers() const { return m_markers; } - - void rewind(unsigned path_id) - { - m_source->rewind(path_id); - m_status = initial; - } - - unsigned vertex(double* x, double* y); - - private: - // Prohibit copying - conv_adaptor_vcgen(const conv_adaptor_vcgen&); - const conv_adaptor_vcgen& - operator = (const conv_adaptor_vcgen&); - - VertexSource* m_source; - Generator m_generator; - Markers m_markers; - status m_status; - unsigned m_last_cmd; - double m_start_x; - double m_start_y; - }; - - - - - - //------------------------------------------------------------------------ - template - unsigned conv_adaptor_vcgen::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_stop; - bool done = false; - while(!done) - { - switch(m_status) - { - case initial: - m_markers.remove_all(); - m_last_cmd = m_source->vertex(&m_start_x, &m_start_y); - m_status = accumulate; - - case accumulate: - if(is_stop(m_last_cmd)) return path_cmd_stop; - - m_generator.remove_all(); - m_generator.add_vertex(m_start_x, m_start_y, path_cmd_move_to); - m_markers.add_vertex(m_start_x, m_start_y, path_cmd_move_to); - - for(;;) - { - cmd = m_source->vertex(x, y); - if(is_vertex(cmd)) - { - m_last_cmd = cmd; - if(is_move_to(cmd)) - { - m_start_x = *x; - m_start_y = *y; - break; - } - m_generator.add_vertex(*x, *y, cmd); - m_markers.add_vertex(*x, *y, path_cmd_line_to); - } - else - { - if(is_stop(cmd)) - { - m_last_cmd = path_cmd_stop; - break; - } - if(is_end_poly(cmd)) - { - m_generator.add_vertex(*x, *y, cmd); - break; - } - } - } - m_generator.rewind(0); - m_status = generate; - - case generate: - cmd = m_generator.vertex(x, y); - if(is_stop(cmd)) - { - m_status = accumulate; - break; - } - done = true; - break; - } - } - return cmd; - } - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_adaptor_vpgen.h corsix-th-0.62/agg/include/agg_conv_adaptor_vpgen.h --- corsix-th-0.30/agg/include/agg_conv_adaptor_vpgen.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_adaptor_vpgen.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_ADAPTOR_VPGEN_INCLUDED -#define AGG_CONV_ADAPTOR_VPGEN_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //======================================================conv_adaptor_vpgen - template class conv_adaptor_vpgen - { - public: - explicit conv_adaptor_vpgen(VertexSource& source) : m_source(&source) {} - void attach(VertexSource& source) { m_source = &source; } - - VPGen& vpgen() { return m_vpgen; } - const VPGen& vpgen() const { return m_vpgen; } - - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - conv_adaptor_vpgen(const conv_adaptor_vpgen&); - const conv_adaptor_vpgen& - operator = (const conv_adaptor_vpgen&); - - VertexSource* m_source; - VPGen m_vpgen; - double m_start_x; - double m_start_y; - unsigned m_poly_flags; - int m_vertices; - }; - - - - //------------------------------------------------------------------------ - template - void conv_adaptor_vpgen::rewind(unsigned path_id) - { - m_source->rewind(path_id); - m_vpgen.reset(); - m_start_x = 0; - m_start_y = 0; - m_poly_flags = 0; - m_vertices = 0; - } - - - //------------------------------------------------------------------------ - template - unsigned conv_adaptor_vpgen::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_stop; - for(;;) - { - cmd = m_vpgen.vertex(x, y); - if(!is_stop(cmd)) break; - - if(m_poly_flags && !m_vpgen.auto_unclose()) - { - *x = 0.0; - *y = 0.0; - cmd = m_poly_flags; - m_poly_flags = 0; - break; - } - - if(m_vertices < 0) - { - if(m_vertices < -1) - { - m_vertices = 0; - return path_cmd_stop; - } - m_vpgen.move_to(m_start_x, m_start_y); - m_vertices = 1; - continue; - } - - double tx, ty; - cmd = m_source->vertex(&tx, &ty); - if(is_vertex(cmd)) - { - if(is_move_to(cmd)) - { - if(m_vpgen.auto_close() && m_vertices > 2) - { - m_vpgen.line_to(m_start_x, m_start_y); - m_poly_flags = path_cmd_end_poly | path_flags_close; - m_start_x = tx; - m_start_y = ty; - m_vertices = -1; - continue; - } - m_vpgen.move_to(tx, ty); - m_start_x = tx; - m_start_y = ty; - m_vertices = 1; - } - else - { - m_vpgen.line_to(tx, ty); - ++m_vertices; - } - } - else - { - if(is_end_poly(cmd)) - { - m_poly_flags = cmd; - if(is_closed(cmd) || m_vpgen.auto_close()) - { - if(m_vpgen.auto_close()) m_poly_flags |= path_flags_close; - if(m_vertices > 2) - { - m_vpgen.line_to(m_start_x, m_start_y); - } - m_vertices = 0; - } - } - else - { - // path_cmd_stop - if(m_vpgen.auto_close() && m_vertices > 2) - { - m_vpgen.line_to(m_start_x, m_start_y); - m_poly_flags = path_cmd_end_poly | path_flags_close; - m_vertices = -2; - continue; - } - break; - } - } - } - return cmd; - } - - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_conv_bspline.h corsix-th-0.62/agg/include/agg_conv_bspline.h --- corsix-th-0.30/agg/include/agg_conv_bspline.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_bspline.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_BSPLINE_INCLUDED -#define AGG_CONV_BSPLINE_INCLUDED - -#include "agg_basics.h" -#include "agg_vcgen_bspline.h" -#include "agg_conv_adaptor_vcgen.h" - - -namespace agg -{ - - //---------------------------------------------------------conv_bspline - template - struct conv_bspline : public conv_adaptor_vcgen - { - typedef conv_adaptor_vcgen base_type; - - conv_bspline(VertexSource& vs) : - conv_adaptor_vcgen(vs) {} - - void interpolation_step(double v) { base_type::generator().interpolation_step(v); } - double interpolation_step() const { return base_type::generator().interpolation_step(); } - - private: - conv_bspline(const conv_bspline&); - const conv_bspline& - operator = (const conv_bspline&); - }; - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_conv_clip_polygon.h corsix-th-0.62/agg/include/agg_conv_clip_polygon.h --- corsix-th-0.30/agg/include/agg_conv_clip_polygon.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_clip_polygon.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Polygon clipping converter -// There an optimized Liang-Basky algorithm is used. -// The algorithm doesn't optimize the degenerate edges, i.e. it will never -// break a closed polygon into two or more ones, instead, there will be -// degenerate edges coinciding with the respective clipping boundaries. -// This is a sub-optimal solution, because that optimization would require -// extra, rather expensive math while the rasterizer tolerates it quite well, -// without any considerable overhead. -// -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_CLIP_POLYGON_INCLUDED -#define AGG_CONV_CLIP_POLYGON_INCLUDED - -#include "agg_basics.h" -#include "agg_conv_adaptor_vpgen.h" -#include "agg_vpgen_clip_polygon.h" - -namespace agg -{ - - //=======================================================conv_clip_polygon - template - struct conv_clip_polygon : public conv_adaptor_vpgen - { - typedef conv_adaptor_vpgen base_type; - - conv_clip_polygon(VertexSource& vs) : - conv_adaptor_vpgen(vs) {} - - void clip_box(double x1, double y1, double x2, double y2) - { - base_type::vpgen().clip_box(x1, y1, x2, y2); - } - - double x1() const { return base_type::vpgen().x1(); } - double y1() const { return base_type::vpgen().y1(); } - double x2() const { return base_type::vpgen().x2(); } - double y2() const { return base_type::vpgen().y2(); } - - private: - conv_clip_polygon(const conv_clip_polygon&); - const conv_clip_polygon& - operator = (const conv_clip_polygon&); - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_clip_polyline.h corsix-th-0.62/agg/include/agg_conv_clip_polyline.h --- corsix-th-0.30/agg/include/agg_conv_clip_polyline.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_clip_polyline.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// polyline clipping converter -// There an optimized Liang-Basky algorithm is used. -// The algorithm doesn't optimize the degenerate edges, i.e. it will never -// break a closed polyline into two or more ones, instead, there will be -// degenerate edges coinciding with the respective clipping boundaries. -// This is a sub-optimal solution, because that optimization would require -// extra, rather expensive math while the rasterizer tolerates it quite well, -// without any considerable overhead. -// -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_CLIP_polyline_INCLUDED -#define AGG_CONV_CLIP_polyline_INCLUDED - -#include "agg_basics.h" -#include "agg_conv_adaptor_vpgen.h" -#include "agg_vpgen_clip_polyline.h" - -namespace agg -{ - - //=======================================================conv_clip_polyline - template - struct conv_clip_polyline : public conv_adaptor_vpgen - { - typedef conv_adaptor_vpgen base_type; - - conv_clip_polyline(VertexSource& vs) : - conv_adaptor_vpgen(vs) {} - - void clip_box(double x1, double y1, double x2, double y2) - { - base_type::vpgen().clip_box(x1, y1, x2, y2); - } - - double x1() const { return base_type::vpgen().x1(); } - double y1() const { return base_type::vpgen().y1(); } - double x2() const { return base_type::vpgen().x2(); } - double y2() const { return base_type::vpgen().y2(); } - - private: - conv_clip_polyline(const conv_clip_polyline&); - const conv_clip_polyline& - operator = (const conv_clip_polyline&); - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_close_polygon.h corsix-th-0.62/agg/include/agg_conv_close_polygon.h --- corsix-th-0.30/agg/include/agg_conv_close_polygon.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_close_polygon.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_CLOSE_POLYGON_INCLUDED -#define AGG_CONV_CLOSE_POLYGON_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //======================================================conv_close_polygon - template class conv_close_polygon - { - public: - explicit conv_close_polygon(VertexSource& vs) : m_source(&vs) {} - void attach(VertexSource& source) { m_source = &source; } - - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - conv_close_polygon(const conv_close_polygon&); - const conv_close_polygon& - operator = (const conv_close_polygon&); - - VertexSource* m_source; - unsigned m_cmd[2]; - double m_x[2]; - double m_y[2]; - unsigned m_vertex; - bool m_line_to; - }; - - - - //------------------------------------------------------------------------ - template - void conv_close_polygon::rewind(unsigned path_id) - { - m_source->rewind(path_id); - m_vertex = 2; - m_line_to = false; - } - - - - //------------------------------------------------------------------------ - template - unsigned conv_close_polygon::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_stop; - for(;;) - { - if(m_vertex < 2) - { - *x = m_x[m_vertex]; - *y = m_y[m_vertex]; - cmd = m_cmd[m_vertex]; - ++m_vertex; - break; - } - - cmd = m_source->vertex(x, y); - - if(is_end_poly(cmd)) - { - cmd |= path_flags_close; - break; - } - - if(is_stop(cmd)) - { - if(m_line_to) - { - m_cmd[0] = path_cmd_end_poly | path_flags_close; - m_cmd[1] = path_cmd_stop; - m_vertex = 0; - m_line_to = false; - continue; - } - break; - } - - if(is_move_to(cmd)) - { - if(m_line_to) - { - m_x[0] = 0.0; - m_y[0] = 0.0; - m_cmd[0] = path_cmd_end_poly | path_flags_close; - m_x[1] = *x; - m_y[1] = *y; - m_cmd[1] = cmd; - m_vertex = 0; - m_line_to = false; - continue; - } - break; - } - - if(is_vertex(cmd)) - { - m_line_to = true; - break; - } - } - return cmd; - } - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_concat.h corsix-th-0.62/agg/include/agg_conv_concat.h --- corsix-th-0.30/agg/include/agg_conv_concat.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_concat.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_CONCAT_INCLUDED -#define AGG_CONV_CONCAT_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - //=============================================================conv_concat - // Concatenation of two paths. Usually used to combine lines or curves - // with markers such as arrowheads - template class conv_concat - { - public: - conv_concat(VS1& source1, VS2& source2) : - m_source1(&source1), m_source2(&source2), m_status(2) {} - void attach1(VS1& source) { m_source1 = &source; } - void attach2(VS2& source) { m_source2 = &source; } - - - void rewind(unsigned path_id) - { - m_source1->rewind(path_id); - m_source2->rewind(0); - m_status = 0; - } - - unsigned vertex(double* x, double* y) - { - unsigned cmd; - if(m_status == 0) - { - cmd = m_source1->vertex(x, y); - if(!is_stop(cmd)) return cmd; - m_status = 1; - } - if(m_status == 1) - { - cmd = m_source2->vertex(x, y); - if(!is_stop(cmd)) return cmd; - m_status = 2; - } - return path_cmd_stop; - } - - private: - conv_concat(const conv_concat&); - const conv_concat& - operator = (const conv_concat&); - - VS1* m_source1; - VS2* m_source2; - int m_status; - - }; -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_contour.h corsix-th-0.62/agg/include/agg_conv_contour.h --- corsix-th-0.30/agg/include/agg_conv_contour.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_contour.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// conv_stroke -// -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_CONTOUR_INCLUDED -#define AGG_CONV_CONTOUR_INCLUDED - -#include "agg_basics.h" -#include "agg_vcgen_contour.h" -#include "agg_conv_adaptor_vcgen.h" - -namespace agg -{ - - //-----------------------------------------------------------conv_contour - template - struct conv_contour : public conv_adaptor_vcgen - { - typedef conv_adaptor_vcgen base_type; - - conv_contour(VertexSource& vs) : - conv_adaptor_vcgen(vs) - { - } - - void line_join(line_join_e lj) { base_type::generator().line_join(lj); } - void inner_join(inner_join_e ij) { base_type::generator().inner_join(ij); } - void width(double w) { base_type::generator().width(w); } - void miter_limit(double ml) { base_type::generator().miter_limit(ml); } - void miter_limit_theta(double t) { base_type::generator().miter_limit_theta(t); } - void inner_miter_limit(double ml) { base_type::generator().inner_miter_limit(ml); } - void approximation_scale(double as) { base_type::generator().approximation_scale(as); } - void auto_detect_orientation(bool v) { base_type::generator().auto_detect_orientation(v); } - - line_join_e line_join() const { return base_type::generator().line_join(); } - inner_join_e inner_join() const { return base_type::generator().inner_join(); } - double width() const { return base_type::generator().width(); } - double miter_limit() const { return base_type::generator().miter_limit(); } - double inner_miter_limit() const { return base_type::generator().inner_miter_limit(); } - double approximation_scale() const { return base_type::generator().approximation_scale(); } - bool auto_detect_orientation() const { return base_type::generator().auto_detect_orientation(); } - - private: - conv_contour(const conv_contour&); - const conv_contour& - operator = (const conv_contour&); - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_curve.h corsix-th-0.62/agg/include/agg_conv_curve.h --- corsix-th-0.30/agg/include/agg_conv_curve.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_curve.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,201 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// classes conv_curve -// -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_CURVE_INCLUDED -#define AGG_CONV_CURVE_INCLUDED - -#include "agg_basics.h" -#include "agg_curves.h" - -namespace agg -{ - - - //---------------------------------------------------------------conv_curve - // Curve converter class. Any path storage can have Bezier curves defined - // by their control points. There're two types of curves supported: curve3 - // and curve4. Curve3 is a conic Bezier curve with 2 endpoints and 1 control - // point. Curve4 has 2 control points (4 points in total) and can be used - // to interpolate more complicated curves. Curve4, unlike curve3 can be used - // to approximate arcs, both circular and elliptical. Curves are approximated - // with straight lines and one of the approaches is just to store the whole - // sequence of vertices that approximate our curve. It takes additional - // memory, and at the same time the consecutive vertices can be calculated - // on demand. - // - // Initially, path storages are not suppose to keep all the vertices of the - // curves (although, nothing prevents us from doing so). Instead, path_storage - // keeps only vertices, needed to calculate a curve on demand. Those vertices - // are marked with special commands. So, if the path_storage contains curves - // (which are not real curves yet), and we render this storage directly, - // all we will see is only 2 or 3 straight line segments (for curve3 and - // curve4 respectively). If we need to see real curves drawn we need to - // include this class into the conversion pipeline. - // - // Class conv_curve recognizes commands path_cmd_curve3 and path_cmd_curve4 - // and converts these vertices into a move_to/line_to sequence. - //----------------------------------------------------------------------- - template class conv_curve - { - public: - typedef Curve3 curve3_type; - typedef Curve4 curve4_type; - typedef conv_curve self_type; - - explicit conv_curve(VertexSource& source) : - m_source(&source), m_last_x(0.0), m_last_y(0.0) {} - void attach(VertexSource& source) { m_source = &source; } - - void approximation_method(curve_approximation_method_e v) - { - m_curve3.approximation_method(v); - m_curve4.approximation_method(v); - } - - curve_approximation_method_e approximation_method() const - { - return m_curve4.approximation_method(); - } - - void approximation_scale(double s) - { - m_curve3.approximation_scale(s); - m_curve4.approximation_scale(s); - } - - double approximation_scale() const - { - return m_curve4.approximation_scale(); - } - - void angle_tolerance(double v) - { - m_curve3.angle_tolerance(v); - m_curve4.angle_tolerance(v); - } - - double angle_tolerance() const - { - return m_curve4.angle_tolerance(); - } - - void cusp_limit(double v) - { - m_curve3.cusp_limit(v); - m_curve4.cusp_limit(v); - } - - double cusp_limit() const - { - return m_curve4.cusp_limit(); - } - - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - conv_curve(const self_type&); - const self_type& operator = (const self_type&); - - VertexSource* m_source; - double m_last_x; - double m_last_y; - curve3_type m_curve3; - curve4_type m_curve4; - }; - - - - //------------------------------------------------------------------------ - template - void conv_curve::rewind(unsigned path_id) - { - m_source->rewind(path_id); - m_last_x = 0.0; - m_last_y = 0.0; - m_curve3.reset(); - m_curve4.reset(); - } - - - //------------------------------------------------------------------------ - template - unsigned conv_curve::vertex(double* x, double* y) - { - if(!is_stop(m_curve3.vertex(x, y))) - { - m_last_x = *x; - m_last_y = *y; - return path_cmd_line_to; - } - - if(!is_stop(m_curve4.vertex(x, y))) - { - m_last_x = *x; - m_last_y = *y; - return path_cmd_line_to; - } - - double ct2_x; - double ct2_y; - double end_x; - double end_y; - - unsigned cmd = m_source->vertex(x, y); - switch(cmd) - { - case path_cmd_curve3: - m_source->vertex(&end_x, &end_y); - - m_curve3.init(m_last_x, m_last_y, - *x, *y, - end_x, end_y); - - m_curve3.vertex(x, y); // First call returns path_cmd_move_to - m_curve3.vertex(x, y); // This is the first vertex of the curve - cmd = path_cmd_line_to; - break; - - case path_cmd_curve4: - m_source->vertex(&ct2_x, &ct2_y); - m_source->vertex(&end_x, &end_y); - - m_curve4.init(m_last_x, m_last_y, - *x, *y, - ct2_x, ct2_y, - end_x, end_y); - - m_curve4.vertex(x, y); // First call returns path_cmd_move_to - m_curve4.vertex(x, y); // This is the first vertex of the curve - cmd = path_cmd_line_to; - break; - } - m_last_x = *x; - m_last_y = *y; - return cmd; - } - - -} - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_dash.h corsix-th-0.62/agg/include/agg_conv_dash.h --- corsix-th-0.30/agg/include/agg_conv_dash.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_dash.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// conv_dash -// -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_DASH_INCLUDED -#define AGG_CONV_DASH_INCLUDED - -#include "agg_basics.h" -#include "agg_vcgen_dash.h" -#include "agg_conv_adaptor_vcgen.h" - -namespace agg -{ - - //---------------------------------------------------------------conv_dash - template - struct conv_dash : public conv_adaptor_vcgen - { - typedef Markers marker_type; - typedef conv_adaptor_vcgen base_type; - - conv_dash(VertexSource& vs) : - conv_adaptor_vcgen(vs) - { - } - - void remove_all_dashes() - { - base_type::generator().remove_all_dashes(); - } - - void add_dash(double dash_len, double gap_len) - { - base_type::generator().add_dash(dash_len, gap_len); - } - - void dash_start(double ds) - { - base_type::generator().dash_start(ds); - } - - void shorten(double s) { base_type::generator().shorten(s); } - double shorten() const { return base_type::generator().shorten(); } - - private: - conv_dash(const conv_dash&); - const conv_dash& - operator = (const conv_dash&); - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_gpc.h corsix-th-0.62/agg/include/agg_conv_gpc.h --- corsix-th-0.30/agg/include/agg_conv_gpc.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_gpc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,432 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// General Polygon Clipper based on the GPC library by Alan Murta -// Union, Intersection, XOR, A-B, B-A -// Contact the author if you intend to use it in commercial applications! -// http://www.cs.man.ac.uk/aig/staff/alan/software/ -// Alan Murta (email: gpc@cs.man.ac.uk) -// -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_GPC_INCLUDED -#define AGG_CONV_GPC_INCLUDED - -#include -#include "agg_basics.h" -#include "agg_array.h" - -extern "C" -{ -#include "gpc.h" -} - -namespace agg -{ - enum gpc_op_e - { - gpc_or, - gpc_and, - gpc_xor, - gpc_a_minus_b, - gpc_b_minus_a - }; - - - //================================================================conv_gpc - template class conv_gpc - { - enum status - { - status_move_to, - status_line_to, - status_stop - }; - - struct contour_header_type - { - int num_vertices; - int hole_flag; - gpc_vertex* vertices; - }; - - typedef pod_bvector vertex_array_type; - typedef pod_bvector contour_header_array_type; - - - public: - typedef VSA source_a_type; - typedef VSB source_b_type; - typedef conv_gpc self_type; - - ~conv_gpc() - { - free_gpc_data(); - } - - conv_gpc(source_a_type& a, source_b_type& b, gpc_op_e op = gpc_or) : - m_src_a(&a), - m_src_b(&b), - m_status(status_move_to), - m_vertex(-1), - m_contour(-1), - m_operation(op) - { - memset(&m_poly_a, 0, sizeof(m_poly_a)); - memset(&m_poly_b, 0, sizeof(m_poly_b)); - memset(&m_result, 0, sizeof(m_result)); - } - - void attach1(VSA& source) { m_src_a = &source; } - void attach2(VSB& source) { m_src_b = &source; } - - void operation(gpc_op_e v) { m_operation = v; } - - // Vertex Source Interface - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - conv_gpc(const conv_gpc&); - const conv_gpc& operator = (const conv_gpc&); - - //-------------------------------------------------------------------- - void free_polygon(gpc_polygon& p); - void free_result(); - void free_gpc_data(); - void start_contour(); - void add_vertex(double x, double y); - void end_contour(unsigned orientation); - void make_polygon(gpc_polygon& p); - void start_extracting(); - bool next_contour(); - bool next_vertex(double* x, double* y); - - - //-------------------------------------------------------------------- - template void add(VS& src, gpc_polygon& p) - { - unsigned cmd; - double x, y; - double start_x = 0.0; - double start_y = 0.0; - bool line_to = false; - unsigned orientation = 0; - - m_contour_accumulator.remove_all(); - - while(!is_stop(cmd = src.vertex(&x, &y))) - { - if(is_vertex(cmd)) - { - if(is_move_to(cmd)) - { - if(line_to) - { - end_contour(orientation); - orientation = 0; - } - start_contour(); - start_x = x; - start_y = y; - } - add_vertex(x, y); - line_to = true; - } - else - { - if(is_end_poly(cmd)) - { - orientation = get_orientation(cmd); - if(line_to && is_closed(cmd)) - { - add_vertex(start_x, start_y); - } - } - } - } - if(line_to) - { - end_contour(orientation); - } - make_polygon(p); - } - - - private: - //-------------------------------------------------------------------- - source_a_type* m_src_a; - source_b_type* m_src_b; - status m_status; - int m_vertex; - int m_contour; - gpc_op_e m_operation; - vertex_array_type m_vertex_accumulator; - contour_header_array_type m_contour_accumulator; - gpc_polygon m_poly_a; - gpc_polygon m_poly_b; - gpc_polygon m_result; - }; - - - - - - //------------------------------------------------------------------------ - template - void conv_gpc::free_polygon(gpc_polygon& p) - { - int i; - for(i = 0; i < p.num_contours; i++) - { - pod_allocator::deallocate(p.contour[i].vertex, - p.contour[i].num_vertices); - } - pod_allocator::deallocate(p.contour, p.num_contours); - memset(&p, 0, sizeof(gpc_polygon)); - } - - - //------------------------------------------------------------------------ - template - void conv_gpc::free_result() - { - if(m_result.contour) - { - gpc_free_polygon(&m_result); - } - memset(&m_result, 0, sizeof(m_result)); - } - - - //------------------------------------------------------------------------ - template - void conv_gpc::free_gpc_data() - { - free_polygon(m_poly_a); - free_polygon(m_poly_b); - free_result(); - } - - - //------------------------------------------------------------------------ - template - void conv_gpc::start_contour() - { - contour_header_type h; - memset(&h, 0, sizeof(h)); - m_contour_accumulator.add(h); - m_vertex_accumulator.remove_all(); - } - - - //------------------------------------------------------------------------ - template - inline void conv_gpc::add_vertex(double x, double y) - { - gpc_vertex v; - v.x = x; - v.y = y; - m_vertex_accumulator.add(v); - } - - - //------------------------------------------------------------------------ - template - void conv_gpc::end_contour(unsigned orientation) - { - if(m_contour_accumulator.size()) - { - if(m_vertex_accumulator.size() > 2) - { - contour_header_type& h = - m_contour_accumulator[m_contour_accumulator.size() - 1]; - - h.num_vertices = m_vertex_accumulator.size(); - h.hole_flag = 0; - - // TO DO: Clarify the "holes" - //if(is_cw(orientation)) h.hole_flag = 1; - - h.vertices = pod_allocator::allocate(h.num_vertices); - gpc_vertex* d = h.vertices; - int i; - for(i = 0; i < h.num_vertices; i++) - { - const gpc_vertex& s = m_vertex_accumulator[i]; - d->x = s.x; - d->y = s.y; - ++d; - } - } - else - { - m_vertex_accumulator.remove_last(); - } - } - } - - - //------------------------------------------------------------------------ - template - void conv_gpc::make_polygon(gpc_polygon& p) - { - free_polygon(p); - if(m_contour_accumulator.size()) - { - p.num_contours = m_contour_accumulator.size(); - - p.hole = 0; - p.contour = pod_allocator::allocate(p.num_contours); - - int i; - gpc_vertex_list* pv = p.contour; - for(i = 0; i < p.num_contours; i++) - { - const contour_header_type& h = m_contour_accumulator[i]; - pv->num_vertices = h.num_vertices; - pv->vertex = h.vertices; - ++pv; - } - } - } - - - //------------------------------------------------------------------------ - template - void conv_gpc::start_extracting() - { - m_status = status_move_to; - m_contour = -1; - m_vertex = -1; - } - - - //------------------------------------------------------------------------ - template - bool conv_gpc::next_contour() - { - if(++m_contour < m_result.num_contours) - { - m_vertex = -1; - return true; - } - return false; - } - - - //------------------------------------------------------------------------ - template - inline bool conv_gpc::next_vertex(double* x, double* y) - { - const gpc_vertex_list& vlist = m_result.contour[m_contour]; - if(++m_vertex < vlist.num_vertices) - { - const gpc_vertex& v = vlist.vertex[m_vertex]; - *x = v.x; - *y = v.y; - return true; - } - return false; - } - - - //------------------------------------------------------------------------ - template - void conv_gpc::rewind(unsigned path_id) - { - free_result(); - m_src_a->rewind(path_id); - m_src_b->rewind(path_id); - add(*m_src_a, m_poly_a); - add(*m_src_b, m_poly_b); - switch(m_operation) - { - case gpc_or: - gpc_polygon_clip(GPC_UNION, - &m_poly_a, - &m_poly_b, - &m_result); - break; - - case gpc_and: - gpc_polygon_clip(GPC_INT, - &m_poly_a, - &m_poly_b, - &m_result); - break; - - case gpc_xor: - gpc_polygon_clip(GPC_XOR, - &m_poly_a, - &m_poly_b, - &m_result); - break; - - case gpc_a_minus_b: - gpc_polygon_clip(GPC_DIFF, - &m_poly_a, - &m_poly_b, - &m_result); - break; - - case gpc_b_minus_a: - gpc_polygon_clip(GPC_DIFF, - &m_poly_b, - &m_poly_a, - &m_result); - break; - } - start_extracting(); - } - - - //------------------------------------------------------------------------ - template - unsigned conv_gpc::vertex(double* x, double* y) - { - if(m_status == status_move_to) - { - if(next_contour()) - { - if(next_vertex(x, y)) - { - m_status = status_line_to; - return path_cmd_move_to; - } - m_status = status_stop; - return path_cmd_end_poly | path_flags_close; - } - } - else - { - if(next_vertex(x, y)) - { - return path_cmd_line_to; - } - else - { - m_status = status_move_to; - } - return path_cmd_end_poly | path_flags_close; - } - return path_cmd_stop; - } - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_marker_adaptor.h corsix-th-0.62/agg/include/agg_conv_marker_adaptor.h --- corsix-th-0.30/agg/include/agg_conv_marker_adaptor.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_marker_adaptor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_MARKER_ADAPTOR_INCLUDED -#define AGG_CONV_MARKER_ADAPTOR_INCLUDED - -#include "agg_basics.h" -#include "agg_conv_adaptor_vcgen.h" -#include "agg_vcgen_vertex_sequence.h" - -namespace agg -{ - - //=====================================================conv_marker_adaptor - template - struct conv_marker_adaptor : - public conv_adaptor_vcgen - { - typedef Markers marker_type; - typedef conv_adaptor_vcgen base_type; - - conv_marker_adaptor(VertexSource& vs) : - conv_adaptor_vcgen(vs) - { - } - - void shorten(double s) { base_type::generator().shorten(s); } - double shorten() const { return base_type::generator().shorten(); } - - private: - conv_marker_adaptor(const conv_marker_adaptor&); - const conv_marker_adaptor& - operator = (const conv_marker_adaptor&); - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_marker.h corsix-th-0.62/agg/include/agg_conv_marker.h --- corsix-th-0.30/agg/include/agg_conv_marker.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_marker.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// conv_marker -// -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_MARKER_INCLUDED -#define AGG_CONV_MARKER_INCLUDED - -#include "agg_basics.h" -#include "agg_trans_affine.h" - -namespace agg -{ - //-------------------------------------------------------------conv_marker - template - class conv_marker - { - public: - conv_marker(MarkerLocator& ml, MarkerShapes& ms); - - trans_affine& transform() { return m_transform; } - const trans_affine& transform() const { return m_transform; } - - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - conv_marker(const conv_marker&); - const conv_marker& - operator = (const conv_marker&); - - enum status_e - { - initial, - markers, - polygon, - stop - }; - - MarkerLocator* m_marker_locator; - MarkerShapes* m_marker_shapes; - trans_affine m_transform; - trans_affine m_mtx; - status_e m_status; - unsigned m_marker; - unsigned m_num_markers; - }; - - - //------------------------------------------------------------------------ - template - conv_marker::conv_marker(MarkerLocator& ml, MarkerShapes& ms) : - m_marker_locator(&ml), - m_marker_shapes(&ms), - m_status(initial), - m_marker(0), - m_num_markers(1) - { - } - - - //------------------------------------------------------------------------ - template - void conv_marker::rewind(unsigned) - { - m_status = initial; - m_marker = 0; - m_num_markers = 1; - } - - - //------------------------------------------------------------------------ - template - unsigned conv_marker::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_move_to; - double x1, y1, x2, y2; - - while(!is_stop(cmd)) - { - switch(m_status) - { - case initial: - if(m_num_markers == 0) - { - cmd = path_cmd_stop; - break; - } - m_marker_locator->rewind(m_marker); - ++m_marker; - m_num_markers = 0; - m_status = markers; - - case markers: - if(is_stop(m_marker_locator->vertex(&x1, &y1))) - { - m_status = initial; - break; - } - if(is_stop(m_marker_locator->vertex(&x2, &y2))) - { - m_status = initial; - break; - } - ++m_num_markers; - m_mtx = m_transform; - m_mtx *= trans_affine_rotation(atan2(y2 - y1, x2 - x1)); - m_mtx *= trans_affine_translation(x1, y1); - m_marker_shapes->rewind(m_marker - 1); - m_status = polygon; - - case polygon: - cmd = m_marker_shapes->vertex(x, y); - if(is_stop(cmd)) - { - cmd = path_cmd_move_to; - m_status = markers; - break; - } - m_mtx.transform(x, y); - return cmd; - - case stop: - cmd = path_cmd_stop; - break; - } - } - return cmd; - } - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_conv_segmentator.h corsix-th-0.62/agg/include/agg_conv_segmentator.h --- corsix-th-0.30/agg/include/agg_conv_segmentator.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_segmentator.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_SEGMENTATOR_INCLUDED -#define AGG_CONV_SEGMENTATOR_INCLUDED - -#include "agg_basics.h" -#include "agg_conv_adaptor_vpgen.h" -#include "agg_vpgen_segmentator.h" - -namespace agg -{ - - //========================================================conv_segmentator - template - struct conv_segmentator : public conv_adaptor_vpgen - { - typedef conv_adaptor_vpgen base_type; - - conv_segmentator(VertexSource& vs) : - conv_adaptor_vpgen(vs) {} - - void approximation_scale(double s) { base_type::vpgen().approximation_scale(s); } - double approximation_scale() const { return base_type::vpgen().approximation_scale(); } - - private: - conv_segmentator(const conv_segmentator&); - const conv_segmentator& - operator = (const conv_segmentator&); - }; - - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_conv_shorten_path.h corsix-th-0.62/agg/include/agg_conv_shorten_path.h --- corsix-th-0.30/agg/include/agg_conv_shorten_path.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_shorten_path.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_SHORTEN_PATH_INCLUDED -#define AGG_CONV_SHORTEN_PATH_INCLUDED - -#include "agg_basics.h" -#include "agg_conv_adaptor_vcgen.h" -#include "agg_vcgen_vertex_sequence.h" - -namespace agg -{ - - //=======================================================conv_shorten_path - template class conv_shorten_path : - public conv_adaptor_vcgen - { - public: - typedef conv_adaptor_vcgen base_type; - - conv_shorten_path(VertexSource& vs) : - conv_adaptor_vcgen(vs) - { - } - - void shorten(double s) { base_type::generator().shorten(s); } - double shorten() const { return base_type::generator().shorten(); } - - private: - conv_shorten_path(const conv_shorten_path&); - const conv_shorten_path& - operator = (const conv_shorten_path&); - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_smooth_poly1.h corsix-th-0.62/agg/include/agg_conv_smooth_poly1.h --- corsix-th-0.30/agg/include/agg_conv_smooth_poly1.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_smooth_poly1.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Smooth polygon generator -// -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_SMOOTH_POLY1_INCLUDED -#define AGG_CONV_SMOOTH_POLY1_INCLUDED - -#include "agg_basics.h" -#include "agg_vcgen_smooth_poly1.h" -#include "agg_conv_adaptor_vcgen.h" -#include "agg_conv_curve.h" - - -namespace agg -{ - - //-------------------------------------------------------conv_smooth_poly1 - template - struct conv_smooth_poly1 : - public conv_adaptor_vcgen - { - typedef conv_adaptor_vcgen base_type; - - conv_smooth_poly1(VertexSource& vs) : - conv_adaptor_vcgen(vs) - { - } - - void smooth_value(double v) { base_type::generator().smooth_value(v); } - double smooth_value() const { return base_type::generator().smooth_value(); } - - private: - conv_smooth_poly1(const conv_smooth_poly1&); - const conv_smooth_poly1& - operator = (const conv_smooth_poly1&); - }; - - - - //-------------------------------------------------conv_smooth_poly1_curve - template - struct conv_smooth_poly1_curve : - public conv_curve > - { - conv_smooth_poly1_curve(VertexSource& vs) : - conv_curve >(m_smooth), - m_smooth(vs) - { - } - - void smooth_value(double v) { m_smooth.generator().smooth_value(v); } - double smooth_value() const { return m_smooth.generator().smooth_value(); } - - private: - conv_smooth_poly1_curve(const conv_smooth_poly1_curve&); - const conv_smooth_poly1_curve& - operator = (const conv_smooth_poly1_curve&); - - conv_smooth_poly1 m_smooth; - }; - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_conv_stroke.h corsix-th-0.62/agg/include/agg_conv_stroke.h --- corsix-th-0.30/agg/include/agg_conv_stroke.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_stroke.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// conv_stroke -// -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_STROKE_INCLUDED -#define AGG_CONV_STROKE_INCLUDED - -#include "agg_basics.h" -#include "agg_vcgen_stroke.h" -#include "agg_conv_adaptor_vcgen.h" - -namespace agg -{ - - //-------------------------------------------------------------conv_stroke - template - struct conv_stroke : - public conv_adaptor_vcgen - { - typedef Markers marker_type; - typedef conv_adaptor_vcgen base_type; - - conv_stroke(VertexSource& vs) : - conv_adaptor_vcgen(vs) - { - } - - void line_cap(line_cap_e lc) { base_type::generator().line_cap(lc); } - void line_join(line_join_e lj) { base_type::generator().line_join(lj); } - void inner_join(inner_join_e ij) { base_type::generator().inner_join(ij); } - - line_cap_e line_cap() const { return base_type::generator().line_cap(); } - line_join_e line_join() const { return base_type::generator().line_join(); } - inner_join_e inner_join() const { return base_type::generator().inner_join(); } - - void width(double w) { base_type::generator().width(w); } - void miter_limit(double ml) { base_type::generator().miter_limit(ml); } - void miter_limit_theta(double t) { base_type::generator().miter_limit_theta(t); } - void inner_miter_limit(double ml) { base_type::generator().inner_miter_limit(ml); } - void approximation_scale(double as) { base_type::generator().approximation_scale(as); } - - double width() const { return base_type::generator().width(); } - double miter_limit() const { return base_type::generator().miter_limit(); } - double inner_miter_limit() const { return base_type::generator().inner_miter_limit(); } - double approximation_scale() const { return base_type::generator().approximation_scale(); } - - void shorten(double s) { base_type::generator().shorten(s); } - double shorten() const { return base_type::generator().shorten(); } - - private: - conv_stroke(const conv_stroke&); - const conv_stroke& - operator = (const conv_stroke&); - - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_transform.h corsix-th-0.62/agg/include/agg_conv_transform.h --- corsix-th-0.30/agg/include/agg_conv_transform.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_transform.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class conv_transform -// -//---------------------------------------------------------------------------- -#ifndef AGG_CONV_TRANSFORM_INCLUDED -#define AGG_CONV_TRANSFORM_INCLUDED - -#include "agg_basics.h" -#include "agg_trans_affine.h" - -namespace agg -{ - - //----------------------------------------------------------conv_transform - template class conv_transform - { - public: - conv_transform(VertexSource& source, const Transformer& tr) : - m_source(&source), m_trans(&tr) {} - void attach(VertexSource& source) { m_source = &source; } - - void rewind(unsigned path_id) - { - m_source->rewind(path_id); - } - - unsigned vertex(double* x, double* y) - { - unsigned cmd = m_source->vertex(x, y); - if(is_vertex(cmd)) - { - m_trans->transform(x, y); - } - return cmd; - } - - void transformer(const Transformer& tr) - { - m_trans = &tr; - } - - private: - conv_transform(const conv_transform&); - const conv_transform& - operator = (const conv_transform&); - - VertexSource* m_source; - const Transformer* m_trans; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_conv_unclose_polygon.h corsix-th-0.62/agg/include/agg_conv_unclose_polygon.h --- corsix-th-0.30/agg/include/agg_conv_unclose_polygon.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_conv_unclose_polygon.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CONV_UNCLOSE_POLYGON_INCLUDED -#define AGG_CONV_UNCLOSE_POLYGON_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - //====================================================conv_unclose_polygon - template class conv_unclose_polygon - { - public: - explicit conv_unclose_polygon(VertexSource& vs) : m_source(&vs) {} - void attach(VertexSource& source) { m_source = &source; } - - void rewind(unsigned path_id) - { - m_source->rewind(path_id); - } - - unsigned vertex(double* x, double* y) - { - unsigned cmd = m_source->vertex(x, y); - if(is_end_poly(cmd)) cmd &= ~path_flags_close; - return cmd; - } - - private: - conv_unclose_polygon(const conv_unclose_polygon&); - const conv_unclose_polygon& - operator = (const conv_unclose_polygon&); - - VertexSource* m_source; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_curves.h corsix-th-0.62/agg/include/agg_curves.h --- corsix-th-0.30/agg/include/agg_curves.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_curves.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,693 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// Copyright (C) 2005 Tony Juricic (tonygeek@yahoo.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_CURVES_INCLUDED -#define AGG_CURVES_INCLUDED - -#include "agg_array.h" - -namespace agg -{ - - // See Implementation agg_curves.cpp - - //--------------------------------------------curve_approximation_method_e - enum curve_approximation_method_e - { - curve_inc, - curve_div - }; - - //--------------------------------------------------------------curve3_inc - class curve3_inc - { - public: - curve3_inc() : - m_num_steps(0), m_step(0), m_scale(1.0) { } - - curve3_inc(double x1, double y1, - double x2, double y2, - double x3, double y3) : - m_num_steps(0), m_step(0), m_scale(1.0) - { - init(x1, y1, x2, y2, x3, y3); - } - - void reset() { m_num_steps = 0; m_step = -1; } - void init(double x1, double y1, - double x2, double y2, - double x3, double y3); - - void approximation_method(curve_approximation_method_e) {} - curve_approximation_method_e approximation_method() const { return curve_inc; } - - void approximation_scale(double s); - double approximation_scale() const; - - void angle_tolerance(double) {} - double angle_tolerance() const { return 0.0; } - - void cusp_limit(double) {} - double cusp_limit() const { return 0.0; } - - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - int m_num_steps; - int m_step; - double m_scale; - double m_start_x; - double m_start_y; - double m_end_x; - double m_end_y; - double m_fx; - double m_fy; - double m_dfx; - double m_dfy; - double m_ddfx; - double m_ddfy; - double m_saved_fx; - double m_saved_fy; - double m_saved_dfx; - double m_saved_dfy; - }; - - - - - - //-------------------------------------------------------------curve3_div - class curve3_div - { - public: - curve3_div() : - m_approximation_scale(1.0), - m_angle_tolerance(0.0), - m_count(0) - {} - - curve3_div(double x1, double y1, - double x2, double y2, - double x3, double y3) : - m_approximation_scale(1.0), - m_angle_tolerance(0.0), - m_count(0) - { - init(x1, y1, x2, y2, x3, y3); - } - - void reset() { m_points.remove_all(); m_count = 0; } - void init(double x1, double y1, - double x2, double y2, - double x3, double y3); - - void approximation_method(curve_approximation_method_e) {} - curve_approximation_method_e approximation_method() const { return curve_div; } - - void approximation_scale(double s) { m_approximation_scale = s; } - double approximation_scale() const { return m_approximation_scale; } - - void angle_tolerance(double a) { m_angle_tolerance = a; } - double angle_tolerance() const { return m_angle_tolerance; } - - void cusp_limit(double) {} - double cusp_limit() const { return 0.0; } - - void rewind(unsigned) - { - m_count = 0; - } - - unsigned vertex(double* x, double* y) - { - if(m_count >= m_points.size()) return path_cmd_stop; - const point_d& p = m_points[m_count++]; - *x = p.x; - *y = p.y; - return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to; - } - - private: - void bezier(double x1, double y1, - double x2, double y2, - double x3, double y3); - void recursive_bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - unsigned level); - - double m_approximation_scale; - double m_distance_tolerance_square; - double m_angle_tolerance; - unsigned m_count; - pod_bvector m_points; - }; - - - - - - - - //-------------------------------------------------------------curve4_points - struct curve4_points - { - double cp[8]; - curve4_points() {} - curve4_points(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2; - cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4; - } - void init(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2; - cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4; - } - double operator [] (unsigned i) const { return cp[i]; } - double& operator [] (unsigned i) { return cp[i]; } - }; - - - - //-------------------------------------------------------------curve4_inc - class curve4_inc - { - public: - curve4_inc() : - m_num_steps(0), m_step(0), m_scale(1.0) { } - - curve4_inc(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) : - m_num_steps(0), m_step(0), m_scale(1.0) - { - init(x1, y1, x2, y2, x3, y3, x4, y4); - } - - curve4_inc(const curve4_points& cp) : - m_num_steps(0), m_step(0), m_scale(1.0) - { - init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); - } - - void reset() { m_num_steps = 0; m_step = -1; } - void init(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4); - - void init(const curve4_points& cp) - { - init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); - } - - void approximation_method(curve_approximation_method_e) {} - curve_approximation_method_e approximation_method() const { return curve_inc; } - - void approximation_scale(double s); - double approximation_scale() const; - - void angle_tolerance(double) {} - double angle_tolerance() const { return 0.0; } - - void cusp_limit(double) {} - double cusp_limit() const { return 0.0; } - - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - int m_num_steps; - int m_step; - double m_scale; - double m_start_x; - double m_start_y; - double m_end_x; - double m_end_y; - double m_fx; - double m_fy; - double m_dfx; - double m_dfy; - double m_ddfx; - double m_ddfy; - double m_dddfx; - double m_dddfy; - double m_saved_fx; - double m_saved_fy; - double m_saved_dfx; - double m_saved_dfy; - double m_saved_ddfx; - double m_saved_ddfy; - }; - - - - //-------------------------------------------------------catrom_to_bezier - inline curve4_points catrom_to_bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - // Trans. matrix Catmull-Rom to Bezier - // - // 0 1 0 0 - // -1/6 1 1/6 0 - // 0 1/6 1 -1/6 - // 0 0 1 0 - // - return curve4_points( - x2, - y2, - (-x1 + 6*x2 + x3) / 6, - (-y1 + 6*y2 + y3) / 6, - ( x2 + 6*x3 - x4) / 6, - ( y2 + 6*y3 - y4) / 6, - x3, - y3); - } - - - //----------------------------------------------------------------------- - inline curve4_points - catrom_to_bezier(const curve4_points& cp) - { - return catrom_to_bezier(cp[0], cp[1], cp[2], cp[3], - cp[4], cp[5], cp[6], cp[7]); - } - - - - //-----------------------------------------------------ubspline_to_bezier - inline curve4_points ubspline_to_bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - // Trans. matrix Uniform BSpline to Bezier - // - // 1/6 4/6 1/6 0 - // 0 4/6 2/6 0 - // 0 2/6 4/6 0 - // 0 1/6 4/6 1/6 - // - return curve4_points( - (x1 + 4*x2 + x3) / 6, - (y1 + 4*y2 + y3) / 6, - (4*x2 + 2*x3) / 6, - (4*y2 + 2*y3) / 6, - (2*x2 + 4*x3) / 6, - (2*y2 + 4*y3) / 6, - (x2 + 4*x3 + x4) / 6, - (y2 + 4*y3 + y4) / 6); - } - - - //----------------------------------------------------------------------- - inline curve4_points - ubspline_to_bezier(const curve4_points& cp) - { - return ubspline_to_bezier(cp[0], cp[1], cp[2], cp[3], - cp[4], cp[5], cp[6], cp[7]); - } - - - - - //------------------------------------------------------hermite_to_bezier - inline curve4_points hermite_to_bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - // Trans. matrix Hermite to Bezier - // - // 1 0 0 0 - // 1 0 1/3 0 - // 0 1 0 -1/3 - // 0 1 0 0 - // - return curve4_points( - x1, - y1, - (3*x1 + x3) / 3, - (3*y1 + y3) / 3, - (3*x2 - x4) / 3, - (3*y2 - y4) / 3, - x2, - y2); - } - - - - //----------------------------------------------------------------------- - inline curve4_points - hermite_to_bezier(const curve4_points& cp) - { - return hermite_to_bezier(cp[0], cp[1], cp[2], cp[3], - cp[4], cp[5], cp[6], cp[7]); - } - - - //-------------------------------------------------------------curve4_div - class curve4_div - { - public: - curve4_div() : - m_approximation_scale(1.0), - m_angle_tolerance(0.0), - m_cusp_limit(0.0), - m_count(0) - {} - - curve4_div(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) : - m_approximation_scale(1.0), - m_angle_tolerance(0.0), - m_cusp_limit(0.0), - m_count(0) - { - init(x1, y1, x2, y2, x3, y3, x4, y4); - } - - curve4_div(const curve4_points& cp) : - m_approximation_scale(1.0), - m_angle_tolerance(0.0), - m_count(0) - { - init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); - } - - void reset() { m_points.remove_all(); m_count = 0; } - void init(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4); - - void init(const curve4_points& cp) - { - init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); - } - - void approximation_method(curve_approximation_method_e) {} - - curve_approximation_method_e approximation_method() const - { - return curve_div; - } - - void approximation_scale(double s) { m_approximation_scale = s; } - double approximation_scale() const { return m_approximation_scale; } - - void angle_tolerance(double a) { m_angle_tolerance = a; } - double angle_tolerance() const { return m_angle_tolerance; } - - void cusp_limit(double v) - { - m_cusp_limit = (v == 0.0) ? 0.0 : pi - v; - } - - double cusp_limit() const - { - return (m_cusp_limit == 0.0) ? 0.0 : pi - m_cusp_limit; - } - - void rewind(unsigned) - { - m_count = 0; - } - - unsigned vertex(double* x, double* y) - { - if(m_count >= m_points.size()) return path_cmd_stop; - const point_d& p = m_points[m_count++]; - *x = p.x; - *y = p.y; - return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to; - } - - private: - void bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4); - - void recursive_bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4, - unsigned level); - - double m_approximation_scale; - double m_distance_tolerance_square; - double m_angle_tolerance; - double m_cusp_limit; - unsigned m_count; - pod_bvector m_points; - }; - - - //-----------------------------------------------------------------curve3 - class curve3 - { - public: - curve3() : m_approximation_method(curve_div) {} - curve3(double x1, double y1, - double x2, double y2, - double x3, double y3) : - m_approximation_method(curve_div) - { - init(x1, y1, x2, y2, x3, y3); - } - - void reset() - { - m_curve_inc.reset(); - m_curve_div.reset(); - } - - void init(double x1, double y1, - double x2, double y2, - double x3, double y3) - { - if(m_approximation_method == curve_inc) - { - m_curve_inc.init(x1, y1, x2, y2, x3, y3); - } - else - { - m_curve_div.init(x1, y1, x2, y2, x3, y3); - } - } - - void approximation_method(curve_approximation_method_e v) - { - m_approximation_method = v; - } - - curve_approximation_method_e approximation_method() const - { - return m_approximation_method; - } - - void approximation_scale(double s) - { - m_curve_inc.approximation_scale(s); - m_curve_div.approximation_scale(s); - } - - double approximation_scale() const - { - return m_curve_inc.approximation_scale(); - } - - void angle_tolerance(double a) - { - m_curve_div.angle_tolerance(a); - } - - double angle_tolerance() const - { - return m_curve_div.angle_tolerance(); - } - - void cusp_limit(double v) - { - m_curve_div.cusp_limit(v); - } - - double cusp_limit() const - { - return m_curve_div.cusp_limit(); - } - - void rewind(unsigned path_id) - { - if(m_approximation_method == curve_inc) - { - m_curve_inc.rewind(path_id); - } - else - { - m_curve_div.rewind(path_id); - } - } - - unsigned vertex(double* x, double* y) - { - if(m_approximation_method == curve_inc) - { - return m_curve_inc.vertex(x, y); - } - return m_curve_div.vertex(x, y); - } - - private: - curve3_inc m_curve_inc; - curve3_div m_curve_div; - curve_approximation_method_e m_approximation_method; - }; - - - - - - //-----------------------------------------------------------------curve4 - class curve4 - { - public: - curve4() : m_approximation_method(curve_div) {} - curve4(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) : - m_approximation_method(curve_div) - { - init(x1, y1, x2, y2, x3, y3, x4, y4); - } - - curve4(const curve4_points& cp) : - m_approximation_method(curve_div) - { - init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); - } - - void reset() - { - m_curve_inc.reset(); - m_curve_div.reset(); - } - - void init(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - if(m_approximation_method == curve_inc) - { - m_curve_inc.init(x1, y1, x2, y2, x3, y3, x4, y4); - } - else - { - m_curve_div.init(x1, y1, x2, y2, x3, y3, x4, y4); - } - } - - void init(const curve4_points& cp) - { - init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); - } - - void approximation_method(curve_approximation_method_e v) - { - m_approximation_method = v; - } - - curve_approximation_method_e approximation_method() const - { - return m_approximation_method; - } - - void approximation_scale(double s) - { - m_curve_inc.approximation_scale(s); - m_curve_div.approximation_scale(s); - } - double approximation_scale() const { return m_curve_inc.approximation_scale(); } - - void angle_tolerance(double v) - { - m_curve_div.angle_tolerance(v); - } - - double angle_tolerance() const - { - return m_curve_div.angle_tolerance(); - } - - void cusp_limit(double v) - { - m_curve_div.cusp_limit(v); - } - - double cusp_limit() const - { - return m_curve_div.cusp_limit(); - } - - void rewind(unsigned path_id) - { - if(m_approximation_method == curve_inc) - { - m_curve_inc.rewind(path_id); - } - else - { - m_curve_div.rewind(path_id); - } - } - - unsigned vertex(double* x, double* y) - { - if(m_approximation_method == curve_inc) - { - return m_curve_inc.vertex(x, y); - } - return m_curve_div.vertex(x, y); - } - - private: - curve4_inc m_curve_inc; - curve4_div m_curve_div; - curve_approximation_method_e m_approximation_method; - }; - - - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_dda_line.h corsix-th-0.62/agg/include/agg_dda_line.h --- corsix-th-0.30/agg/include/agg_dda_line.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_dda_line.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,290 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// classes dda_line_interpolator, dda2_line_interpolator -// -//---------------------------------------------------------------------------- - -#ifndef AGG_DDA_LINE_INCLUDED -#define AGG_DDA_LINE_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - - //===================================================dda_line_interpolator - template class dda_line_interpolator - { - public: - //-------------------------------------------------------------------- - dda_line_interpolator() {} - - //-------------------------------------------------------------------- - dda_line_interpolator(int y1, int y2, unsigned count) : - m_y(y1), - m_inc(((y2 - y1) << FractionShift) / int(count)), - m_dy(0) - { - } - - //-------------------------------------------------------------------- - void operator ++ () - { - m_dy += m_inc; - } - - //-------------------------------------------------------------------- - void operator -- () - { - m_dy -= m_inc; - } - - //-------------------------------------------------------------------- - void operator += (unsigned n) - { - m_dy += m_inc * n; - } - - //-------------------------------------------------------------------- - void operator -= (unsigned n) - { - m_dy -= m_inc * n; - } - - - //-------------------------------------------------------------------- - int y() const { return m_y + (m_dy >> (FractionShift-YShift)); } - int dy() const { return m_dy; } - - - private: - int m_y; - int m_inc; - int m_dy; - }; - - - - - - //=================================================dda2_line_interpolator - class dda2_line_interpolator - { - public: - typedef int save_data_type; - enum save_size_e { save_size = 2 }; - - //-------------------------------------------------------------------- - dda2_line_interpolator() {} - - //-------------------------------------------- Forward-adjusted line - dda2_line_interpolator(int y1, int y2, int count) : - m_cnt(count <= 0 ? 1 : count), - m_lft((y2 - y1) / m_cnt), - m_rem((y2 - y1) % m_cnt), - m_mod(m_rem), - m_y(y1) - { - if(m_mod <= 0) - { - m_mod += count; - m_rem += count; - m_lft--; - } - m_mod -= count; - } - - //-------------------------------------------- Backward-adjusted line - dda2_line_interpolator(int y1, int y2, int count, int) : - m_cnt(count <= 0 ? 1 : count), - m_lft((y2 - y1) / m_cnt), - m_rem((y2 - y1) % m_cnt), - m_mod(m_rem), - m_y(y1) - { - if(m_mod <= 0) - { - m_mod += count; - m_rem += count; - m_lft--; - } - } - - //-------------------------------------------- Backward-adjusted line - dda2_line_interpolator(int y, int count) : - m_cnt(count <= 0 ? 1 : count), - m_lft(y / m_cnt), - m_rem(y % m_cnt), - m_mod(m_rem), - m_y(0) - { - if(m_mod <= 0) - { - m_mod += count; - m_rem += count; - m_lft--; - } - } - - - //-------------------------------------------------------------------- - void save(save_data_type* data) const - { - data[0] = m_mod; - data[1] = m_y; - } - - //-------------------------------------------------------------------- - void load(const save_data_type* data) - { - m_mod = data[0]; - m_y = data[1]; - } - - //-------------------------------------------------------------------- - void operator++() - { - m_mod += m_rem; - m_y += m_lft; - if(m_mod > 0) - { - m_mod -= m_cnt; - m_y++; - } - } - - //-------------------------------------------------------------------- - void operator--() - { - if(m_mod <= m_rem) - { - m_mod += m_cnt; - m_y--; - } - m_mod -= m_rem; - m_y -= m_lft; - } - - //-------------------------------------------------------------------- - void adjust_forward() - { - m_mod -= m_cnt; - } - - //-------------------------------------------------------------------- - void adjust_backward() - { - m_mod += m_cnt; - } - - //-------------------------------------------------------------------- - int mod() const { return m_mod; } - int rem() const { return m_rem; } - int lft() const { return m_lft; } - - //-------------------------------------------------------------------- - int y() const { return m_y; } - - private: - int m_cnt; - int m_lft; - int m_rem; - int m_mod; - int m_y; - }; - - - - - - - - //---------------------------------------------line_bresenham_interpolator - class line_bresenham_interpolator - { - public: - enum subpixel_scale_e - { - subpixel_shift = 8, - subpixel_scale = 1 << subpixel_shift, - subpixel_mask = subpixel_scale - 1 - }; - - //-------------------------------------------------------------------- - static int line_lr(int v) { return v >> subpixel_shift; } - - //-------------------------------------------------------------------- - line_bresenham_interpolator(int x1, int y1, int x2, int y2) : - m_x1_lr(line_lr(x1)), - m_y1_lr(line_lr(y1)), - m_x2_lr(line_lr(x2)), - m_y2_lr(line_lr(y2)), - m_ver(abs(m_x2_lr - m_x1_lr) < abs(m_y2_lr - m_y1_lr)), - m_len(m_ver ? abs(m_y2_lr - m_y1_lr) : - abs(m_x2_lr - m_x1_lr)), - m_inc(m_ver ? ((y2 > y1) ? 1 : -1) : ((x2 > x1) ? 1 : -1)), - m_interpolator(m_ver ? x1 : y1, - m_ver ? x2 : y2, - m_len) - { - } - - //-------------------------------------------------------------------- - bool is_ver() const { return m_ver; } - unsigned len() const { return m_len; } - int inc() const { return m_inc; } - - //-------------------------------------------------------------------- - void hstep() - { - ++m_interpolator; - m_x1_lr += m_inc; - } - - //-------------------------------------------------------------------- - void vstep() - { - ++m_interpolator; - m_y1_lr += m_inc; - } - - //-------------------------------------------------------------------- - int x1() const { return m_x1_lr; } - int y1() const { return m_y1_lr; } - int x2() const { return line_lr(m_interpolator.y()); } - int y2() const { return line_lr(m_interpolator.y()); } - int x2_hr() const { return m_interpolator.y(); } - int y2_hr() const { return m_interpolator.y(); } - - private: - int m_x1_lr; - int m_y1_lr; - int m_x2_lr; - int m_y2_lr; - bool m_ver; - unsigned m_len; - int m_inc; - dda2_line_interpolator m_interpolator; - - }; - - -} - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_ellipse_bresenham.h corsix-th-0.62/agg/include/agg_ellipse_bresenham.h --- corsix-th-0.30/agg/include/agg_ellipse_bresenham.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_ellipse_bresenham.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Simple Bresenham interpolator for ellipsees -// -//---------------------------------------------------------------------------- - -#ifndef AGG_ELLIPSE_BRESENHAM_INCLUDED -#define AGG_ELLIPSE_BRESENHAM_INCLUDED - - -#include "agg_basics.h" - - -namespace agg -{ - - //------------------------------------------ellipse_bresenham_interpolator - class ellipse_bresenham_interpolator - { - public: - ellipse_bresenham_interpolator(int rx, int ry) : - m_rx2(rx * rx), - m_ry2(ry * ry), - m_two_rx2(m_rx2 << 1), - m_two_ry2(m_ry2 << 1), - m_dx(0), - m_dy(0), - m_inc_x(0), - m_inc_y(-ry * m_two_rx2), - m_cur_f(0) - {} - - int dx() const { return m_dx; } - int dy() const { return m_dy; } - - void operator++ () - { - int mx, my, mxy, min_m; - int fx, fy, fxy; - - mx = fx = m_cur_f + m_inc_x + m_ry2; - if(mx < 0) mx = -mx; - - my = fy = m_cur_f + m_inc_y + m_rx2; - if(my < 0) my = -my; - - mxy = fxy = m_cur_f + m_inc_x + m_ry2 + m_inc_y + m_rx2; - if(mxy < 0) mxy = -mxy; - - min_m = mx; - bool flag = true; - - if(min_m > my) - { - min_m = my; - flag = false; - } - - m_dx = m_dy = 0; - - if(min_m > mxy) - { - m_inc_x += m_two_ry2; - m_inc_y += m_two_rx2; - m_cur_f = fxy; - m_dx = 1; - m_dy = 1; - return; - } - - if(flag) - { - m_inc_x += m_two_ry2; - m_cur_f = fx; - m_dx = 1; - return; - } - - m_inc_y += m_two_rx2; - m_cur_f = fy; - m_dy = 1; - } - - private: - int m_rx2; - int m_ry2; - int m_two_rx2; - int m_two_ry2; - int m_dx; - int m_dy; - int m_inc_x; - int m_inc_y; - int m_cur_f; - - }; - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_ellipse.h corsix-th-0.62/agg/include/agg_ellipse.h --- corsix-th-0.30/agg/include/agg_ellipse.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_ellipse.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class ellipse -// -//---------------------------------------------------------------------------- - -#ifndef AGG_ELLIPSE_INCLUDED -#define AGG_ELLIPSE_INCLUDED - -#include "agg_basics.h" -#include - -namespace agg -{ - - //----------------------------------------------------------------ellipse - class ellipse - { - public: - ellipse() : - m_x(0.0), m_y(0.0), m_rx(1.0), m_ry(1.0), m_scale(1.0), - m_num(4), m_step(0), m_cw(false) {} - - ellipse(double x, double y, double rx, double ry, - unsigned num_steps=0, bool cw=false) : - m_x(x), m_y(y), m_rx(rx), m_ry(ry), m_scale(1.0), - m_num(num_steps), m_step(0), m_cw(cw) - { - if(m_num == 0) calc_num_steps(); - } - - void init(double x, double y, double rx, double ry, - unsigned num_steps=0, bool cw=false); - - void approximation_scale(double scale); - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - void calc_num_steps(); - - double m_x; - double m_y; - double m_rx; - double m_ry; - double m_scale; - unsigned m_num; - unsigned m_step; - bool m_cw; - }; - - //------------------------------------------------------------------------ - inline void ellipse::init(double x, double y, double rx, double ry, - unsigned num_steps, bool cw) - { - m_x = x; - m_y = y; - m_rx = rx; - m_ry = ry; - m_num = num_steps; - m_step = 0; - m_cw = cw; - if(m_num == 0) calc_num_steps(); - } - - //------------------------------------------------------------------------ - inline void ellipse::approximation_scale(double scale) - { - m_scale = scale; - calc_num_steps(); - } - - //------------------------------------------------------------------------ - inline void ellipse::calc_num_steps() - { - double ra = (fabs(m_rx) + fabs(m_ry)) / 2; - double da = acos(ra / (ra + 0.125 / m_scale)) * 2; - m_num = uround(2*pi / da); - } - - //------------------------------------------------------------------------ - inline void ellipse::rewind(unsigned) - { - m_step = 0; - } - - //------------------------------------------------------------------------ - inline unsigned ellipse::vertex(double* x, double* y) - { - if(m_step == m_num) - { - ++m_step; - return path_cmd_end_poly | path_flags_close | path_flags_ccw; - } - if(m_step > m_num) return path_cmd_stop; - double angle = double(m_step) / double(m_num) * 2.0 * pi; - if(m_cw) angle = 2.0 * pi - angle; - *x = m_x + cos(angle) * m_rx; - *y = m_y + sin(angle) * m_ry; - m_step++; - return ((m_step == 1) ? path_cmd_move_to : path_cmd_line_to); - } - -} - - - -#endif - - diff -Nru corsix-th-0.30/agg/include/agg_embedded_raster_fonts.h corsix-th-0.62/agg/include/agg_embedded_raster_fonts.h --- corsix-th-0.30/agg/include/agg_embedded_raster_fonts.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_embedded_raster_fonts.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_EMBEDDED_RASTER_FONTS_INCLUDED -#define AGG_EMBEDDED_RASTER_FONTS_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - extern const int8u gse4x6[]; - extern const int8u gse4x8[]; - extern const int8u gse5x7[]; - extern const int8u gse5x9[]; - extern const int8u gse6x12[]; - extern const int8u gse6x9[]; - extern const int8u gse7x11[]; - extern const int8u gse7x11_bold[]; - extern const int8u gse7x15[]; - extern const int8u gse7x15_bold[]; - extern const int8u gse8x16[]; - extern const int8u gse8x16_bold[]; - extern const int8u mcs11_prop[]; - extern const int8u mcs11_prop_condensed[]; - extern const int8u mcs12_prop[]; - extern const int8u mcs13_prop[]; - extern const int8u mcs5x10_mono[]; - extern const int8u mcs5x11_mono[]; - extern const int8u mcs6x10_mono[]; - extern const int8u mcs6x11_mono[]; - extern const int8u mcs7x12_mono_high[]; - extern const int8u mcs7x12_mono_low[]; - extern const int8u verdana12[]; - extern const int8u verdana12_bold[]; - extern const int8u verdana13[]; - extern const int8u verdana13_bold[]; - extern const int8u verdana14[]; - extern const int8u verdana14_bold[]; - extern const int8u verdana16[]; - extern const int8u verdana16_bold[]; - extern const int8u verdana17[]; - extern const int8u verdana17_bold[]; - extern const int8u verdana18[]; - extern const int8u verdana18_bold[]; -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_font_cache_manager.h corsix-th-0.62/agg/include/agg_font_cache_manager.h --- corsix-th-0.30/agg/include/agg_font_cache_manager.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_font_cache_manager.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,409 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_FONT_CACHE_MANAGER_INCLUDED -#define AGG_FONT_CACHE_MANAGER_INCLUDED - -#include -#include "agg_array.h" - -namespace agg -{ - - //---------------------------------------------------------glyph_data_type - enum glyph_data_type - { - glyph_data_invalid = 0, - glyph_data_mono = 1, - glyph_data_gray8 = 2, - glyph_data_outline = 3 - }; - - - //-------------------------------------------------------------glyph_cache - struct glyph_cache - { - unsigned glyph_index; - int8u* data; - unsigned data_size; - glyph_data_type data_type; - rect_i bounds; - double advance_x; - double advance_y; - }; - - - //--------------------------------------------------------------font_cache - class font_cache - { - public: - enum block_size_e { block_size = 16384-16 }; - - //-------------------------------------------------------------------- - font_cache() : - m_allocator(block_size), - m_font_signature(0) - {} - - //-------------------------------------------------------------------- - void signature(const char* font_signature) - { - m_font_signature = (char*)m_allocator.allocate(strlen(font_signature) + 1); - strcpy(m_font_signature, font_signature); - memset(m_glyphs, 0, sizeof(m_glyphs)); - } - - //-------------------------------------------------------------------- - bool font_is(const char* font_signature) const - { - return strcmp(font_signature, m_font_signature) == 0; - } - - //-------------------------------------------------------------------- - const glyph_cache* find_glyph(unsigned glyph_code) const - { - unsigned msb = (glyph_code >> 8) & 0xFF; - if(m_glyphs[msb]) - { - return m_glyphs[msb][glyph_code & 0xFF]; - } - return 0; - } - - //-------------------------------------------------------------------- - glyph_cache* cache_glyph(unsigned glyph_code, - unsigned glyph_index, - unsigned data_size, - glyph_data_type data_type, - const rect_i& bounds, - double advance_x, - double advance_y) - { - unsigned msb = (glyph_code >> 8) & 0xFF; - if(m_glyphs[msb] == 0) - { - m_glyphs[msb] = - (glyph_cache**)m_allocator.allocate(sizeof(glyph_cache*) * 256, - sizeof(glyph_cache*)); - memset(m_glyphs[msb], 0, sizeof(glyph_cache*) * 256); - } - - unsigned lsb = glyph_code & 0xFF; - if(m_glyphs[msb][lsb]) return 0; // Already exists, do not overwrite - - glyph_cache* glyph = - (glyph_cache*)m_allocator.allocate(sizeof(glyph_cache), - sizeof(double)); - - glyph->glyph_index = glyph_index; - glyph->data = m_allocator.allocate(data_size); - glyph->data_size = data_size; - glyph->data_type = data_type; - glyph->bounds = bounds; - glyph->advance_x = advance_x; - glyph->advance_y = advance_y; - return m_glyphs[msb][lsb] = glyph; - } - - private: - block_allocator m_allocator; - glyph_cache** m_glyphs[256]; - char* m_font_signature; - }; - - - - - - - - //---------------------------------------------------------font_cache_pool - class font_cache_pool - { - public: - //-------------------------------------------------------------------- - ~font_cache_pool() - { - unsigned i; - for(i = 0; i < m_num_fonts; ++i) - { - obj_allocator::deallocate(m_fonts[i]); - } - pod_allocator::deallocate(m_fonts, m_max_fonts); - } - - //-------------------------------------------------------------------- - font_cache_pool(unsigned max_fonts=32) : - m_fonts(pod_allocator::allocate(max_fonts)), - m_max_fonts(max_fonts), - m_num_fonts(0), - m_cur_font(0) - {} - - - //-------------------------------------------------------------------- - void font(const char* font_signature, bool reset_cache = false) - { - int idx = find_font(font_signature); - if(idx >= 0) - { - if(reset_cache) - { - obj_allocator::deallocate(m_fonts[idx]); - m_fonts[idx] = obj_allocator::allocate(); - m_fonts[idx]->signature(font_signature); - } - m_cur_font = m_fonts[idx]; - } - else - { - if(m_num_fonts >= m_max_fonts) - { - obj_allocator::deallocate(m_fonts[0]); - memcpy(m_fonts, - m_fonts + 1, - (m_max_fonts - 1) * sizeof(font_cache*)); - m_num_fonts = m_max_fonts - 1; - } - m_fonts[m_num_fonts] = obj_allocator::allocate(); - m_fonts[m_num_fonts]->signature(font_signature); - m_cur_font = m_fonts[m_num_fonts]; - ++m_num_fonts; - } - } - - //-------------------------------------------------------------------- - const font_cache* font() const - { - return m_cur_font; - } - - //-------------------------------------------------------------------- - const glyph_cache* find_glyph(unsigned glyph_code) const - { - if(m_cur_font) return m_cur_font->find_glyph(glyph_code); - return 0; - } - - //-------------------------------------------------------------------- - glyph_cache* cache_glyph(unsigned glyph_code, - unsigned glyph_index, - unsigned data_size, - glyph_data_type data_type, - const rect_i& bounds, - double advance_x, - double advance_y) - { - if(m_cur_font) - { - return m_cur_font->cache_glyph(glyph_code, - glyph_index, - data_size, - data_type, - bounds, - advance_x, - advance_y); - } - return 0; - } - - - //-------------------------------------------------------------------- - int find_font(const char* font_signature) - { - unsigned i; - for(i = 0; i < m_num_fonts; i++) - { - if(m_fonts[i]->font_is(font_signature)) return int(i); - } - return -1; - } - - private: - font_cache** m_fonts; - unsigned m_max_fonts; - unsigned m_num_fonts; - font_cache* m_cur_font; - }; - - - - - //------------------------------------------------------------------------ - enum glyph_rendering - { - glyph_ren_native_mono, - glyph_ren_native_gray8, - glyph_ren_outline, - glyph_ren_agg_mono, - glyph_ren_agg_gray8 - }; - - - - - //------------------------------------------------------font_cache_manager - template class font_cache_manager - { - public: - typedef FontEngine font_engine_type; - typedef font_cache_manager self_type; - typedef typename font_engine_type::path_adaptor_type path_adaptor_type; - typedef typename font_engine_type::gray8_adaptor_type gray8_adaptor_type; - typedef typename gray8_adaptor_type::embedded_scanline gray8_scanline_type; - typedef typename font_engine_type::mono_adaptor_type mono_adaptor_type; - typedef typename mono_adaptor_type::embedded_scanline mono_scanline_type; - - //-------------------------------------------------------------------- - font_cache_manager(font_engine_type& engine, unsigned max_fonts=32) : - m_fonts(max_fonts), - m_engine(engine), - m_change_stamp(-1), - m_prev_glyph(0), - m_last_glyph(0) - {} - - //-------------------------------------------------------------------- - void reset_last_glyph() - { - m_prev_glyph = m_last_glyph = 0; - } - - //-------------------------------------------------------------------- - const glyph_cache* glyph(unsigned glyph_code) - { - synchronize(); - const glyph_cache* gl = m_fonts.find_glyph(glyph_code); - if(gl) - { - m_prev_glyph = m_last_glyph; - return m_last_glyph = gl; - } - else - { - if(m_engine.prepare_glyph(glyph_code)) - { - m_prev_glyph = m_last_glyph; - m_last_glyph = m_fonts.cache_glyph(glyph_code, - m_engine.glyph_index(), - m_engine.data_size(), - m_engine.data_type(), - m_engine.bounds(), - m_engine.advance_x(), - m_engine.advance_y()); - m_engine.write_glyph_to(m_last_glyph->data); - return m_last_glyph; - } - } - return 0; - } - - //-------------------------------------------------------------------- - void init_embedded_adaptors(const glyph_cache* gl, - double x, double y, - double scale=1.0) - { - if(gl) - { - switch(gl->data_type) - { - default: return; - case glyph_data_mono: - m_mono_adaptor.init(gl->data, gl->data_size, x, y); - break; - - case glyph_data_gray8: - m_gray8_adaptor.init(gl->data, gl->data_size, x, y); - break; - - case glyph_data_outline: - m_path_adaptor.init(gl->data, gl->data_size, x, y, scale); - break; - } - } - } - - - //-------------------------------------------------------------------- - path_adaptor_type& path_adaptor() { return m_path_adaptor; } - gray8_adaptor_type& gray8_adaptor() { return m_gray8_adaptor; } - gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; } - mono_adaptor_type& mono_adaptor() { return m_mono_adaptor; } - mono_scanline_type& mono_scanline() { return m_mono_scanline; } - - //-------------------------------------------------------------------- - const glyph_cache* perv_glyph() const { return m_prev_glyph; } - const glyph_cache* last_glyph() const { return m_last_glyph; } - - //-------------------------------------------------------------------- - bool add_kerning(double* x, double* y) - { - if(m_prev_glyph && m_last_glyph) - { - return m_engine.add_kerning(m_prev_glyph->glyph_index, - m_last_glyph->glyph_index, - x, y); - } - return false; - } - - //-------------------------------------------------------------------- - void precache(unsigned from, unsigned to) - { - for(; from <= to; ++from) glyph(from); - } - - //-------------------------------------------------------------------- - void reset_cache() - { - m_fonts.font(m_engine.font_signature(), true); - m_change_stamp = m_engine.change_stamp(); - m_prev_glyph = m_last_glyph = 0; - } - - private: - //-------------------------------------------------------------------- - font_cache_manager(const self_type&); - const self_type& operator = (const self_type&); - - //-------------------------------------------------------------------- - void synchronize() - { - if(m_change_stamp != m_engine.change_stamp()) - { - m_fonts.font(m_engine.font_signature()); - m_change_stamp = m_engine.change_stamp(); - m_prev_glyph = m_last_glyph = 0; - } - } - - font_cache_pool m_fonts; - font_engine_type& m_engine; - int m_change_stamp; - double m_dx; - double m_dy; - const glyph_cache* m_prev_glyph; - const glyph_cache* m_last_glyph; - path_adaptor_type m_path_adaptor; - gray8_adaptor_type m_gray8_adaptor; - gray8_scanline_type m_gray8_scanline; - mono_adaptor_type m_mono_adaptor; - mono_scanline_type m_mono_scanline; - }; - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_gamma_functions.h corsix-th-0.62/agg/include/agg_gamma_functions.h --- corsix-th-0.30/agg/include/agg_gamma_functions.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_gamma_functions.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_GAMMA_FUNCTIONS_INCLUDED -#define AGG_GAMMA_FUNCTIONS_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - //===============================================================gamma_none - struct gamma_none - { - double operator()(double x) const { return x; } - }; - - - //==============================================================gamma_power - class gamma_power - { - public: - gamma_power() : m_gamma(1.0) {} - gamma_power(double g) : m_gamma(g) {} - - void gamma(double g) { m_gamma = g; } - double gamma() const { return m_gamma; } - - double operator() (double x) const - { - return pow(x, m_gamma); - } - - private: - double m_gamma; - }; - - - //==========================================================gamma_threshold - class gamma_threshold - { - public: - gamma_threshold() : m_threshold(0.5) {} - gamma_threshold(double t) : m_threshold(t) {} - - void threshold(double t) { m_threshold = t; } - double threshold() const { return m_threshold; } - - double operator() (double x) const - { - return (x < m_threshold) ? 0.0 : 1.0; - } - - private: - double m_threshold; - }; - - - //============================================================gamma_linear - class gamma_linear - { - public: - gamma_linear() : m_start(0.0), m_end(1.0) {} - gamma_linear(double s, double e) : m_start(s), m_end(e) {} - - void set(double s, double e) { m_start = s; m_end = e; } - void start(double s) { m_start = s; } - void end(double e) { m_end = e; } - double start() const { return m_start; } - double end() const { return m_end; } - - double operator() (double x) const - { - if(x < m_start) return 0.0; - if(x > m_end) return 1.0; - return (x - m_start) / (m_end - m_start); - } - - private: - double m_start; - double m_end; - }; - - - //==========================================================gamma_multiply - class gamma_multiply - { - public: - gamma_multiply() : m_mul(1.0) {} - gamma_multiply(double v) : m_mul(v) {} - - void value(double v) { m_mul = v; } - double value() const { return m_mul; } - - double operator() (double x) const - { - double y = x * m_mul; - if(y > 1.0) y = 1.0; - return y; - } - - private: - double m_mul; - }; - -} - -#endif - - - diff -Nru corsix-th-0.30/agg/include/agg_gamma_lut.h corsix-th-0.62/agg/include/agg_gamma_lut.h --- corsix-th-0.30/agg/include/agg_gamma_lut.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_gamma_lut.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_GAMMA_LUT_INCLUDED -#define AGG_GAMMA_LUT_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - template class gamma_lut - { - public: - typedef gamma_lut self_type; - - enum gamma_scale_e - { - gamma_shift = GammaShift, - gamma_size = 1 << gamma_shift, - gamma_mask = gamma_size - 1 - }; - - enum hi_res_scale_e - { - hi_res_shift = HiResShift, - hi_res_size = 1 << hi_res_shift, - hi_res_mask = hi_res_size - 1 - }; - - ~gamma_lut() - { - pod_allocator::deallocate(m_inv_gamma, hi_res_size); - pod_allocator::deallocate(m_dir_gamma, gamma_size); - } - - gamma_lut() : - m_gamma(1.0), - m_dir_gamma(pod_allocator::allocate(gamma_size)), - m_inv_gamma(pod_allocator::allocate(hi_res_size)) - { - unsigned i; - for(i = 0; i < gamma_size; i++) - { - m_dir_gamma[i] = HiResT(i << (hi_res_shift - gamma_shift)); - } - - for(i = 0; i < hi_res_size; i++) - { - m_inv_gamma[i] = LoResT(i >> (hi_res_shift - gamma_shift)); - } - } - - gamma_lut(double g) : - m_gamma(1.0), - m_dir_gamma(pod_allocator::allocate(gamma_size)), - m_inv_gamma(pod_allocator::allocate(hi_res_size)) - { - gamma(g); - } - - void gamma(double g) - { - m_gamma = g; - - unsigned i; - for(i = 0; i < gamma_size; i++) - { - m_dir_gamma[i] = (HiResT) - uround(pow(i / double(gamma_mask), m_gamma) * double(hi_res_mask)); - } - - double inv_g = 1.0 / g; - for(i = 0; i < hi_res_size; i++) - { - m_inv_gamma[i] = (LoResT) - uround(pow(i / double(hi_res_mask), inv_g) * double(gamma_mask)); - } - } - - double gamma() const - { - return m_gamma; - } - - HiResT dir(LoResT v) const - { - return m_dir_gamma[unsigned(v)]; - } - - LoResT inv(HiResT v) const - { - return m_inv_gamma[unsigned(v)]; - } - - private: - gamma_lut(const self_type&); - const self_type& operator = (const self_type&); - - double m_gamma; - HiResT* m_dir_gamma; - LoResT* m_inv_gamma; - }; -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_glyph_raster_bin.h corsix-th-0.62/agg/include/agg_glyph_raster_bin.h --- corsix-th-0.30/agg/include/agg_glyph_raster_bin.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_glyph_raster_bin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_GLYPH_RASTER_BIN_INCLUDED -#define AGG_GLYPH_RASTER_BIN_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - - //========================================================glyph_raster_bin - template class glyph_raster_bin - { - public: - typedef ColorT color_type; - - //-------------------------------------------------------------------- - struct glyph_rect - { - int x1,y1,x2,y2; - double dx, dy; - }; - - //-------------------------------------------------------------------- - glyph_raster_bin(const int8u* font) : - m_font(font), - m_big_endian(false) - { - int t = 1; - if(*(char*)&t == 0) m_big_endian = true; - memset(m_span, 0, sizeof(m_span)); - } - - //-------------------------------------------------------------------- - const int8u* font() const { return m_font; } - void font(const int8u* f) { m_font = f; } - - //-------------------------------------------------------------------- - double height() const { return m_font[0]; } - double base_line() const { return m_font[1]; } - - //-------------------------------------------------------------------- - template - double width(const CharT* str) const - { - unsigned start_char = m_font[2]; - unsigned num_chars = m_font[3]; - - unsigned w = 0; - while(*str) - { - unsigned glyph = *str; - const int8u* bits = m_font + 4 + num_chars * 2 + - value(m_font + 4 + (glyph - start_char) * 2); - w += *bits; - ++str; - } - return w; - } - - //-------------------------------------------------------------------- - void prepare(glyph_rect* r, double x, double y, unsigned glyph, bool flip) - { - unsigned start_char = m_font[2]; - unsigned num_chars = m_font[3]; - - m_bits = m_font + 4 + num_chars * 2 + - value(m_font + 4 + (glyph - start_char) * 2); - - m_glyph_width = *m_bits++; - m_glyph_byte_width = (m_glyph_width + 7) >> 3; - - r->x1 = int(x); - r->x2 = r->x1 + m_glyph_width - 1; - if(flip) - { - r->y1 = int(y) - m_font[0] + m_font[1]; - r->y2 = r->y1 + m_font[0] - 1; - } - else - { - r->y1 = int(y) - m_font[1] + 1; - r->y2 = r->y1 + m_font[0] - 1; - } - r->dx = m_glyph_width; - r->dy = 0; - } - - //-------------------------------------------------------------------- - const cover_type* span(unsigned i) - { - i = m_font[0] - i - 1; - const int8u* bits = m_bits + i * m_glyph_byte_width; - unsigned j; - unsigned val = *bits; - unsigned nb = 0; - for(j = 0; j < m_glyph_width; ++j) - { - m_span[j] = (cover_type)((val & 0x80) ? cover_full : cover_none); - val <<= 1; - if(++nb >= 8) - { - val = *++bits; - nb = 0; - } - } - return m_span; - } - - private: - //-------------------------------------------------------------------- - int16u value(const int8u* p) const - { - int16u v; - if(m_big_endian) - { - *(int8u*)&v = p[1]; - *((int8u*)&v + 1) = p[0]; - } - else - { - *(int8u*)&v = p[0]; - *((int8u*)&v + 1) = p[1]; - } - return v; - } - - - //-------------------------------------------------------------------- - const int8u* m_font; - bool m_big_endian; - cover_type m_span[32]; - const int8u* m_bits; - unsigned m_glyph_width; - unsigned m_glyph_byte_width; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_gradient_lut.h corsix-th-0.62/agg/include/agg_gradient_lut.h --- corsix-th-0.30/agg/include/agg_gradient_lut.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_gradient_lut.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,244 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_GRADIENT_LUT_INCLUDED -#define AGG_GRADIENT_LUT_INCLUDED - -#include "agg_array.h" -#include "agg_dda_line.h" -#include "agg_color_rgba.h" -#include "agg_color_gray.h" - -namespace agg -{ - - //======================================================color_interpolator - template struct color_interpolator - { - public: - typedef ColorT color_type; - - color_interpolator(const color_type& c1, - const color_type& c2, - unsigned len) : - m_c1(c1), - m_c2(c2), - m_len(len), - m_count(0) - {} - - void operator ++ () - { - ++m_count; - } - - color_type color() const - { - return m_c1.gradient(m_c2, double(m_count) / m_len); - } - - private: - color_type m_c1; - color_type m_c2; - unsigned m_len; - unsigned m_count; - }; - - //======================================================================== - // Fast specialization for rgba8 - template<> struct color_interpolator - { - public: - typedef rgba8 color_type; - - color_interpolator(const color_type& c1, - const color_type& c2, - unsigned len) : - r(c1.r, c2.r, len), - g(c1.g, c2.g, len), - b(c1.b, c2.b, len), - a(c1.a, c2.a, len) - {} - - void operator ++ () - { - ++r; ++g; ++b; ++a; - } - - color_type color() const - { - return color_type(r.y(), g.y(), b.y(), a.y()); - } - - private: - agg::dda_line_interpolator<14> r, g, b, a; - }; - - //======================================================================== - // Fast specialization for gray8 - template<> struct color_interpolator - { - public: - typedef gray8 color_type; - - color_interpolator(const color_type& c1, - const color_type& c2, - unsigned len) : - v(c1.v, c2.v, len), - a(c1.a, c2.a, len) - {} - - void operator ++ () - { - ++v; ++a; - } - - color_type color() const - { - return color_type(v.y(), a.y()); - } - - private: - agg::dda_line_interpolator<14> v,a; - }; - - //============================================================gradient_lut - template class gradient_lut - { - public: - typedef ColorInterpolator interpolator_type; - typedef typename interpolator_type::color_type color_type; - enum { color_lut_size = ColorLutSize }; - - //-------------------------------------------------------------------- - gradient_lut() : m_color_lut(color_lut_size) {} - - // Build Gradient Lut - // First, call remove_all(), then add_color() at least twice, - // then build_lut(). Argument "offset" in add_color must be - // in range [0...1] and defines a color stop as it is described - // in SVG specification, section Gradients and Patterns. - // The simplest linear gradient is: - // gradient_lut.add_color(0.0, start_color); - // gradient_lut.add_color(1.0, end_color); - //-------------------------------------------------------------------- - void remove_all(); - void add_color(double offset, const color_type& color); - void build_lut(); - - // Size-index Interface. This class can be used directly as the - // ColorF in span_gradient. All it needs is two access methods - // size() and operator []. - //-------------------------------------------------------------------- - static unsigned size() - { - return color_lut_size; - } - const color_type& operator [] (unsigned i) const - { - return m_color_lut[i]; - } - - private: - //-------------------------------------------------------------------- - struct color_point - { - double offset; - color_type color; - - color_point() {} - color_point(double off, const color_type& c) : - offset(off), color(c) - { - if(offset < 0.0) offset = 0.0; - if(offset > 1.0) offset = 1.0; - } - }; - typedef agg::pod_bvector color_profile_type; - typedef agg::pod_array color_lut_type; - - static bool offset_less(const color_point& a, const color_point& b) - { - return a.offset < b.offset; - } - static bool offset_equal(const color_point& a, const color_point& b) - { - return a.offset == b.offset; - } - - //-------------------------------------------------------------------- - color_profile_type m_color_profile; - color_lut_type m_color_lut; - }; - - - - //------------------------------------------------------------------------ - template - void gradient_lut::remove_all() - { - m_color_profile.remove_all(); - } - - //------------------------------------------------------------------------ - template - void gradient_lut::add_color(double offset, const color_type& color) - { - m_color_profile.add(color_point(offset, color)); - } - - //------------------------------------------------------------------------ - template - void gradient_lut::build_lut() - { - quick_sort(m_color_profile, offset_less); - m_color_profile.cut_at(remove_duplicates(m_color_profile, offset_equal)); - if(m_color_profile.size() >= 2) - { - unsigned i; - unsigned start = uround(m_color_profile[0].offset * color_lut_size); - unsigned end; - color_type c = m_color_profile[0].color; - for(i = 0; i < start; i++) - { - m_color_lut[i] = c; - } - for(i = 1; i < m_color_profile.size(); i++) - { - end = uround(m_color_profile[i].offset * color_lut_size); - interpolator_type ci(m_color_profile[i-1].color, - m_color_profile[i ].color, - end - start + 1); - while(start < end) - { - m_color_lut[start] = ci.color(); - ++ci; - ++start; - } - } - c = m_color_profile.last().color; - for(; end < m_color_lut.size(); end++) - { - m_color_lut[end] = c; - } - } - } -} - - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_gsv_text.h corsix-th-0.62/agg/include/agg_gsv_text.h --- corsix-th-0.30/agg/include/agg_gsv_text.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_gsv_text.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,153 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Class gsv_text -// -//---------------------------------------------------------------------------- - -#ifndef AGG_GSV_TEXT_INCLUDED -#define AGG_GSV_TEXT_INCLUDED - -#include "agg_array.h" -#include "agg_conv_stroke.h" -#include "agg_conv_transform.h" - -namespace agg -{ - - - //---------------------------------------------------------------gsv_text - // - // See Implementation agg_gsv_text.cpp - // - class gsv_text - { - enum status - { - initial, - next_char, - start_glyph, - glyph - }; - - public: - gsv_text(); - - void font(const void* font); - void flip(bool flip_y) { m_flip = flip_y; } - void load_font(const char* file); - void size(double height, double width=0.0); - void space(double space); - void line_space(double line_space); - void start_point(double x, double y); - void text(const char* text); - - double text_width(); - - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - // not supposed to be copied - gsv_text(const gsv_text&); - const gsv_text& operator = (const gsv_text&); - - int16u value(const int8u* p) const - { - int16u v; - if(m_big_endian) - { - *(int8u*)&v = p[1]; - *((int8u*)&v + 1) = p[0]; - } - else - { - *(int8u*)&v = p[0]; - *((int8u*)&v + 1) = p[1]; - } - return v; - } - - private: - double m_x; - double m_y; - double m_start_x; - double m_width; - double m_height; - double m_space; - double m_line_space; - char m_chr[2]; - char* m_text; - pod_array m_text_buf; - char* m_cur_chr; - const void* m_font; - pod_array m_loaded_font; - status m_status; - bool m_big_endian; - bool m_flip; - int8u* m_indices; - int8* m_glyphs; - int8* m_bglyph; - int8* m_eglyph; - double m_w; - double m_h; - }; - - - - - //--------------------------------------------------------gsv_text_outline - template class gsv_text_outline - { - public: - gsv_text_outline(gsv_text& text, const Transformer& trans) : - m_polyline(text), - m_trans(m_polyline, trans) - { - } - - void width(double w) - { - m_polyline.width(w); - } - - void transformer(const Transformer* trans) - { - m_trans->transformer(trans); - } - - void rewind(unsigned path_id) - { - m_trans.rewind(path_id); - m_polyline.line_join(round_join); - m_polyline.line_cap(round_cap); - } - - unsigned vertex(double* x, double* y) - { - return m_trans.vertex(x, y); - } - - private: - conv_stroke m_polyline; - conv_transform, Transformer> m_trans; - }; - - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_image_accessors.h corsix-th-0.62/agg/include/agg_image_accessors.h --- corsix-th-0.30/agg/include/agg_image_accessors.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_image_accessors.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,481 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_IMAGE_ACCESSORS_INCLUDED -#define AGG_IMAGE_ACCESSORS_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //-----------------------------------------------------image_accessor_clip - template class image_accessor_clip - { - public: - typedef PixFmt pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::order_type order_type; - typedef typename pixfmt_type::value_type value_type; - enum pix_width_e { pix_width = pixfmt_type::pix_width }; - - image_accessor_clip() {} - explicit image_accessor_clip(const pixfmt_type& pixf, - const color_type& bk) : - m_pixf(&pixf) - { - pixfmt_type::make_pix(m_bk_buf, bk); - } - - void attach(const pixfmt_type& pixf) - { - m_pixf = &pixf; - } - - void background_color(const color_type& bk) - { - pixfmt_type::make_pix(m_bk_buf, bk); - } - - private: - AGG_INLINE const int8u* pixel() const - { - if(m_y >= 0 && m_y < (int)m_pixf->height() && - m_x >= 0 && m_x < (int)m_pixf->width()) - { - return m_pixf->pix_ptr(m_x, m_y); - } - return m_bk_buf; - } - - public: - AGG_INLINE const int8u* span(int x, int y, unsigned len) - { - m_x = m_x0 = x; - m_y = y; - if(y >= 0 && y < (int)m_pixf->height() && - x >= 0 && x+(int)len <= (int)m_pixf->width()) - { - return m_pix_ptr = m_pixf->pix_ptr(x, y); - } - m_pix_ptr = 0; - return pixel(); - } - - AGG_INLINE const int8u* next_x() - { - if(m_pix_ptr) return m_pix_ptr += pix_width; - ++m_x; - return pixel(); - } - - AGG_INLINE const int8u* next_y() - { - ++m_y; - m_x = m_x0; - if(m_pix_ptr && - m_y >= 0 && m_y < (int)m_pixf->height()) - { - return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y); - } - m_pix_ptr = 0; - return pixel(); - } - - private: - const pixfmt_type* m_pixf; - int8u m_bk_buf[4]; - int m_x, m_x0, m_y; - const int8u* m_pix_ptr; - }; - - - - - //--------------------------------------------------image_accessor_no_clip - template class image_accessor_no_clip - { - public: - typedef PixFmt pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::order_type order_type; - typedef typename pixfmt_type::value_type value_type; - enum pix_width_e { pix_width = pixfmt_type::pix_width }; - - image_accessor_no_clip() {} - explicit image_accessor_no_clip(const pixfmt_type& pixf) : - m_pixf(&pixf) - {} - - void attach(const pixfmt_type& pixf) - { - m_pixf = &pixf; - } - - AGG_INLINE const int8u* span(int x, int y, unsigned) - { - m_x = x; - m_y = y; - return m_pix_ptr = m_pixf->pix_ptr(x, y); - } - - AGG_INLINE const int8u* next_x() - { - return m_pix_ptr += pix_width; - } - - AGG_INLINE const int8u* next_y() - { - ++m_y; - return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y); - } - - private: - const pixfmt_type* m_pixf; - int m_x, m_y; - const int8u* m_pix_ptr; - }; - - - - - //----------------------------------------------------image_accessor_clone - template class image_accessor_clone - { - public: - typedef PixFmt pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::order_type order_type; - typedef typename pixfmt_type::value_type value_type; - enum pix_width_e { pix_width = pixfmt_type::pix_width }; - - image_accessor_clone() {} - explicit image_accessor_clone(const pixfmt_type& pixf) : - m_pixf(&pixf) - {} - - void attach(const pixfmt_type& pixf) - { - m_pixf = &pixf; - } - - private: - AGG_INLINE const int8u* pixel() const - { - register int x = m_x; - register int y = m_y; - if(x < 0) x = 0; - if(y < 0) y = 0; - if(x >= (int)m_pixf->width()) x = m_pixf->width() - 1; - if(y >= (int)m_pixf->height()) y = m_pixf->height() - 1; - return m_pixf->pix_ptr(x, y); - } - - public: - AGG_INLINE const int8u* span(int x, int y, unsigned len) - { - m_x = m_x0 = x; - m_y = y; - if(y >= 0 && y < (int)m_pixf->height() && - x >= 0 && x+len <= (int)m_pixf->width()) - { - return m_pix_ptr = m_pixf->pix_ptr(x, y); - } - m_pix_ptr = 0; - return pixel(); - } - - AGG_INLINE const int8u* next_x() - { - if(m_pix_ptr) return m_pix_ptr += pix_width; - ++m_x; - return pixel(); - } - - AGG_INLINE const int8u* next_y() - { - ++m_y; - m_x = m_x0; - if(m_pix_ptr && - m_y >= 0 && m_y < (int)m_pixf->height()) - { - return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y); - } - m_pix_ptr = 0; - return pixel(); - } - - private: - const pixfmt_type* m_pixf; - int m_x, m_x0, m_y; - const int8u* m_pix_ptr; - }; - - - - - - //-----------------------------------------------------image_accessor_wrap - template class image_accessor_wrap - { - public: - typedef PixFmt pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::order_type order_type; - typedef typename pixfmt_type::value_type value_type; - enum pix_width_e { pix_width = pixfmt_type::pix_width }; - - image_accessor_wrap() {} - explicit image_accessor_wrap(const pixfmt_type& pixf) : - m_pixf(&pixf), - m_wrap_x(pixf.width()), - m_wrap_y(pixf.height()) - {} - - void attach(const pixfmt_type& pixf) - { - m_pixf = &pixf; - } - - AGG_INLINE const int8u* span(int x, int y, unsigned) - { - m_x = x; - m_row_ptr = m_pixf->row_ptr(m_wrap_y(y)); - return m_row_ptr + m_wrap_x(x) * pix_width; - } - - AGG_INLINE const int8u* next_x() - { - int x = ++m_wrap_x; - return m_row_ptr + x * pix_width; - } - - AGG_INLINE const int8u* next_y() - { - m_row_ptr = m_pixf->row_ptr(++m_wrap_y); - return m_row_ptr + m_wrap_x(m_x) * pix_width; - } - - private: - const pixfmt_type* m_pixf; - const int8u* m_row_ptr; - int m_x; - WrapX m_wrap_x; - WrapY m_wrap_y; - }; - - - - - //--------------------------------------------------------wrap_mode_repeat - class wrap_mode_repeat - { - public: - wrap_mode_repeat() {} - wrap_mode_repeat(unsigned size) : - m_size(size), - m_add(size * (0x3FFFFFFF / size)), - m_value(0) - {} - - AGG_INLINE unsigned operator() (int v) - { - return m_value = (unsigned(v) + m_add) % m_size; - } - - AGG_INLINE unsigned operator++ () - { - ++m_value; - if(m_value >= m_size) m_value = 0; - return m_value; - } - private: - unsigned m_size; - unsigned m_add; - unsigned m_value; - }; - - - //---------------------------------------------------wrap_mode_repeat_pow2 - class wrap_mode_repeat_pow2 - { - public: - wrap_mode_repeat_pow2() {} - wrap_mode_repeat_pow2(unsigned size) : m_value(0) - { - m_mask = 1; - while(m_mask < size) m_mask = (m_mask << 1) | 1; - m_mask >>= 1; - } - AGG_INLINE unsigned operator() (int v) - { - return m_value = unsigned(v) & m_mask; - } - AGG_INLINE unsigned operator++ () - { - ++m_value; - if(m_value > m_mask) m_value = 0; - return m_value; - } - private: - unsigned m_mask; - unsigned m_value; - }; - - - //----------------------------------------------wrap_mode_repeat_auto_pow2 - class wrap_mode_repeat_auto_pow2 - { - public: - wrap_mode_repeat_auto_pow2() {} - wrap_mode_repeat_auto_pow2(unsigned size) : - m_size(size), - m_add(size * (0x3FFFFFFF / size)), - m_mask((m_size & (m_size-1)) ? 0 : m_size-1), - m_value(0) - {} - - AGG_INLINE unsigned operator() (int v) - { - if(m_mask) return m_value = unsigned(v) & m_mask; - return m_value = (unsigned(v) + m_add) % m_size; - } - AGG_INLINE unsigned operator++ () - { - ++m_value; - if(m_value >= m_size) m_value = 0; - return m_value; - } - - private: - unsigned m_size; - unsigned m_add; - unsigned m_mask; - unsigned m_value; - }; - - - //-------------------------------------------------------wrap_mode_reflect - class wrap_mode_reflect - { - public: - wrap_mode_reflect() {} - wrap_mode_reflect(unsigned size) : - m_size(size), - m_size2(size * 2), - m_add(m_size2 * (0x3FFFFFFF / m_size2)), - m_value(0) - {} - - AGG_INLINE unsigned operator() (int v) - { - m_value = (unsigned(v) + m_add) % m_size2; - if(m_value >= m_size) return m_size2 - m_value - 1; - return m_value; - } - - AGG_INLINE unsigned operator++ () - { - ++m_value; - if(m_value >= m_size2) m_value = 0; - if(m_value >= m_size) return m_size2 - m_value - 1; - return m_value; - } - private: - unsigned m_size; - unsigned m_size2; - unsigned m_add; - unsigned m_value; - }; - - - - //--------------------------------------------------wrap_mode_reflect_pow2 - class wrap_mode_reflect_pow2 - { - public: - wrap_mode_reflect_pow2() {} - wrap_mode_reflect_pow2(unsigned size) : m_value(0) - { - m_mask = 1; - m_size = 1; - while(m_mask < size) - { - m_mask = (m_mask << 1) | 1; - m_size <<= 1; - } - } - AGG_INLINE unsigned operator() (int v) - { - m_value = unsigned(v) & m_mask; - if(m_value >= m_size) return m_mask - m_value; - return m_value; - } - AGG_INLINE unsigned operator++ () - { - ++m_value; - m_value &= m_mask; - if(m_value >= m_size) return m_mask - m_value; - return m_value; - } - private: - unsigned m_size; - unsigned m_mask; - unsigned m_value; - }; - - - - //---------------------------------------------wrap_mode_reflect_auto_pow2 - class wrap_mode_reflect_auto_pow2 - { - public: - wrap_mode_reflect_auto_pow2() {} - wrap_mode_reflect_auto_pow2(unsigned size) : - m_size(size), - m_size2(size * 2), - m_add(m_size2 * (0x3FFFFFFF / m_size2)), - m_mask((m_size2 & (m_size2-1)) ? 0 : m_size2-1), - m_value(0) - {} - - AGG_INLINE unsigned operator() (int v) - { - m_value = m_mask ? unsigned(v) & m_mask : - (unsigned(v) + m_add) % m_size2; - if(m_value >= m_size) return m_size2 - m_value - 1; - return m_value; - } - AGG_INLINE unsigned operator++ () - { - ++m_value; - if(m_value >= m_size2) m_value = 0; - if(m_value >= m_size) return m_size2 - m_value - 1; - return m_value; - } - - private: - unsigned m_size; - unsigned m_size2; - unsigned m_add; - unsigned m_mask; - unsigned m_value; - }; - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_image_filters.h corsix-th-0.62/agg/include/agg_image_filters.h --- corsix-th-0.30/agg/include/agg_image_filters.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_image_filters.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,448 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Image transformation filters, -// Filtering classes (image_filter_lut, image_filter), -// Basic filter shape classes -//---------------------------------------------------------------------------- -#ifndef AGG_IMAGE_FILTERS_INCLUDED -#define AGG_IMAGE_FILTERS_INCLUDED - -#include "agg_array.h" -#include "agg_math.h" - -namespace agg -{ - - // See Implementation agg_image_filters.cpp - - enum image_filter_scale_e - { - image_filter_shift = 14, //----image_filter_shift - image_filter_scale = 1 << image_filter_shift, //----image_filter_scale - image_filter_mask = image_filter_scale - 1 //----image_filter_mask - }; - - enum image_subpixel_scale_e - { - image_subpixel_shift = 8, //----image_subpixel_shift - image_subpixel_scale = 1 << image_subpixel_shift, //----image_subpixel_scale - image_subpixel_mask = image_subpixel_scale - 1 //----image_subpixel_mask - }; - - - //-----------------------------------------------------image_filter_lut - class image_filter_lut - { - public: - template void calculate(const FilterF& filter, - bool normalization=true) - { - double r = filter.radius(); - realloc_lut(r); - unsigned i; - unsigned pivot = diameter() << (image_subpixel_shift - 1); - for(i = 0; i < pivot; i++) - { - double x = double(i) / double(image_subpixel_scale); - double y = filter.calc_weight(x); - m_weight_array[pivot + i] = - m_weight_array[pivot - i] = (int16)iround(y * image_filter_scale); - } - unsigned end = (diameter() << image_subpixel_shift) - 1; - m_weight_array[0] = m_weight_array[end]; - if(normalization) - { - normalize(); - } - } - - image_filter_lut() : m_radius(0), m_diameter(0), m_start(0) {} - - template image_filter_lut(const FilterF& filter, - bool normalization=true) - { - calculate(filter, normalization); - } - - double radius() const { return m_radius; } - unsigned diameter() const { return m_diameter; } - int start() const { return m_start; } - const int16* weight_array() const { return &m_weight_array[0]; } - void normalize(); - - private: - void realloc_lut(double radius); - image_filter_lut(const image_filter_lut&); - const image_filter_lut& operator = (const image_filter_lut&); - - double m_radius; - unsigned m_diameter; - int m_start; - pod_array m_weight_array; - }; - - - - //--------------------------------------------------------image_filter - template class image_filter : public image_filter_lut - { - public: - image_filter() - { - calculate(m_filter_function); - } - private: - FilterF m_filter_function; - }; - - - //-----------------------------------------------image_filter_bilinear - struct image_filter_bilinear - { - static double radius() { return 1.0; } - static double calc_weight(double x) - { - return 1.0 - x; - } - }; - - - //-----------------------------------------------image_filter_hanning - struct image_filter_hanning - { - static double radius() { return 1.0; } - static double calc_weight(double x) - { - return 0.5 + 0.5 * cos(pi * x); - } - }; - - - //-----------------------------------------------image_filter_hamming - struct image_filter_hamming - { - static double radius() { return 1.0; } - static double calc_weight(double x) - { - return 0.54 + 0.46 * cos(pi * x); - } - }; - - //-----------------------------------------------image_filter_hermite - struct image_filter_hermite - { - static double radius() { return 1.0; } - static double calc_weight(double x) - { - return (2.0 * x - 3.0) * x * x + 1.0; - } - }; - - //------------------------------------------------image_filter_quadric - struct image_filter_quadric - { - static double radius() { return 1.5; } - static double calc_weight(double x) - { - double t; - if(x < 0.5) return 0.75 - x * x; - if(x < 1.5) {t = x - 1.5; return 0.5 * t * t;} - return 0.0; - } - }; - - //------------------------------------------------image_filter_bicubic - class image_filter_bicubic - { - static double pow3(double x) - { - return (x <= 0.0) ? 0.0 : x * x * x; - } - - public: - static double radius() { return 2.0; } - static double calc_weight(double x) - { - return - (1.0/6.0) * - (pow3(x + 2) - 4 * pow3(x + 1) + 6 * pow3(x) - 4 * pow3(x - 1)); - } - }; - - //-------------------------------------------------image_filter_kaiser - class image_filter_kaiser - { - double a; - double i0a; - double epsilon; - - public: - image_filter_kaiser(double b = 6.33) : - a(b), epsilon(1e-12) - { - i0a = 1.0 / bessel_i0(b); - } - - static double radius() { return 1.0; } - double calc_weight(double x) const - { - return bessel_i0(a * sqrt(1. - x * x)) * i0a; - } - - private: - double bessel_i0(double x) const - { - int i; - double sum, y, t; - - sum = 1.; - y = x * x / 4.; - t = y; - - for(i = 2; t > epsilon; i++) - { - sum += t; - t *= (double)y / (i * i); - } - return sum; - } - }; - - //----------------------------------------------image_filter_catrom - struct image_filter_catrom - { - static double radius() { return 2.0; } - static double calc_weight(double x) - { - if(x < 1.0) return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0)); - if(x < 2.0) return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x))); - return 0.; - } - }; - - //---------------------------------------------image_filter_mitchell - class image_filter_mitchell - { - double p0, p2, p3; - double q0, q1, q2, q3; - - public: - image_filter_mitchell(double b = 1.0/3.0, double c = 1.0/3.0) : - p0((6.0 - 2.0 * b) / 6.0), - p2((-18.0 + 12.0 * b + 6.0 * c) / 6.0), - p3((12.0 - 9.0 * b - 6.0 * c) / 6.0), - q0((8.0 * b + 24.0 * c) / 6.0), - q1((-12.0 * b - 48.0 * c) / 6.0), - q2((6.0 * b + 30.0 * c) / 6.0), - q3((-b - 6.0 * c) / 6.0) - {} - - static double radius() { return 2.0; } - double calc_weight(double x) const - { - if(x < 1.0) return p0 + x * x * (p2 + x * p3); - if(x < 2.0) return q0 + x * (q1 + x * (q2 + x * q3)); - return 0.0; - } - }; - - - //----------------------------------------------image_filter_spline16 - struct image_filter_spline16 - { - static double radius() { return 2.0; } - static double calc_weight(double x) - { - if(x < 1.0) - { - return ((x - 9.0/5.0 ) * x - 1.0/5.0 ) * x + 1.0; - } - return ((-1.0/3.0 * (x-1) + 4.0/5.0) * (x-1) - 7.0/15.0 ) * (x-1); - } - }; - - - //---------------------------------------------image_filter_spline36 - struct image_filter_spline36 - { - static double radius() { return 3.0; } - static double calc_weight(double x) - { - if(x < 1.0) - { - return ((13.0/11.0 * x - 453.0/209.0) * x - 3.0/209.0) * x + 1.0; - } - if(x < 2.0) - { - return ((-6.0/11.0 * (x-1) + 270.0/209.0) * (x-1) - 156.0/ 209.0) * (x-1); - } - return ((1.0/11.0 * (x-2) - 45.0/209.0) * (x-2) + 26.0/209.0) * (x-2); - } - }; - - - //----------------------------------------------image_filter_gaussian - struct image_filter_gaussian - { - static double radius() { return 2.0; } - static double calc_weight(double x) - { - return exp(-2.0 * x * x) * sqrt(2.0 / pi); - } - }; - - - //------------------------------------------------image_filter_bessel - struct image_filter_bessel - { - static double radius() { return 3.2383; } - static double calc_weight(double x) - { - return (x == 0.0) ? pi / 4.0 : besj(pi * x, 1) / (2.0 * x); - } - }; - - - //-------------------------------------------------image_filter_sinc - class image_filter_sinc - { - public: - image_filter_sinc(double r) : m_radius(r < 2.0 ? 2.0 : r) {} - double radius() const { return m_radius; } - double calc_weight(double x) const - { - if(x == 0.0) return 1.0; - x *= pi; - return sin(x) / x; - } - private: - double m_radius; - }; - - - //-----------------------------------------------image_filter_lanczos - class image_filter_lanczos - { - public: - image_filter_lanczos(double r) : m_radius(r < 2.0 ? 2.0 : r) {} - double radius() const { return m_radius; } - double calc_weight(double x) const - { - if(x == 0.0) return 1.0; - if(x > m_radius) return 0.0; - x *= pi; - double xr = x / m_radius; - return (sin(x) / x) * (sin(xr) / xr); - } - private: - double m_radius; - }; - - - //----------------------------------------------image_filter_blackman - class image_filter_blackman - { - public: - image_filter_blackman(double r) : m_radius(r < 2.0 ? 2.0 : r) {} - double radius() const { return m_radius; } - double calc_weight(double x) const - { - if(x == 0.0) return 1.0; - if(x > m_radius) return 0.0; - x *= pi; - double xr = x / m_radius; - return (sin(x) / x) * (0.42 + 0.5*cos(xr) + 0.08*cos(2*xr)); - } - private: - double m_radius; - }; - - //------------------------------------------------image_filter_sinc36 - class image_filter_sinc36 : public image_filter_sinc - { public: image_filter_sinc36() : image_filter_sinc(3.0){} }; - - //------------------------------------------------image_filter_sinc64 - class image_filter_sinc64 : public image_filter_sinc - { public: image_filter_sinc64() : image_filter_sinc(4.0){} }; - - //-----------------------------------------------image_filter_sinc100 - class image_filter_sinc100 : public image_filter_sinc - { public: image_filter_sinc100() : image_filter_sinc(5.0){} }; - - //-----------------------------------------------image_filter_sinc144 - class image_filter_sinc144 : public image_filter_sinc - { public: image_filter_sinc144() : image_filter_sinc(6.0){} }; - - //-----------------------------------------------image_filter_sinc196 - class image_filter_sinc196 : public image_filter_sinc - { public: image_filter_sinc196() : image_filter_sinc(7.0){} }; - - //-----------------------------------------------image_filter_sinc256 - class image_filter_sinc256 : public image_filter_sinc - { public: image_filter_sinc256() : image_filter_sinc(8.0){} }; - - //---------------------------------------------image_filter_lanczos36 - class image_filter_lanczos36 : public image_filter_lanczos - { public: image_filter_lanczos36() : image_filter_lanczos(3.0){} }; - - //---------------------------------------------image_filter_lanczos64 - class image_filter_lanczos64 : public image_filter_lanczos - { public: image_filter_lanczos64() : image_filter_lanczos(4.0){} }; - - //--------------------------------------------image_filter_lanczos100 - class image_filter_lanczos100 : public image_filter_lanczos - { public: image_filter_lanczos100() : image_filter_lanczos(5.0){} }; - - //--------------------------------------------image_filter_lanczos144 - class image_filter_lanczos144 : public image_filter_lanczos - { public: image_filter_lanczos144() : image_filter_lanczos(6.0){} }; - - //--------------------------------------------image_filter_lanczos196 - class image_filter_lanczos196 : public image_filter_lanczos - { public: image_filter_lanczos196() : image_filter_lanczos(7.0){} }; - - //--------------------------------------------image_filter_lanczos256 - class image_filter_lanczos256 : public image_filter_lanczos - { public: image_filter_lanczos256() : image_filter_lanczos(8.0){} }; - - //--------------------------------------------image_filter_blackman36 - class image_filter_blackman36 : public image_filter_blackman - { public: image_filter_blackman36() : image_filter_blackman(3.0){} }; - - //--------------------------------------------image_filter_blackman64 - class image_filter_blackman64 : public image_filter_blackman - { public: image_filter_blackman64() : image_filter_blackman(4.0){} }; - - //-------------------------------------------image_filter_blackman100 - class image_filter_blackman100 : public image_filter_blackman - { public: image_filter_blackman100() : image_filter_blackman(5.0){} }; - - //-------------------------------------------image_filter_blackman144 - class image_filter_blackman144 : public image_filter_blackman - { public: image_filter_blackman144() : image_filter_blackman(6.0){} }; - - //-------------------------------------------image_filter_blackman196 - class image_filter_blackman196 : public image_filter_blackman - { public: image_filter_blackman196() : image_filter_blackman(7.0){} }; - - //-------------------------------------------image_filter_blackman256 - class image_filter_blackman256 : public image_filter_blackman - { public: image_filter_blackman256() : image_filter_blackman(8.0){} }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_line_aa_basics.h corsix-th-0.62/agg/include/agg_line_aa_basics.h --- corsix-th-0.30/agg/include/agg_line_aa_basics.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_line_aa_basics.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,189 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_LINE_AA_BASICS_INCLUDED -#define AGG_LINE_AA_BASICS_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - - // See Implementation agg_line_aa_basics.cpp - - //------------------------------------------------------------------------- - enum line_subpixel_scale_e - { - line_subpixel_shift = 8, //----line_subpixel_shift - line_subpixel_scale = 1 << line_subpixel_shift, //----line_subpixel_scale - line_subpixel_mask = line_subpixel_scale - 1, //----line_subpixel_mask - line_max_coord = (1 << 28) - 1, //----line_max_coord - line_max_length = 1 << (line_subpixel_shift + 10) //----line_max_length - }; - - //------------------------------------------------------------------------- - enum line_mr_subpixel_scale_e - { - line_mr_subpixel_shift = 4, //----line_mr_subpixel_shift - line_mr_subpixel_scale = 1 << line_mr_subpixel_shift, //----line_mr_subpixel_scale - line_mr_subpixel_mask = line_mr_subpixel_scale - 1 //----line_mr_subpixel_mask - }; - - //------------------------------------------------------------------line_mr - AGG_INLINE int line_mr(int x) - { - return x >> (line_subpixel_shift - line_mr_subpixel_shift); - } - - //-------------------------------------------------------------------line_hr - AGG_INLINE int line_hr(int x) - { - return x << (line_subpixel_shift - line_mr_subpixel_shift); - } - - //---------------------------------------------------------------line_dbl_hr - AGG_INLINE int line_dbl_hr(int x) - { - return x << line_subpixel_shift; - } - - //---------------------------------------------------------------line_coord - struct line_coord - { - AGG_INLINE static int conv(double x) - { - return iround(x * line_subpixel_scale); - } - }; - - //-----------------------------------------------------------line_coord_sat - struct line_coord_sat - { - AGG_INLINE static int conv(double x) - { - return saturation::iround(x * line_subpixel_scale); - } - }; - - //==========================================================line_parameters - struct line_parameters - { - //--------------------------------------------------------------------- - line_parameters() {} - line_parameters(int x1_, int y1_, int x2_, int y2_, int len_) : - x1(x1_), y1(y1_), x2(x2_), y2(y2_), - dx(abs(x2_ - x1_)), - dy(abs(y2_ - y1_)), - sx((x2_ > x1_) ? 1 : -1), - sy((y2_ > y1_) ? 1 : -1), - vertical(dy >= dx), - inc(vertical ? sy : sx), - len(len_), - octant((sy & 4) | (sx & 2) | int(vertical)) - { - } - - //--------------------------------------------------------------------- - unsigned orthogonal_quadrant() const { return s_orthogonal_quadrant[octant]; } - unsigned diagonal_quadrant() const { return s_diagonal_quadrant[octant]; } - - //--------------------------------------------------------------------- - bool same_orthogonal_quadrant(const line_parameters& lp) const - { - return s_orthogonal_quadrant[octant] == s_orthogonal_quadrant[lp.octant]; - } - - //--------------------------------------------------------------------- - bool same_diagonal_quadrant(const line_parameters& lp) const - { - return s_diagonal_quadrant[octant] == s_diagonal_quadrant[lp.octant]; - } - - //--------------------------------------------------------------------- - void divide(line_parameters& lp1, line_parameters& lp2) const - { - int xmid = (x1 + x2) >> 1; - int ymid = (y1 + y2) >> 1; - int len2 = len >> 1; - - lp1 = *this; - lp2 = *this; - - lp1.x2 = xmid; - lp1.y2 = ymid; - lp1.len = len2; - lp1.dx = abs(lp1.x2 - lp1.x1); - lp1.dy = abs(lp1.y2 - lp1.y1); - - lp2.x1 = xmid; - lp2.y1 = ymid; - lp2.len = len2; - lp2.dx = abs(lp2.x2 - lp2.x1); - lp2.dy = abs(lp2.y2 - lp2.y1); - } - - //--------------------------------------------------------------------- - int x1, y1, x2, y2, dx, dy, sx, sy; - bool vertical; - int inc; - int len; - int octant; - - //--------------------------------------------------------------------- - static const int8u s_orthogonal_quadrant[8]; - static const int8u s_diagonal_quadrant[8]; - }; - - - - // See Implementation agg_line_aa_basics.cpp - - //----------------------------------------------------------------bisectrix - void bisectrix(const line_parameters& l1, - const line_parameters& l2, - int* x, int* y); - - - //-------------------------------------------fix_degenerate_bisectrix_start - void inline fix_degenerate_bisectrix_start(const line_parameters& lp, - int* x, int* y) - { - int d = iround((double(*x - lp.x2) * double(lp.y2 - lp.y1) - - double(*y - lp.y2) * double(lp.x2 - lp.x1)) / lp.len); - if(d < line_subpixel_scale/2) - { - *x = lp.x1 + (lp.y2 - lp.y1); - *y = lp.y1 - (lp.x2 - lp.x1); - } - } - - - //---------------------------------------------fix_degenerate_bisectrix_end - void inline fix_degenerate_bisectrix_end(const line_parameters& lp, - int* x, int* y) - { - int d = iround((double(*x - lp.x2) * double(lp.y2 - lp.y1) - - double(*y - lp.y2) * double(lp.x2 - lp.x1)) / lp.len); - if(d < line_subpixel_scale/2) - { - *x = lp.x2 + (lp.y2 - lp.y1); - *y = lp.y2 - (lp.x2 - lp.x1); - } - } - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_math.h corsix-th-0.62/agg/include/agg_math.h --- corsix-th-0.30/agg/include/agg_math.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_math.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,437 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// Bessel function (besj) was adapted for use in AGG library by Andy Wilk -// Contact: castor.vulgaris@gmail.com -//---------------------------------------------------------------------------- - -#ifndef AGG_MATH_INCLUDED -#define AGG_MATH_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - - //------------------------------------------------------vertex_dist_epsilon - // Coinciding points maximal distance (Epsilon) - const double vertex_dist_epsilon = 1e-14; - - //-----------------------------------------------------intersection_epsilon - // See calc_intersection - const double intersection_epsilon = 1.0e-30; - - //------------------------------------------------------------cross_product - AGG_INLINE double cross_product(double x1, double y1, - double x2, double y2, - double x, double y) - { - return (x - x2) * (y2 - y1) - (y - y2) * (x2 - x1); - } - - //--------------------------------------------------------point_in_triangle - AGG_INLINE bool point_in_triangle(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x, double y) - { - bool cp1 = cross_product(x1, y1, x2, y2, x, y) < 0.0; - bool cp2 = cross_product(x2, y2, x3, y3, x, y) < 0.0; - bool cp3 = cross_product(x3, y3, x1, y1, x, y) < 0.0; - return cp1 == cp2 && cp2 == cp3 && cp3 == cp1; - } - - //-----------------------------------------------------------calc_distance - AGG_INLINE double calc_distance(double x1, double y1, double x2, double y2) - { - double dx = x2-x1; - double dy = y2-y1; - return sqrt(dx * dx + dy * dy); - } - - //--------------------------------------------------------calc_sq_distance - AGG_INLINE double calc_sq_distance(double x1, double y1, double x2, double y2) - { - double dx = x2-x1; - double dy = y2-y1; - return dx * dx + dy * dy; - } - - //------------------------------------------------calc_line_point_distance - AGG_INLINE double calc_line_point_distance(double x1, double y1, - double x2, double y2, - double x, double y) - { - double dx = x2-x1; - double dy = y2-y1; - double d = sqrt(dx * dx + dy * dy); - if(d < vertex_dist_epsilon) - { - return calc_distance(x1, y1, x, y); - } - return ((x - x2) * dy - (y - y2) * dx) / d; - } - - //-------------------------------------------------------calc_line_point_u - AGG_INLINE double calc_segment_point_u(double x1, double y1, - double x2, double y2, - double x, double y) - { - double dx = x2 - x1; - double dy = y2 - y1; - - if(dx == 0 && dy == 0) - { - return 0; - } - - double pdx = x - x1; - double pdy = y - y1; - - return (pdx * dx + pdy * dy) / (dx * dx + dy * dy); - } - - //---------------------------------------------calc_line_point_sq_distance - AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, - double x2, double y2, - double x, double y, - double u) - { - if(u <= 0) - { - return calc_sq_distance(x, y, x1, y1); - } - else - if(u >= 1) - { - return calc_sq_distance(x, y, x2, y2); - } - return calc_sq_distance(x, y, x1 + u * (x2 - x1), y1 + u * (y2 - y1)); - } - - //---------------------------------------------calc_line_point_sq_distance - AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, - double x2, double y2, - double x, double y) - { - return - calc_segment_point_sq_distance( - x1, y1, x2, y2, x, y, - calc_segment_point_u(x1, y1, x2, y2, x, y)); - } - - //-------------------------------------------------------calc_intersection - AGG_INLINE bool calc_intersection(double ax, double ay, double bx, double by, - double cx, double cy, double dx, double dy, - double* x, double* y) - { - double num = (ay-cy) * (dx-cx) - (ax-cx) * (dy-cy); - double den = (bx-ax) * (dy-cy) - (by-ay) * (dx-cx); - if(fabs(den) < intersection_epsilon) return false; - double r = num / den; - *x = ax + r * (bx-ax); - *y = ay + r * (by-ay); - return true; - } - - //-----------------------------------------------------intersection_exists - AGG_INLINE bool intersection_exists(double x1, double y1, double x2, double y2, - double x3, double y3, double x4, double y4) - { - // It's less expensive but you can't control the - // boundary conditions: Less or LessEqual - double dx1 = x2 - x1; - double dy1 = y2 - y1; - double dx2 = x4 - x3; - double dy2 = y4 - y3; - return ((x3 - x2) * dy1 - (y3 - y2) * dx1 < 0.0) != - ((x4 - x2) * dy1 - (y4 - y2) * dx1 < 0.0) && - ((x1 - x4) * dy2 - (y1 - y4) * dx2 < 0.0) != - ((x2 - x4) * dy2 - (y2 - y4) * dx2 < 0.0); - - // It's is more expensive but more flexible - // in terms of boundary conditions. - //-------------------- - //double den = (x2-x1) * (y4-y3) - (y2-y1) * (x4-x3); - //if(fabs(den) < intersection_epsilon) return false; - //double nom1 = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3); - //double nom2 = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3); - //double ua = nom1 / den; - //double ub = nom2 / den; - //return ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0; - } - - //--------------------------------------------------------calc_orthogonal - AGG_INLINE void calc_orthogonal(double thickness, - double x1, double y1, - double x2, double y2, - double* x, double* y) - { - double dx = x2 - x1; - double dy = y2 - y1; - double d = sqrt(dx*dx + dy*dy); - *x = thickness * dy / d; - *y = -thickness * dx / d; - } - - //--------------------------------------------------------dilate_triangle - AGG_INLINE void dilate_triangle(double x1, double y1, - double x2, double y2, - double x3, double y3, - double *x, double* y, - double d) - { - double dx1=0.0; - double dy1=0.0; - double dx2=0.0; - double dy2=0.0; - double dx3=0.0; - double dy3=0.0; - double loc = cross_product(x1, y1, x2, y2, x3, y3); - if(fabs(loc) > intersection_epsilon) - { - if(cross_product(x1, y1, x2, y2, x3, y3) > 0.0) - { - d = -d; - } - calc_orthogonal(d, x1, y1, x2, y2, &dx1, &dy1); - calc_orthogonal(d, x2, y2, x3, y3, &dx2, &dy2); - calc_orthogonal(d, x3, y3, x1, y1, &dx3, &dy3); - } - *x++ = x1 + dx1; *y++ = y1 + dy1; - *x++ = x2 + dx1; *y++ = y2 + dy1; - *x++ = x2 + dx2; *y++ = y2 + dy2; - *x++ = x3 + dx2; *y++ = y3 + dy2; - *x++ = x3 + dx3; *y++ = y3 + dy3; - *x++ = x1 + dx3; *y++ = y1 + dy3; - } - - //------------------------------------------------------calc_triangle_area - AGG_INLINE double calc_triangle_area(double x1, double y1, - double x2, double y2, - double x3, double y3) - { - return (x1*y2 - x2*y1 + x2*y3 - x3*y2 + x3*y1 - x1*y3) * 0.5; - } - - //-------------------------------------------------------calc_polygon_area - template double calc_polygon_area(const Storage& st) - { - unsigned i; - double sum = 0.0; - double x = st[0].x; - double y = st[0].y; - double xs = x; - double ys = y; - - for(i = 1; i < st.size(); i++) - { - const typename Storage::value_type& v = st[i]; - sum += x * v.y - y * v.x; - x = v.x; - y = v.y; - } - return (sum + x * ys - y * xs) * 0.5; - } - - //------------------------------------------------------------------------ - // Tables for fast sqrt - extern int16u g_sqrt_table[1024]; - extern int8 g_elder_bit_table[256]; - - - //---------------------------------------------------------------fast_sqrt - //Fast integer Sqrt - really fast: no cycles, divisions or multiplications - #if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable : 4035) //Disable warning "no return value" - #endif - AGG_INLINE unsigned fast_sqrt(unsigned val) - { - #if defined(_M_IX86) && defined(_MSC_VER) && !defined(AGG_NO_ASM) - //For Ix86 family processors this assembler code is used. - //The key command here is bsr - determination the number of the most - //significant bit of the value. For other processors - //(and maybe compilers) the pure C "#else" section is used. - __asm - { - mov ebx, val - mov edx, 11 - bsr ecx, ebx - sub ecx, 9 - jle less_than_9_bits - shr ecx, 1 - adc ecx, 0 - sub edx, ecx - shl ecx, 1 - shr ebx, cl - less_than_9_bits: - xor eax, eax - mov ax, g_sqrt_table[ebx*2] - mov ecx, edx - shr eax, cl - } - #else - - //This code is actually pure C and portable to most - //arcitectures including 64bit ones. - unsigned t = val; - int bit=0; - unsigned shift = 11; - - //The following piece of code is just an emulation of the - //Ix86 assembler command "bsr" (see above). However on old - //Intels (like Intel MMX 233MHz) this code is about twice - //faster (sic!) then just one "bsr". On PIII and PIV the - //bsr is optimized quite well. - bit = t >> 24; - if(bit) - { - bit = g_elder_bit_table[bit] + 24; - } - else - { - bit = (t >> 16) & 0xFF; - if(bit) - { - bit = g_elder_bit_table[bit] + 16; - } - else - { - bit = (t >> 8) & 0xFF; - if(bit) - { - bit = g_elder_bit_table[bit] + 8; - } - else - { - bit = g_elder_bit_table[t]; - } - } - } - - //This code calculates the sqrt. - bit -= 9; - if(bit > 0) - { - bit = (bit >> 1) + (bit & 1); - shift -= bit; - val >>= (bit << 1); - } - return g_sqrt_table[val] >> shift; - #endif - } - #if defined(_MSC_VER) - #pragma warning(pop) - #endif - - - - - //--------------------------------------------------------------------besj - // Function BESJ calculates Bessel function of first kind of order n - // Arguments: - // n - an integer (>=0), the order - // x - value at which the Bessel function is required - //-------------------- - // C++ Mathematical Library - // Convereted from equivalent FORTRAN library - // Converetd by Gareth Walker for use by course 392 computational project - // All functions tested and yield the same results as the corresponding - // FORTRAN versions. - // - // If you have any problems using these functions please report them to - // M.Muldoon@UMIST.ac.uk - // - // Documentation available on the web - // http://www.ma.umist.ac.uk/mrm/Teaching/392/libs/392.html - // Version 1.0 8/98 - // 29 October, 1999 - //-------------------- - // Adapted for use in AGG library by Andy Wilk (castor.vulgaris@gmail.com) - //------------------------------------------------------------------------ - inline double besj(double x, int n) - { - if(n < 0) - { - return 0; - } - double d = 1E-6; - double b = 0; - if(fabs(x) <= d) - { - if(n != 0) return 0; - return 1; - } - double b1 = 0; // b1 is the value from the previous iteration - // Set up a starting order for recurrence - int m1 = (int)fabs(x) + 6; - if(fabs(x) > 5) - { - m1 = (int)(fabs(1.4 * x + 60 / x)); - } - int m2 = (int)(n + 2 + fabs(x) / 4); - if (m1 > m2) - { - m2 = m1; - } - - // Apply recurrence down from curent max order - for(;;) - { - double c3 = 0; - double c2 = 1E-30; - double c4 = 0; - int m8 = 1; - if (m2 / 2 * 2 == m2) - { - m8 = -1; - } - int imax = m2 - 2; - for (int i = 1; i <= imax; i++) - { - double c6 = 2 * (m2 - i) * c2 / x - c3; - c3 = c2; - c2 = c6; - if(m2 - i - 1 == n) - { - b = c6; - } - m8 = -1 * m8; - if (m8 > 0) - { - c4 = c4 + 2 * c6; - } - } - double c6 = 2 * c2 / x - c3; - if(n == 0) - { - b = c6; - } - c4 += c6; - b /= c4; - if(fabs(b - b1) < d) - { - return b; - } - b1 = b; - m2 += 3; - } - } - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_math_stroke.h corsix-th-0.62/agg/include/agg_math_stroke.h --- corsix-th-0.30/agg/include/agg_math_stroke.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_math_stroke.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,526 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Stroke math -// -//---------------------------------------------------------------------------- - -#ifndef AGG_STROKE_MATH_INCLUDED -#define AGG_STROKE_MATH_INCLUDED - -#include "agg_math.h" -#include "agg_vertex_sequence.h" - -namespace agg -{ - //-------------------------------------------------------------line_cap_e - enum line_cap_e - { - butt_cap, - square_cap, - round_cap - }; - - //------------------------------------------------------------line_join_e - enum line_join_e - { - miter_join = 0, - miter_join_revert = 1, - round_join = 2, - bevel_join = 3, - miter_join_round = 4 - }; - - - //-----------------------------------------------------------inner_join_e - enum inner_join_e - { - inner_bevel, - inner_miter, - inner_jag, - inner_round - }; - - //------------------------------------------------------------math_stroke - template class math_stroke - { - public: - typedef typename VertexConsumer::value_type coord_type; - - math_stroke(); - - void line_cap(line_cap_e lc) { m_line_cap = lc; } - void line_join(line_join_e lj) { m_line_join = lj; } - void inner_join(inner_join_e ij) { m_inner_join = ij; } - - line_cap_e line_cap() const { return m_line_cap; } - line_join_e line_join() const { return m_line_join; } - inner_join_e inner_join() const { return m_inner_join; } - - void width(double w); - void miter_limit(double ml) { m_miter_limit = ml; } - void miter_limit_theta(double t); - void inner_miter_limit(double ml) { m_inner_miter_limit = ml; } - void approximation_scale(double as) { m_approx_scale = as; } - - double width() const { return m_width * 2.0; } - double miter_limit() const { return m_miter_limit; } - double inner_miter_limit() const { return m_inner_miter_limit; } - double approximation_scale() const { return m_approx_scale; } - - void calc_cap(VertexConsumer& vc, - const vertex_dist& v0, - const vertex_dist& v1, - double len); - - void calc_join(VertexConsumer& vc, - const vertex_dist& v0, - const vertex_dist& v1, - const vertex_dist& v2, - double len1, - double len2); - - private: - AGG_INLINE void add_vertex(VertexConsumer& vc, double x, double y) - { - vc.add(coord_type(x, y)); - } - - void calc_arc(VertexConsumer& vc, - double x, double y, - double dx1, double dy1, - double dx2, double dy2); - - void calc_miter(VertexConsumer& vc, - const vertex_dist& v0, - const vertex_dist& v1, - const vertex_dist& v2, - double dx1, double dy1, - double dx2, double dy2, - line_join_e lj, - double mlimit, - double dbevel); - - double m_width; - double m_width_abs; - double m_width_eps; - int m_width_sign; - double m_miter_limit; - double m_inner_miter_limit; - double m_approx_scale; - line_cap_e m_line_cap; - line_join_e m_line_join; - inner_join_e m_inner_join; - }; - - //----------------------------------------------------------------------- - template math_stroke::math_stroke() : - m_width(0.5), - m_width_abs(0.5), - m_width_eps(0.5/1024.0), - m_width_sign(1), - m_miter_limit(4.0), - m_inner_miter_limit(1.01), - m_approx_scale(1.0), - m_line_cap(butt_cap), - m_line_join(miter_join), - m_inner_join(inner_miter) - { - } - - //----------------------------------------------------------------------- - template void math_stroke::width(double w) - { - m_width = w * 0.5; - if(m_width < 0) - { - m_width_abs = -m_width; - m_width_sign = -1; - } - else - { - m_width_abs = m_width; - m_width_sign = 1; - } - m_width_eps = m_width / 1024.0; - } - - //----------------------------------------------------------------------- - template void math_stroke::miter_limit_theta(double t) - { - m_miter_limit = 1.0 / sin(t * 0.5) ; - } - - //----------------------------------------------------------------------- - template - void math_stroke::calc_arc(VC& vc, - double x, double y, - double dx1, double dy1, - double dx2, double dy2) - { - double a1 = atan2(dy1 * m_width_sign, dx1 * m_width_sign); - double a2 = atan2(dy2 * m_width_sign, dx2 * m_width_sign); - double da = a1 - a2; - int i, n; - - da = acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2; - - add_vertex(vc, x + dx1, y + dy1); - if(m_width_sign > 0) - { - if(a1 > a2) a2 += 2 * pi; - n = int((a2 - a1) / da); - da = (a2 - a1) / (n + 1); - a1 += da; - for(i = 0; i < n; i++) - { - add_vertex(vc, x + cos(a1) * m_width, y + sin(a1) * m_width); - a1 += da; - } - } - else - { - if(a1 < a2) a2 -= 2 * pi; - n = int((a1 - a2) / da); - da = (a1 - a2) / (n + 1); - a1 -= da; - for(i = 0; i < n; i++) - { - add_vertex(vc, x + cos(a1) * m_width, y + sin(a1) * m_width); - a1 -= da; - } - } - add_vertex(vc, x + dx2, y + dy2); - } - - //----------------------------------------------------------------------- - template - void math_stroke::calc_miter(VC& vc, - const vertex_dist& v0, - const vertex_dist& v1, - const vertex_dist& v2, - double dx1, double dy1, - double dx2, double dy2, - line_join_e lj, - double mlimit, - double dbevel) - { - double xi = v1.x; - double yi = v1.y; - double di = 1; - double lim = m_width_abs * mlimit; - bool miter_limit_exceeded = true; // Assume the worst - bool intersection_failed = true; // Assume the worst - - if(calc_intersection(v0.x + dx1, v0.y - dy1, - v1.x + dx1, v1.y - dy1, - v1.x + dx2, v1.y - dy2, - v2.x + dx2, v2.y - dy2, - &xi, &yi)) - { - // Calculation of the intersection succeeded - //--------------------- - di = calc_distance(v1.x, v1.y, xi, yi); - if(di <= lim) - { - // Inside the miter limit - //--------------------- - add_vertex(vc, xi, yi); - miter_limit_exceeded = false; - } - intersection_failed = false; - } - else - { - // Calculation of the intersection failed, most probably - // the three points lie one straight line. - // First check if v0 and v2 lie on the opposite sides of vector: - // (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular - // to the line determined by vertices v0 and v1. - // This condition determines whether the next line segments continues - // the previous one or goes back. - //---------------- - double x2 = v1.x + dx1; - double y2 = v1.y - dy1; - if((cross_product(v0.x, v0.y, v1.x, v1.y, x2, y2) < 0.0) == - (cross_product(v1.x, v1.y, v2.x, v2.y, x2, y2) < 0.0)) - { - // This case means that the next segment continues - // the previous one (straight line) - //----------------- - add_vertex(vc, v1.x + dx1, v1.y - dy1); - miter_limit_exceeded = false; - } - } - - if(miter_limit_exceeded) - { - // Miter limit exceeded - //------------------------ - switch(lj) - { - case miter_join_revert: - // For the compatibility with SVG, PDF, etc, - // we use a simple bevel join instead of - // "smart" bevel - //------------------- - add_vertex(vc, v1.x + dx1, v1.y - dy1); - add_vertex(vc, v1.x + dx2, v1.y - dy2); - break; - - case miter_join_round: - calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2); - break; - - default: - // If no miter-revert, calculate new dx1, dy1, dx2, dy2 - //---------------- - if(intersection_failed) - { - mlimit *= m_width_sign; - add_vertex(vc, v1.x + dx1 + dy1 * mlimit, - v1.y - dy1 + dx1 * mlimit); - add_vertex(vc, v1.x + dx2 - dy2 * mlimit, - v1.y - dy2 - dx2 * mlimit); - } - else - { - double x1 = v1.x + dx1; - double y1 = v1.y - dy1; - double x2 = v1.x + dx2; - double y2 = v1.y - dy2; - di = (lim - dbevel) / (di - dbevel); - add_vertex(vc, x1 + (xi - x1) * di, - y1 + (yi - y1) * di); - add_vertex(vc, x2 + (xi - x2) * di, - y2 + (yi - y2) * di); - } - break; - } - } - } - - //--------------------------------------------------------stroke_calc_cap - template - void math_stroke::calc_cap(VC& vc, - const vertex_dist& v0, - const vertex_dist& v1, - double len) - { - vc.remove_all(); - - double dx1 = (v1.y - v0.y) / len; - double dy1 = (v1.x - v0.x) / len; - double dx2 = 0; - double dy2 = 0; - - dx1 *= m_width; - dy1 *= m_width; - - if(m_line_cap != round_cap) - { - if(m_line_cap == square_cap) - { - dx2 = dy1 * m_width_sign; - dy2 = dx1 * m_width_sign; - } - add_vertex(vc, v0.x - dx1 - dx2, v0.y + dy1 - dy2); - add_vertex(vc, v0.x + dx1 - dx2, v0.y - dy1 - dy2); - } - else - { - double da = acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2; - double a1; - int i; - int n = int(pi / da); - - da = pi / (n + 1); - add_vertex(vc, v0.x - dx1, v0.y + dy1); - if(m_width_sign > 0) - { - a1 = atan2(dy1, -dx1); - a1 += da; - for(i = 0; i < n; i++) - { - add_vertex(vc, v0.x + cos(a1) * m_width, - v0.y + sin(a1) * m_width); - a1 += da; - } - } - else - { - a1 = atan2(-dy1, dx1); - a1 -= da; - for(i = 0; i < n; i++) - { - add_vertex(vc, v0.x + cos(a1) * m_width, - v0.y + sin(a1) * m_width); - a1 -= da; - } - } - add_vertex(vc, v0.x + dx1, v0.y - dy1); - } - } - - //----------------------------------------------------------------------- - template - void math_stroke::calc_join(VC& vc, - const vertex_dist& v0, - const vertex_dist& v1, - const vertex_dist& v2, - double len1, - double len2) - { - double dx1 = m_width * (v1.y - v0.y) / len1; - double dy1 = m_width * (v1.x - v0.x) / len1; - double dx2 = m_width * (v2.y - v1.y) / len2; - double dy2 = m_width * (v2.x - v1.x) / len2; - - vc.remove_all(); - - double cp = cross_product(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y); - if(cp != 0 && (cp > 0) == (m_width > 0)) - { - // Inner join - //--------------- - double limit = ((len1 < len2) ? len1 : len2) / m_width_abs; - if(limit < m_inner_miter_limit) - { - limit = m_inner_miter_limit; - } - - switch(m_inner_join) - { - default: // inner_bevel - add_vertex(vc, v1.x + dx1, v1.y - dy1); - add_vertex(vc, v1.x + dx2, v1.y - dy2); - break; - - case inner_miter: - calc_miter(vc, - v0, v1, v2, dx1, dy1, dx2, dy2, - miter_join_revert, - limit, 0); - break; - - case inner_jag: - case inner_round: - cp = (dx1-dx2) * (dx1-dx2) + (dy1-dy2) * (dy1-dy2); - if(cp < len1 * len1 && cp < len2 * len2) - { - calc_miter(vc, - v0, v1, v2, dx1, dy1, dx2, dy2, - miter_join_revert, - limit, 0); - } - else - { - if(m_inner_join == inner_jag) - { - add_vertex(vc, v1.x + dx1, v1.y - dy1); - add_vertex(vc, v1.x, v1.y ); - add_vertex(vc, v1.x + dx2, v1.y - dy2); - } - else - { - add_vertex(vc, v1.x + dx1, v1.y - dy1); - add_vertex(vc, v1.x, v1.y ); - calc_arc(vc, v1.x, v1.y, dx2, -dy2, dx1, -dy1); - add_vertex(vc, v1.x, v1.y ); - add_vertex(vc, v1.x + dx2, v1.y - dy2); - } - } - break; - } - } - else - { - // Outer join - //--------------- - - // Calculate the distance between v1 and - // the central point of the bevel line segment - //--------------- - double dx = (dx1 + dx2) / 2; - double dy = (dy1 + dy2) / 2; - double dbevel = sqrt(dx * dx + dy * dy); - - if(m_line_join == round_join || m_line_join == bevel_join) - { - // This is an optimization that reduces the number of points - // in cases of almost collinear segments. If there's no - // visible difference between bevel and miter joins we'd rather - // use miter join because it adds only one point instead of two. - // - // Here we calculate the middle point between the bevel points - // and then, the distance between v1 and this middle point. - // At outer joins this distance always less than stroke width, - // because it's actually the height of an isosceles triangle of - // v1 and its two bevel points. If the difference between this - // width and this value is small (no visible bevel) we can - // add just one point. - // - // The constant in the expression makes the result approximately - // the same as in round joins and caps. You can safely comment - // out this entire "if". - //------------------- - if(m_approx_scale * (m_width_abs - dbevel) < m_width_eps) - { - if(calc_intersection(v0.x + dx1, v0.y - dy1, - v1.x + dx1, v1.y - dy1, - v1.x + dx2, v1.y - dy2, - v2.x + dx2, v2.y - dy2, - &dx, &dy)) - { - add_vertex(vc, dx, dy); - } - else - { - add_vertex(vc, v1.x + dx1, v1.y - dy1); - } - return; - } - } - - switch(m_line_join) - { - case miter_join: - case miter_join_revert: - case miter_join_round: - calc_miter(vc, - v0, v1, v2, dx1, dy1, dx2, dy2, - m_line_join, - m_miter_limit, - dbevel); - break; - - case round_join: - calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2); - break; - - default: // Bevel join - add_vertex(vc, v1.x + dx1, v1.y - dy1); - add_vertex(vc, v1.x + dx2, v1.y - dy2); - break; - } - } - } - - - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_path_length.h corsix-th-0.62/agg/include/agg_path_length.h --- corsix-th-0.30/agg/include/agg_path_length.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_path_length.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_PATH_LENGTH_INCLUDED -#define AGG_PATH_LENGTH_INCLUDED - -#include "agg_math.h" - -namespace agg -{ - template - double path_length(VertexSource& vs, unsigned path_id = 0) - { - double len = 0.0; - double start_x = 0.0; - double start_y = 0.0; - double x1 = 0.0; - double y1 = 0.0; - double x2 = 0.0; - double y2 = 0.0; - bool first = true; - - unsigned cmd; - vs.rewind(path_id); - while(!is_stop(cmd = vs.vertex(&x2, &y2))) - { - if(is_vertex(cmd)) - { - if(first || is_move_to(cmd)) - { - start_x = x2; - start_y = y2; - } - else - { - len += calc_distance(x1, y1, x2, y2); - } - x1 = x2; - y1 = y2; - first = false; - } - else - { - if(is_close(cmd) && !first) - { - len += calc_distance(x1, y1, start_x, start_y); - } - } - } - return len; - } -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_path_storage.h corsix-th-0.62/agg/include/agg_path_storage.h --- corsix-th-0.30/agg/include/agg_path_storage.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_path_storage.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1545 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_PATH_STORAGE_INCLUDED -#define AGG_PATH_STORAGE_INCLUDED - -#include -#include -#include "agg_math.h" -#include "agg_array.h" -#include "agg_bezier_arc.h" - -namespace agg -{ - - - //----------------------------------------------------vertex_block_storage - template - class vertex_block_storage - { - public: - // Allocation parameters - enum block_scale_e - { - block_shift = BlockShift, - block_size = 1 << block_shift, - block_mask = block_size - 1, - block_pool = BlockPool - }; - - typedef T value_type; - typedef vertex_block_storage self_type; - - ~vertex_block_storage(); - vertex_block_storage(); - vertex_block_storage(const self_type& v); - const self_type& operator = (const self_type& ps); - - void remove_all(); - void free_all(); - - void add_vertex(double x, double y, unsigned cmd); - void modify_vertex(unsigned idx, double x, double y); - void modify_vertex(unsigned idx, double x, double y, unsigned cmd); - void modify_command(unsigned idx, unsigned cmd); - void swap_vertices(unsigned v1, unsigned v2); - - unsigned last_command() const; - unsigned last_vertex(double* x, double* y) const; - unsigned prev_vertex(double* x, double* y) const; - - double last_x() const; - double last_y() const; - - unsigned total_vertices() const; - unsigned vertex(unsigned idx, double* x, double* y) const; - unsigned command(unsigned idx) const; - - private: - void allocate_block(unsigned nb); - int8u* storage_ptrs(T** xy_ptr); - - private: - unsigned m_total_vertices; - unsigned m_total_blocks; - unsigned m_max_blocks; - T** m_coord_blocks; - int8u** m_cmd_blocks; - }; - - - //------------------------------------------------------------------------ - template - void vertex_block_storage::free_all() - { - if(m_total_blocks) - { - T** coord_blk = m_coord_blocks + m_total_blocks - 1; - while(m_total_blocks--) - { - pod_allocator::deallocate( - *coord_blk, - block_size * 2 + - block_size / (sizeof(T) / sizeof(unsigned char))); - --coord_blk; - } - pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); - m_total_blocks = 0; - m_max_blocks = 0; - m_coord_blocks = 0; - m_cmd_blocks = 0; - m_total_vertices = 0; - } - } - - //------------------------------------------------------------------------ - template - vertex_block_storage::~vertex_block_storage() - { - free_all(); - } - - //------------------------------------------------------------------------ - template - vertex_block_storage::vertex_block_storage() : - m_total_vertices(0), - m_total_blocks(0), - m_max_blocks(0), - m_coord_blocks(0), - m_cmd_blocks(0) - { - } - - //------------------------------------------------------------------------ - template - vertex_block_storage::vertex_block_storage(const vertex_block_storage& v) : - m_total_vertices(0), - m_total_blocks(0), - m_max_blocks(0), - m_coord_blocks(0), - m_cmd_blocks(0) - { - *this = v; - } - - //------------------------------------------------------------------------ - template - const vertex_block_storage& - vertex_block_storage::operator = (const vertex_block_storage& v) - { - remove_all(); - unsigned i; - for(i = 0; i < v.total_vertices(); i++) - { - double x, y; - unsigned cmd = v.vertex(i, &x, &y); - add_vertex(x, y, cmd); - } - return *this; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::remove_all() - { - m_total_vertices = 0; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::add_vertex(double x, double y, - unsigned cmd) - { - T* coord_ptr = 0; - *storage_ptrs(&coord_ptr) = (int8u)cmd; - coord_ptr[0] = T(x); - coord_ptr[1] = T(y); - m_total_vertices++; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::modify_vertex(unsigned idx, - double x, double y) - { - T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1); - pv[0] = T(x); - pv[1] = T(y); - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::modify_vertex(unsigned idx, - double x, double y, - unsigned cmd) - { - unsigned block = idx >> block_shift; - unsigned offset = idx & block_mask; - T* pv = m_coord_blocks[block] + (offset << 1); - pv[0] = T(x); - pv[1] = T(y); - m_cmd_blocks[block][offset] = (int8u)cmd; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::modify_command(unsigned idx, - unsigned cmd) - { - m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::swap_vertices(unsigned v1, unsigned v2) - { - unsigned b1 = v1 >> block_shift; - unsigned b2 = v2 >> block_shift; - unsigned o1 = v1 & block_mask; - unsigned o2 = v2 & block_mask; - T* pv1 = m_coord_blocks[b1] + (o1 << 1); - T* pv2 = m_coord_blocks[b2] + (o2 << 1); - T val; - val = pv1[0]; pv1[0] = pv2[0]; pv2[0] = val; - val = pv1[1]; pv1[1] = pv2[1]; pv2[1] = val; - int8u cmd = m_cmd_blocks[b1][o1]; - m_cmd_blocks[b1][o1] = m_cmd_blocks[b2][o2]; - m_cmd_blocks[b2][o2] = cmd; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::last_command() const - { - if(m_total_vertices) return command(m_total_vertices - 1); - return path_cmd_stop; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::last_vertex(double* x, double* y) const - { - if(m_total_vertices) return vertex(m_total_vertices - 1, x, y); - return path_cmd_stop; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::prev_vertex(double* x, double* y) const - { - if(m_total_vertices > 1) return vertex(m_total_vertices - 2, x, y); - return path_cmd_stop; - } - - //------------------------------------------------------------------------ - template - inline double vertex_block_storage::last_x() const - { - if(m_total_vertices) - { - unsigned idx = m_total_vertices - 1; - return m_coord_blocks[idx >> block_shift][(idx & block_mask) << 1]; - } - return 0.0; - } - - //------------------------------------------------------------------------ - template - inline double vertex_block_storage::last_y() const - { - if(m_total_vertices) - { - unsigned idx = m_total_vertices - 1; - return m_coord_blocks[idx >> block_shift][((idx & block_mask) << 1) + 1]; - } - return 0.0; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::total_vertices() const - { - return m_total_vertices; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::vertex(unsigned idx, - double* x, double* y) const - { - unsigned nb = idx >> block_shift; - const T* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1); - *x = pv[0]; - *y = pv[1]; - return m_cmd_blocks[nb][idx & block_mask]; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::command(unsigned idx) const - { - return m_cmd_blocks[idx >> block_shift][idx & block_mask]; - } - - //------------------------------------------------------------------------ - template - void vertex_block_storage::allocate_block(unsigned nb) - { - if(nb >= m_max_blocks) - { - T** new_coords = - pod_allocator::allocate((m_max_blocks + block_pool) * 2); - - unsigned char** new_cmds = - (unsigned char**)(new_coords + m_max_blocks + block_pool); - - if(m_coord_blocks) - { - memcpy(new_coords, - m_coord_blocks, - m_max_blocks * sizeof(T*)); - - memcpy(new_cmds, - m_cmd_blocks, - m_max_blocks * sizeof(unsigned char*)); - - pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); - } - m_coord_blocks = new_coords; - m_cmd_blocks = new_cmds; - m_max_blocks += block_pool; - } - m_coord_blocks[nb] = - pod_allocator::allocate(block_size * 2 + - block_size / (sizeof(T) / sizeof(unsigned char))); - - m_cmd_blocks[nb] = - (unsigned char*)(m_coord_blocks[nb] + block_size * 2); - - m_total_blocks++; - } - - //------------------------------------------------------------------------ - template - int8u* vertex_block_storage::storage_ptrs(T** xy_ptr) - { - unsigned nb = m_total_vertices >> block_shift; - if(nb >= m_total_blocks) - { - allocate_block(nb); - } - *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1); - return m_cmd_blocks[nb] + (m_total_vertices & block_mask); - } - - - - - //-----------------------------------------------------poly_plain_adaptor - template class poly_plain_adaptor - { - public: - typedef T value_type; - - poly_plain_adaptor() : - m_data(0), - m_ptr(0), - m_end(0), - m_closed(false), - m_stop(false) - {} - - poly_plain_adaptor(const T* data, unsigned num_points, bool closed) : - m_data(data), - m_ptr(data), - m_end(data + num_points * 2), - m_closed(closed), - m_stop(false) - {} - - void init(const T* data, unsigned num_points, bool closed) - { - m_data = data; - m_ptr = data; - m_end = data + num_points * 2; - m_closed = closed; - m_stop = false; - } - - void rewind(unsigned) - { - m_ptr = m_data; - m_stop = false; - } - - unsigned vertex(double* x, double* y) - { - if(m_ptr < m_end) - { - bool first = m_ptr == m_data; - *x = *m_ptr++; - *y = *m_ptr++; - return first ? path_cmd_move_to : path_cmd_line_to; - } - *x = *y = 0.0; - if(m_closed && !m_stop) - { - m_stop = true; - return path_cmd_end_poly | path_flags_close; - } - return path_cmd_stop; - } - - private: - const T* m_data; - const T* m_ptr; - const T* m_end; - bool m_closed; - bool m_stop; - }; - - - - - - //-------------------------------------------------poly_container_adaptor - template class poly_container_adaptor - { - public: - typedef typename Container::value_type vertex_type; - - poly_container_adaptor() : - m_container(0), - m_index(0), - m_closed(false), - m_stop(false) - {} - - poly_container_adaptor(const Container& data, bool closed) : - m_container(&data), - m_index(0), - m_closed(closed), - m_stop(false) - {} - - void init(const Container& data, bool closed) - { - m_container = &data; - m_index = 0; - m_closed = closed; - m_stop = false; - } - - void rewind(unsigned) - { - m_index = 0; - m_stop = false; - } - - unsigned vertex(double* x, double* y) - { - if(m_index < m_container->size()) - { - bool first = m_index == 0; - const vertex_type& v = (*m_container)[m_index++]; - *x = v.x; - *y = v.y; - return first ? path_cmd_move_to : path_cmd_line_to; - } - *x = *y = 0.0; - if(m_closed && !m_stop) - { - m_stop = true; - return path_cmd_end_poly | path_flags_close; - } - return path_cmd_stop; - } - - private: - const Container* m_container; - unsigned m_index; - bool m_closed; - bool m_stop; - }; - - - - //-----------------------------------------poly_container_reverse_adaptor - template class poly_container_reverse_adaptor - { - public: - typedef typename Container::value_type vertex_type; - - poly_container_reverse_adaptor() : - m_container(0), - m_index(-1), - m_closed(false), - m_stop(false) - {} - - poly_container_reverse_adaptor(const Container& data, bool closed) : - m_container(&data), - m_index(-1), - m_closed(closed), - m_stop(false) - {} - - void init(const Container& data, bool closed) - { - m_container = &data; - m_index = m_container->size() - 1; - m_closed = closed; - m_stop = false; - } - - void rewind(unsigned) - { - m_index = m_container->size() - 1; - m_stop = false; - } - - unsigned vertex(double* x, double* y) - { - if(m_index >= 0) - { - bool first = m_index == int(m_container->size() - 1); - const vertex_type& v = (*m_container)[m_index--]; - *x = v.x; - *y = v.y; - return first ? path_cmd_move_to : path_cmd_line_to; - } - *x = *y = 0.0; - if(m_closed && !m_stop) - { - m_stop = true; - return path_cmd_end_poly | path_flags_close; - } - return path_cmd_stop; - } - - private: - const Container* m_container; - int m_index; - bool m_closed; - bool m_stop; - }; - - - - - - //--------------------------------------------------------line_adaptor - class line_adaptor - { - public: - typedef double value_type; - - line_adaptor() : m_line(m_coord, 2, false) {} - line_adaptor(double x1, double y1, double x2, double y2) : - m_line(m_coord, 2, false) - { - m_coord[0] = x1; - m_coord[1] = y1; - m_coord[2] = x2; - m_coord[3] = y2; - } - - void init(double x1, double y1, double x2, double y2) - { - m_coord[0] = x1; - m_coord[1] = y1; - m_coord[2] = x2; - m_coord[3] = y2; - m_line.rewind(0); - } - - void rewind(unsigned) - { - m_line.rewind(0); - } - - unsigned vertex(double* x, double* y) - { - return m_line.vertex(x, y); - } - - private: - double m_coord[4]; - poly_plain_adaptor m_line; - }; - - - - - - - - - - - - - - //---------------------------------------------------------------path_base - // A container to store vertices with their flags. - // A path consists of a number of contours separated with "move_to" - // commands. The path storage can keep and maintain more than one - // path. - // To navigate to the beginning of a particular path, use rewind(path_id); - // Where path_id is what start_new_path() returns. So, when you call - // start_new_path() you need to store its return value somewhere else - // to navigate to the path afterwards. - // - // See also: vertex_source concept - //------------------------------------------------------------------------ - template class path_base - { - public: - typedef VertexContainer container_type; - typedef path_base self_type; - - //-------------------------------------------------------------------- - path_base() : m_vertices(), m_iterator(0) {} - void remove_all() { m_vertices.remove_all(); m_iterator = 0; } - void free_all() { m_vertices.free_all(); m_iterator = 0; } - - // Make path functions - //-------------------------------------------------------------------- - unsigned start_new_path(); - - void move_to(double x, double y); - void move_rel(double dx, double dy); - - void line_to(double x, double y); - void line_rel(double dx, double dy); - - void hline_to(double x); - void hline_rel(double dx); - - void vline_to(double y); - void vline_rel(double dy); - - void arc_to(double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double x, double y); - - void arc_rel(double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double dx, double dy); - - void curve3(double x_ctrl, double y_ctrl, - double x_to, double y_to); - - void curve3_rel(double dx_ctrl, double dy_ctrl, - double dx_to, double dy_to); - - void curve3(double x_to, double y_to); - - void curve3_rel(double dx_to, double dy_to); - - void curve4(double x_ctrl1, double y_ctrl1, - double x_ctrl2, double y_ctrl2, - double x_to, double y_to); - - void curve4_rel(double dx_ctrl1, double dy_ctrl1, - double dx_ctrl2, double dy_ctrl2, - double dx_to, double dy_to); - - void curve4(double x_ctrl2, double y_ctrl2, - double x_to, double y_to); - - void curve4_rel(double x_ctrl2, double y_ctrl2, - double x_to, double y_to); - - - void end_poly(unsigned flags = path_flags_close); - void close_polygon(unsigned flags = path_flags_none); - - // Accessors - //-------------------------------------------------------------------- - const container_type& vertices() const { return m_vertices; } - container_type& vertices() { return m_vertices; } - - unsigned total_vertices() const; - - void rel_to_abs(double* x, double* y) const; - - unsigned last_vertex(double* x, double* y) const; - unsigned prev_vertex(double* x, double* y) const; - - double last_x() const; - double last_y() const; - - unsigned vertex(unsigned idx, double* x, double* y) const; - unsigned command(unsigned idx) const; - - void modify_vertex(unsigned idx, double x, double y); - void modify_vertex(unsigned idx, double x, double y, unsigned cmd); - void modify_command(unsigned idx, unsigned cmd); - - // VertexSource interface - //-------------------------------------------------------------------- - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - // Arrange the orientation of a polygon, all polygons in a path, - // or in all paths. After calling arrange_orientations() or - // arrange_orientations_all_paths(), all the polygons will have - // the same orientation, i.e. path_flags_cw or path_flags_ccw - //-------------------------------------------------------------------- - unsigned arrange_polygon_orientation(unsigned start, path_flags_e orientation); - unsigned arrange_orientations(unsigned path_id, path_flags_e orientation); - void arrange_orientations_all_paths(path_flags_e orientation); - void invert_polygon(unsigned start); - - // Flip all vertices horizontally or vertically, - // between x1 and x2, or between y1 and y2 respectively - //-------------------------------------------------------------------- - void flip_x(double x1, double x2); - void flip_y(double y1, double y2); - - // Concatenate path. The path is added as is. - //-------------------------------------------------------------------- - template - void concat_path(VertexSource& vs, unsigned path_id = 0) - { - double x, y; - unsigned cmd; - vs.rewind(path_id); - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - m_vertices.add_vertex(x, y, cmd); - } - } - - //-------------------------------------------------------------------- - // Join path. The path is joined with the existing one, that is, - // it behaves as if the pen of a plotter was always down (drawing) - template - void join_path(VertexSource& vs, unsigned path_id = 0) - { - double x, y; - unsigned cmd; - vs.rewind(path_id); - cmd = vs.vertex(&x, &y); - if(!is_stop(cmd)) - { - if(is_vertex(cmd)) - { - double x0, y0; - unsigned cmd0 = last_vertex(&x0, &y0); - if(is_vertex(cmd0)) - { - if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon) - { - if(is_move_to(cmd)) cmd = path_cmd_line_to; - m_vertices.add_vertex(x, y, cmd); - } - } - else - { - if(is_stop(cmd0)) - { - cmd = path_cmd_move_to; - } - else - { - if(is_move_to(cmd)) cmd = path_cmd_line_to; - } - m_vertices.add_vertex(x, y, cmd); - } - } - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - m_vertices.add_vertex(x, y, is_move_to(cmd) ? - unsigned(path_cmd_line_to) : - cmd); - } - } - } - - // Concatenate polygon/polyline. - //-------------------------------------------------------------------- - template void concat_poly(const T* data, - unsigned num_points, - bool closed) - { - poly_plain_adaptor poly(data, num_points, closed); - concat_path(poly); - } - - // Join polygon/polyline continuously. - //-------------------------------------------------------------------- - template void join_poly(const T* data, - unsigned num_points, - bool closed) - { - poly_plain_adaptor poly(data, num_points, closed); - join_path(poly); - } - - //-------------------------------------------------------------------- - void translate(double dx, double dy, unsigned path_id=0); - void translate_all_paths(double dx, double dy); - - //-------------------------------------------------------------------- - template - void transform(const Trans& trans, unsigned path_id=0) - { - unsigned num_ver = m_vertices.total_vertices(); - for(; path_id < num_ver; path_id++) - { - double x, y; - unsigned cmd = m_vertices.vertex(path_id, &x, &y); - if(is_stop(cmd)) break; - if(is_vertex(cmd)) - { - trans.transform(&x, &y); - m_vertices.modify_vertex(path_id, x, y); - } - } - } - - //-------------------------------------------------------------------- - template - void transform_all_paths(const Trans& trans) - { - unsigned idx; - unsigned num_ver = m_vertices.total_vertices(); - for(idx = 0; idx < num_ver; idx++) - { - double x, y; - if(is_vertex(m_vertices.vertex(idx, &x, &y))) - { - trans.transform(&x, &y); - m_vertices.modify_vertex(idx, x, y); - } - } - } - - - - private: - unsigned perceive_polygon_orientation(unsigned start, unsigned end); - void invert_polygon(unsigned start, unsigned end); - - VertexContainer m_vertices; - unsigned m_iterator; - }; - - //------------------------------------------------------------------------ - template - unsigned path_base::start_new_path() - { - if(!is_stop(m_vertices.last_command())) - { - m_vertices.add_vertex(0.0, 0.0, path_cmd_stop); - } - return m_vertices.total_vertices(); - } - - - //------------------------------------------------------------------------ - template - inline void path_base::rel_to_abs(double* x, double* y) const - { - if(m_vertices.total_vertices()) - { - double x2; - double y2; - if(is_vertex(m_vertices.last_vertex(&x2, &y2))) - { - *x += x2; - *y += y2; - } - } - } - - //------------------------------------------------------------------------ - template - inline void path_base::move_to(double x, double y) - { - m_vertices.add_vertex(x, y, path_cmd_move_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::move_rel(double dx, double dy) - { - rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_move_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::line_to(double x, double y) - { - m_vertices.add_vertex(x, y, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::line_rel(double dx, double dy) - { - rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::hline_to(double x) - { - m_vertices.add_vertex(x, last_y(), path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::hline_rel(double dx) - { - double dy = 0; - rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::vline_to(double y) - { - m_vertices.add_vertex(last_x(), y, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::vline_rel(double dy) - { - double dx = 0; - rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - void path_base::arc_to(double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double x, double y) - { - if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command())) - { - const double epsilon = 1e-30; - double x0 = 0.0; - double y0 = 0.0; - m_vertices.last_vertex(&x0, &y0); - - rx = fabs(rx); - ry = fabs(ry); - - // Ensure radii are valid - //------------------------- - if(rx < epsilon || ry < epsilon) - { - line_to(x, y); - return; - } - - if(calc_distance(x0, y0, x, y) < epsilon) - { - // If the endpoints (x, y) and (x0, y0) are identical, then this - // is equivalent to omitting the elliptical arc segment entirely. - return; - } - bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y); - if(a.radii_ok()) - { - join_path(a); - } - else - { - line_to(x, y); - } - } - else - { - move_to(x, y); - } - } - - //------------------------------------------------------------------------ - template - void path_base::arc_rel(double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double dx, double dy) - { - rel_to_abs(&dx, &dy); - arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy); - } - - //------------------------------------------------------------------------ - template - void path_base::curve3(double x_ctrl, double y_ctrl, - double x_to, double y_to) - { - m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); - m_vertices.add_vertex(x_to, y_to, path_cmd_curve3); - } - - //------------------------------------------------------------------------ - template - void path_base::curve3_rel(double dx_ctrl, double dy_ctrl, - double dx_to, double dy_to) - { - rel_to_abs(&dx_ctrl, &dy_ctrl); - rel_to_abs(&dx_to, &dy_to); - m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); - m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve3); - } - - //------------------------------------------------------------------------ - template - void path_base::curve3(double x_to, double y_to) - { - double x0; - double y0; - if(is_vertex(m_vertices.last_vertex(&x0, &y0))) - { - double x_ctrl; - double y_ctrl; - unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl); - if(is_curve(cmd)) - { - x_ctrl = x0 + x0 - x_ctrl; - y_ctrl = y0 + y0 - y_ctrl; - } - else - { - x_ctrl = x0; - y_ctrl = y0; - } - curve3(x_ctrl, y_ctrl, x_to, y_to); - } - } - - //------------------------------------------------------------------------ - template - void path_base::curve3_rel(double dx_to, double dy_to) - { - rel_to_abs(&dx_to, &dy_to); - curve3(dx_to, dy_to); - } - - //------------------------------------------------------------------------ - template - void path_base::curve4(double x_ctrl1, double y_ctrl1, - double x_ctrl2, double y_ctrl2, - double x_to, double y_to) - { - m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); - m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); - m_vertices.add_vertex(x_to, y_to, path_cmd_curve4); - } - - //------------------------------------------------------------------------ - template - void path_base::curve4_rel(double dx_ctrl1, double dy_ctrl1, - double dx_ctrl2, double dy_ctrl2, - double dx_to, double dy_to) - { - rel_to_abs(&dx_ctrl1, &dy_ctrl1); - rel_to_abs(&dx_ctrl2, &dy_ctrl2); - rel_to_abs(&dx_to, &dy_to); - m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); - m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); - m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve4); - } - - //------------------------------------------------------------------------ - template - void path_base::curve4(double x_ctrl2, double y_ctrl2, - double x_to, double y_to) - { - double x0; - double y0; - if(is_vertex(last_vertex(&x0, &y0))) - { - double x_ctrl1; - double y_ctrl1; - unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1); - if(is_curve(cmd)) - { - x_ctrl1 = x0 + x0 - x_ctrl1; - y_ctrl1 = y0 + y0 - y_ctrl1; - } - else - { - x_ctrl1 = x0; - y_ctrl1 = y0; - } - curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to); - } - } - - //------------------------------------------------------------------------ - template - void path_base::curve4_rel(double dx_ctrl2, double dy_ctrl2, - double dx_to, double dy_to) - { - rel_to_abs(&dx_ctrl2, &dy_ctrl2); - rel_to_abs(&dx_to, &dy_to); - curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::end_poly(unsigned flags) - { - if(is_vertex(m_vertices.last_command())) - { - m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags); - } - } - - //------------------------------------------------------------------------ - template - inline void path_base::close_polygon(unsigned flags) - { - end_poly(path_flags_close | flags); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::total_vertices() const - { - return m_vertices.total_vertices(); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::last_vertex(double* x, double* y) const - { - return m_vertices.last_vertex(x, y); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::prev_vertex(double* x, double* y) const - { - return m_vertices.prev_vertex(x, y); - } - - //------------------------------------------------------------------------ - template - inline double path_base::last_x() const - { - return m_vertices.last_x(); - } - - //------------------------------------------------------------------------ - template - inline double path_base::last_y() const - { - return m_vertices.last_y(); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::vertex(unsigned idx, double* x, double* y) const - { - return m_vertices.vertex(idx, x, y); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::command(unsigned idx) const - { - return m_vertices.command(idx); - } - - //------------------------------------------------------------------------ - template - void path_base::modify_vertex(unsigned idx, double x, double y) - { - m_vertices.modify_vertex(idx, x, y); - } - - //------------------------------------------------------------------------ - template - void path_base::modify_vertex(unsigned idx, double x, double y, unsigned cmd) - { - m_vertices.modify_vertex(idx, x, y, cmd); - } - - //------------------------------------------------------------------------ - template - void path_base::modify_command(unsigned idx, unsigned cmd) - { - m_vertices.modify_command(idx, cmd); - } - - //------------------------------------------------------------------------ - template - inline void path_base::rewind(unsigned path_id) - { - m_iterator = path_id; - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::vertex(double* x, double* y) - { - if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop; - return m_vertices.vertex(m_iterator++, x, y); - } - - //------------------------------------------------------------------------ - template - unsigned path_base::perceive_polygon_orientation(unsigned start, - unsigned end) - { - // Calculate signed area (double area to be exact) - //--------------------- - unsigned np = end - start; - double area = 0.0; - unsigned i; - for(i = 0; i < np; i++) - { - double x1, y1, x2, y2; - m_vertices.vertex(start + i, &x1, &y1); - m_vertices.vertex(start + (i + 1) % np, &x2, &y2); - area += x1 * y2 - y1 * x2; - } - return (area < 0.0) ? path_flags_cw : path_flags_ccw; - } - - //------------------------------------------------------------------------ - template - void path_base::invert_polygon(unsigned start, unsigned end) - { - unsigned i; - unsigned tmp_cmd = m_vertices.command(start); - - --end; // Make "end" inclusive - - // Shift all commands to one position - for(i = start; i < end; i++) - { - m_vertices.modify_command(i, m_vertices.command(i + 1)); - } - - // Assign starting command to the ending command - m_vertices.modify_command(end, tmp_cmd); - - // Reverse the polygon - while(end > start) - { - m_vertices.swap_vertices(start++, end--); - } - } - - //------------------------------------------------------------------------ - template - void path_base::invert_polygon(unsigned start) - { - // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && - !is_vertex(m_vertices.command(start))) ++start; - - // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && - is_move_to(m_vertices.command(start)) && - is_move_to(m_vertices.command(start+1))) ++start; - - // Find the last vertex - unsigned end = start + 1; - while(end < m_vertices.total_vertices() && - !is_next_poly(m_vertices.command(end))) ++end; - - invert_polygon(start, end); - } - - //------------------------------------------------------------------------ - template - unsigned path_base::arrange_polygon_orientation(unsigned start, - path_flags_e orientation) - { - if(orientation == path_flags_none) return start; - - // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && - !is_vertex(m_vertices.command(start))) ++start; - - // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && - is_move_to(m_vertices.command(start)) && - is_move_to(m_vertices.command(start+1))) ++start; - - // Find the last vertex - unsigned end = start + 1; - while(end < m_vertices.total_vertices() && - !is_next_poly(m_vertices.command(end))) ++end; - - if(end - start > 2) - { - if(perceive_polygon_orientation(start, end) != unsigned(orientation)) - { - // Invert polygon, set orientation flag, and skip all end_poly - invert_polygon(start, end); - unsigned cmd; - while(end < m_vertices.total_vertices() && - is_end_poly(cmd = m_vertices.command(end))) - { - m_vertices.modify_command(end++, set_orientation(cmd, orientation)); - } - } - } - return end; - } - - //------------------------------------------------------------------------ - template - unsigned path_base::arrange_orientations(unsigned start, - path_flags_e orientation) - { - if(orientation != path_flags_none) - { - while(start < m_vertices.total_vertices()) - { - start = arrange_polygon_orientation(start, orientation); - if(is_stop(m_vertices.command(start))) - { - ++start; - break; - } - } - } - return start; - } - - //------------------------------------------------------------------------ - template - void path_base::arrange_orientations_all_paths(path_flags_e orientation) - { - if(orientation != path_flags_none) - { - unsigned start = 0; - while(start < m_vertices.total_vertices()) - { - start = arrange_orientations(start, orientation); - } - } - } - - //------------------------------------------------------------------------ - template - void path_base::flip_x(double x1, double x2) - { - unsigned i; - double x, y; - for(i = 0; i < m_vertices.total_vertices(); i++) - { - unsigned cmd = m_vertices.vertex(i, &x, &y); - if(is_vertex(cmd)) - { - m_vertices.modify_vertex(i, x2 - x + x1, y); - } - } - } - - //------------------------------------------------------------------------ - template - void path_base::flip_y(double y1, double y2) - { - unsigned i; - double x, y; - for(i = 0; i < m_vertices.total_vertices(); i++) - { - unsigned cmd = m_vertices.vertex(i, &x, &y); - if(is_vertex(cmd)) - { - m_vertices.modify_vertex(i, x, y2 - y + y1); - } - } - } - - //------------------------------------------------------------------------ - template - void path_base::translate(double dx, double dy, unsigned path_id) - { - unsigned num_ver = m_vertices.total_vertices(); - for(; path_id < num_ver; path_id++) - { - double x, y; - unsigned cmd = m_vertices.vertex(path_id, &x, &y); - if(is_stop(cmd)) break; - if(is_vertex(cmd)) - { - x += dx; - y += dy; - m_vertices.modify_vertex(path_id, x, y); - } - } - } - - //------------------------------------------------------------------------ - template - void path_base::translate_all_paths(double dx, double dy) - { - unsigned idx; - unsigned num_ver = m_vertices.total_vertices(); - for(idx = 0; idx < num_ver; idx++) - { - double x, y; - if(is_vertex(m_vertices.vertex(idx, &x, &y))) - { - x += dx; - y += dy; - m_vertices.modify_vertex(idx, x, y); - } - } - } - - //-----------------------------------------------------vertex_stl_storage - template class vertex_stl_storage - { - public: - typedef typename Container::value_type vertex_type; - typedef typename vertex_type::value_type value_type; - - void remove_all() { m_vertices.clear(); } - void free_all() { m_vertices.clear(); } - - void add_vertex(double x, double y, unsigned cmd) - { - m_vertices.push_back(vertex_type(value_type(x), - value_type(y), - int8u(cmd))); - } - - void modify_vertex(unsigned idx, double x, double y) - { - vertex_type& v = m_vertices[idx]; - v.x = value_type(x); - v.y = value_type(y); - } - - void modify_vertex(unsigned idx, double x, double y, unsigned cmd) - { - vertex_type& v = m_vertices[idx]; - v.x = value_type(x); - v.y = value_type(y); - v.cmd = int8u(cmd); - } - - void modify_command(unsigned idx, unsigned cmd) - { - m_vertices[idx].cmd = int8u(cmd); - } - - void swap_vertices(unsigned v1, unsigned v2) - { - vertex_type t = m_vertices[v1]; - m_vertices[v1] = m_vertices[v2]; - m_vertices[v2] = t; - } - - unsigned last_command() const - { - return m_vertices.size() ? - m_vertices[m_vertices.size() - 1].cmd : - path_cmd_stop; - } - - unsigned last_vertex(double* x, double* y) const - { - if(m_vertices.size() == 0) - { - *x = *y = 0.0; - return path_cmd_stop; - } - return vertex(m_vertices.size() - 1, x, y); - } - - unsigned prev_vertex(double* x, double* y) const - { - if(m_vertices.size() < 2) - { - *x = *y = 0.0; - return path_cmd_stop; - } - return vertex(m_vertices.size() - 2, x, y); - } - - double last_x() const - { - return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0; - } - - double last_y() const - { - return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0; - } - - unsigned total_vertices() const - { - return m_vertices.size(); - } - - unsigned vertex(unsigned idx, double* x, double* y) const - { - const vertex_type& v = m_vertices[idx]; - *x = v.x; - *y = v.y; - return v.cmd; - } - - unsigned command(unsigned idx) const - { - return m_vertices[idx].cmd; - } - - private: - Container m_vertices; - }; - - //-----------------------------------------------------------path_storage - typedef path_base > path_storage; - - // Example of declarations path_storage with pod_bvector as a container - //----------------------------------------------------------------------- - //typedef path_base > > path_storage; - -} - - - -// Example of declarations path_storage with std::vector as a container -//--------------------------------------------------------------------------- -//#include -//namespace agg -//{ -// typedef path_base > > stl_path_storage; -//} - - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_path_storage_integer.h corsix-th-0.62/agg/include/agg_path_storage_integer.h --- corsix-th-0.30/agg/include/agg_path_storage_integer.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_path_storage_integer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,295 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_PATH_STORAGE_INTEGER_INCLUDED -#define AGG_PATH_STORAGE_INTEGER_INCLUDED - -#include -#include "agg_array.h" - -namespace agg -{ - //---------------------------------------------------------vertex_integer - template struct vertex_integer - { - enum path_cmd - { - cmd_move_to = 0, - cmd_line_to = 1, - cmd_curve3 = 2, - cmd_curve4 = 3 - }; - - enum coord_scale_e - { - coord_shift = CoordShift, - coord_scale = 1 << coord_shift - }; - - T x,y; - vertex_integer() {} - vertex_integer(T x_, T y_, unsigned flag) : - x(((x_ << 1) & ~1) | (flag & 1)), - y(((y_ << 1) & ~1) | (flag >> 1)) {} - - unsigned vertex(double* x_, double* y_, - double dx=0, double dy=0, - double scale=1.0) const - { - *x_ = dx + (double(x >> 1) / coord_scale) * scale; - *y_ = dy + (double(y >> 1) / coord_scale) * scale; - switch(((y & 1) << 1) | (x & 1)) - { - case cmd_move_to: return path_cmd_move_to; - case cmd_line_to: return path_cmd_line_to; - case cmd_curve3: return path_cmd_curve3; - case cmd_curve4: return path_cmd_curve4; - } - return path_cmd_stop; - } - }; - - - //---------------------------------------------------path_storage_integer - template class path_storage_integer - { - public: - typedef T value_type; - typedef vertex_integer vertex_integer_type; - - //-------------------------------------------------------------------- - path_storage_integer() : m_storage(), m_vertex_idx(0), m_closed(true) {} - - //-------------------------------------------------------------------- - void remove_all() { m_storage.remove_all(); } - - //-------------------------------------------------------------------- - void move_to(T x, T y) - { - m_storage.add(vertex_integer_type(x, y, vertex_integer_type::cmd_move_to)); - } - - //-------------------------------------------------------------------- - void line_to(T x, T y) - { - m_storage.add(vertex_integer_type(x, y, vertex_integer_type::cmd_line_to)); - } - - //-------------------------------------------------------------------- - void curve3(T x_ctrl, T y_ctrl, - T x_to, T y_to) - { - m_storage.add(vertex_integer_type(x_ctrl, y_ctrl, vertex_integer_type::cmd_curve3)); - m_storage.add(vertex_integer_type(x_to, y_to, vertex_integer_type::cmd_curve3)); - } - - //-------------------------------------------------------------------- - void curve4(T x_ctrl1, T y_ctrl1, - T x_ctrl2, T y_ctrl2, - T x_to, T y_to) - { - m_storage.add(vertex_integer_type(x_ctrl1, y_ctrl1, vertex_integer_type::cmd_curve4)); - m_storage.add(vertex_integer_type(x_ctrl2, y_ctrl2, vertex_integer_type::cmd_curve4)); - m_storage.add(vertex_integer_type(x_to, y_to, vertex_integer_type::cmd_curve4)); - } - - //-------------------------------------------------------------------- - void close_polygon() {} - - //-------------------------------------------------------------------- - unsigned size() const { return m_storage.size(); } - unsigned vertex(unsigned idx, double* x, double* y) const - { - return m_storage[idx].vertex(x, y); - } - - //-------------------------------------------------------------------- - unsigned byte_size() const { return m_storage.size() * sizeof(vertex_integer_type); } - void serialize(int8u* ptr) const - { - unsigned i; - for(i = 0; i < m_storage.size(); i++) - { - memcpy(ptr, &m_storage[i], sizeof(vertex_integer_type)); - ptr += sizeof(vertex_integer_type); - } - } - - //-------------------------------------------------------------------- - void rewind(unsigned) - { - m_vertex_idx = 0; - m_closed = true; - } - - //-------------------------------------------------------------------- - unsigned vertex(double* x, double* y) - { - if(m_storage.size() < 2 || m_vertex_idx > m_storage.size()) - { - *x = 0; - *y = 0; - return path_cmd_stop; - } - if(m_vertex_idx == m_storage.size()) - { - *x = 0; - *y = 0; - ++m_vertex_idx; - return path_cmd_end_poly | path_flags_close; - } - unsigned cmd = m_storage[m_vertex_idx].vertex(x, y); - if(is_move_to(cmd) && !m_closed) - { - *x = 0; - *y = 0; - m_closed = true; - return path_cmd_end_poly | path_flags_close; - } - m_closed = false; - ++m_vertex_idx; - return cmd; - } - - //-------------------------------------------------------------------- - rect_d bounding_rect() const - { - rect_d bounds(1e100, 1e100, -1e100, -1e100); - if(m_storage.size() == 0) - { - bounds.x1 = bounds.y1 = bounds.x2 = bounds.y2 = 0.0; - } - else - { - unsigned i; - for(i = 0; i < m_storage.size(); i++) - { - double x, y; - m_storage[i].vertex(&x, &y); - if(x < bounds.x1) bounds.x1 = x; - if(y < bounds.y1) bounds.y1 = y; - if(x > bounds.x2) bounds.x2 = x; - if(y > bounds.y2) bounds.y2 = y; - } - } - return bounds; - } - - private: - pod_bvector m_storage; - unsigned m_vertex_idx; - bool m_closed; - }; - - - - - //-----------------------------------------serialized_integer_path_adaptor - template class serialized_integer_path_adaptor - { - public: - typedef vertex_integer vertex_integer_type; - - //-------------------------------------------------------------------- - serialized_integer_path_adaptor() : - m_data(0), - m_end(0), - m_ptr(0), - m_dx(0.0), - m_dy(0.0), - m_scale(1.0), - m_vertices(0) - {} - - //-------------------------------------------------------------------- - serialized_integer_path_adaptor(const int8u* data, unsigned size, - double dx, double dy) : - m_data(data), - m_end(data + size), - m_ptr(data), - m_dx(dx), - m_dy(dy), - m_vertices(0) - {} - - //-------------------------------------------------------------------- - void init(const int8u* data, unsigned size, - double dx, double dy, double scale=1.0) - { - m_data = data; - m_end = data + size; - m_ptr = data; - m_dx = dx; - m_dy = dy; - m_scale = scale; - m_vertices = 0; - } - - - //-------------------------------------------------------------------- - void rewind(unsigned) - { - m_ptr = m_data; - m_vertices = 0; - } - - //-------------------------------------------------------------------- - unsigned vertex(double* x, double* y) - { - if(m_data == 0 || m_ptr > m_end) - { - *x = 0; - *y = 0; - return path_cmd_stop; - } - - if(m_ptr == m_end) - { - *x = 0; - *y = 0; - m_ptr += sizeof(vertex_integer_type); - return path_cmd_end_poly | path_flags_close; - } - - vertex_integer_type v; - memcpy(&v, m_ptr, sizeof(vertex_integer_type)); - unsigned cmd = v.vertex(x, y, m_dx, m_dy, m_scale); - if(is_move_to(cmd) && m_vertices > 2) - { - *x = 0; - *y = 0; - m_vertices = 0; - return path_cmd_end_poly | path_flags_close; - } - ++m_vertices; - m_ptr += sizeof(vertex_integer_type); - return cmd; - } - - private: - const int8u* m_data; - const int8u* m_end; - const int8u* m_ptr; - double m_dx; - double m_dy; - double m_scale; - unsigned m_vertices; - }; - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_pattern_filters_rgba.h corsix-th-0.62/agg/include/agg_pattern_filters_rgba.h --- corsix-th-0.30/agg/include/agg_pattern_filters_rgba.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_pattern_filters_rgba.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_PATTERN_FILTERS_RGBA8_INCLUDED -#define AGG_PATTERN_FILTERS_RGBA8_INCLUDED - -#include "agg_basics.h" -#include "agg_line_aa_basics.h" -#include "agg_color_rgba.h" - - -namespace agg -{ - - //=======================================================pattern_filter_nn - template struct pattern_filter_nn - { - typedef ColorT color_type; - static unsigned dilation() { return 0; } - - static void AGG_INLINE pixel_low_res(color_type const* const* buf, - color_type* p, int x, int y) - { - *p = buf[y][x]; - } - - static void AGG_INLINE pixel_high_res(color_type const* const* buf, - color_type* p, int x, int y) - { - *p = buf[y >> line_subpixel_shift] - [x >> line_subpixel_shift]; - } - }; - - typedef pattern_filter_nn pattern_filter_nn_rgba8; - typedef pattern_filter_nn pattern_filter_nn_rgba16; - - - //===========================================pattern_filter_bilinear_rgba - template struct pattern_filter_bilinear_rgba - { - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - - - static unsigned dilation() { return 1; } - - static AGG_INLINE void pixel_low_res(color_type const* const* buf, - color_type* p, int x, int y) - { - *p = buf[y][x]; - } - - static AGG_INLINE void pixel_high_res(color_type const* const* buf, - color_type* p, int x, int y) - { - calc_type r, g, b, a; - r = g = b = a = line_subpixel_scale * line_subpixel_scale / 2; - - calc_type weight; - int x_lr = x >> line_subpixel_shift; - int y_lr = y >> line_subpixel_shift; - - x &= line_subpixel_mask; - y &= line_subpixel_mask; - const color_type* ptr = buf[y_lr] + x_lr; - - weight = (line_subpixel_scale - x) * - (line_subpixel_scale - y); - r += weight * ptr->r; - g += weight * ptr->g; - b += weight * ptr->b; - a += weight * ptr->a; - - ++ptr; - - weight = x * (line_subpixel_scale - y); - r += weight * ptr->r; - g += weight * ptr->g; - b += weight * ptr->b; - a += weight * ptr->a; - - ptr = buf[y_lr + 1] + x_lr; - - weight = (line_subpixel_scale - x) * y; - r += weight * ptr->r; - g += weight * ptr->g; - b += weight * ptr->b; - a += weight * ptr->a; - - ++ptr; - - weight = x * y; - r += weight * ptr->r; - g += weight * ptr->g; - b += weight * ptr->b; - a += weight * ptr->a; - - p->r = (value_type)(r >> line_subpixel_shift * 2); - p->g = (value_type)(g >> line_subpixel_shift * 2); - p->b = (value_type)(b >> line_subpixel_shift * 2); - p->a = (value_type)(a >> line_subpixel_shift * 2); - } - }; - - typedef pattern_filter_bilinear_rgba pattern_filter_bilinear_rgba8; - typedef pattern_filter_bilinear_rgba pattern_filter_bilinear_rgba16; -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_pixfmt_amask_adaptor.h corsix-th-0.62/agg/include/agg_pixfmt_amask_adaptor.h --- corsix-th-0.30/agg/include/agg_pixfmt_amask_adaptor.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_pixfmt_amask_adaptor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,240 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_PIXFMT_AMASK_ADAPTOR_INCLUDED -#define AGG_PIXFMT_AMASK_ADAPTOR_INCLUDED - - -#include -#include "agg_array.h" -#include "agg_rendering_buffer.h" - - -namespace agg -{ - //==================================================pixfmt_amask_adaptor - template class pixfmt_amask_adaptor - { - public: - typedef PixFmt pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::row_data row_data; - typedef AlphaMask amask_type; - typedef typename amask_type::cover_type cover_type; - - private: - enum span_extra_tail_e { span_extra_tail = 256 }; - - void realloc_span(unsigned len) - { - if(len > m_span.size()) - { - m_span.resize(len + span_extra_tail); - } - } - - void init_span(unsigned len) - { - realloc_span(len); - memset(&m_span[0], amask_type::cover_full, len * sizeof(cover_type)); - } - - void init_span(unsigned len, const cover_type* covers) - { - realloc_span(len); - memcpy(&m_span[0], covers, len * sizeof(cover_type)); - } - - - public: - pixfmt_amask_adaptor(pixfmt_type& pixf, const amask_type& mask) : - m_pixf(&pixf), m_mask(&mask), m_span() - {} - - void attach_pixfmt(pixfmt_type& pixf) { m_pixf = &pixf; } - void attach_alpha_mask(const amask_type& mask) { m_mask = &mask; } - - //-------------------------------------------------------------------- - template - bool attach_pixfmt(PixFmt2& pixf, int x1, int y1, int x2, int y2) - { - return m_pixf->attach(pixf, x1, y1, x2, y2); - } - - //-------------------------------------------------------------------- - unsigned width() const { return m_pixf->width(); } - unsigned height() const { return m_pixf->height(); } - - //-------------------------------------------------------------------- - color_type pixel(int x, int y) - { - return m_pixf->pixel(x, y); - } - - //-------------------------------------------------------------------- - void copy_pixel(int x, int y, const color_type& c) - { - m_pixf->blend_pixel(x, y, c, m_mask->pixel(x, y)); - } - - //-------------------------------------------------------------------- - void blend_pixel(int x, int y, const color_type& c, cover_type cover) - { - m_pixf->blend_pixel(x, y, c, m_mask->combine_pixel(x, y, cover)); - } - - //-------------------------------------------------------------------- - void copy_hline(int x, int y, - unsigned len, - const color_type& c) - { - realloc_span(len); - m_mask->fill_hspan(x, y, &m_span[0], len); - m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]); - } - - //-------------------------------------------------------------------- - void blend_hline(int x, int y, - unsigned len, - const color_type& c, - cover_type cover) - { - init_span(len); - m_mask->combine_hspan(x, y, &m_span[0], len); - m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]); - } - - //-------------------------------------------------------------------- - void copy_vline(int x, int y, - unsigned len, - const color_type& c) - { - realloc_span(len); - m_mask->fill_vspan(x, y, &m_span[0], len); - m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]); - } - - //-------------------------------------------------------------------- - void blend_vline(int x, int y, - unsigned len, - const color_type& c, - cover_type cover) - { - init_span(len); - m_mask->combine_vspan(x, y, &m_span[0], len); - m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]); - } - - //-------------------------------------------------------------------- - void copy_from(const rendering_buffer& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len) - { - m_pixf->copy_from(from, xdst, ydst, xsrc, ysrc, len); - } - - - //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, - unsigned len, - const color_type& c, - const cover_type* covers) - { - init_span(len, covers); - m_mask->combine_hspan(x, y, &m_span[0], len); - m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]); - } - - - //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, - unsigned len, - const color_type& c, - const cover_type* covers) - { - init_span(len, covers); - m_mask->combine_vspan(x, y, &m_span[0], len); - m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]); - } - - - //-------------------------------------------------------------------- - void copy_color_hspan(int x, int y, unsigned len, const color_type* colors) - { - realloc_span(len); - m_mask->fill_hspan(x, y, &m_span[0], len); - m_pixf->blend_color_hspan(x, y, len, colors, &m_span[0], cover_full); - } - - //-------------------------------------------------------------------- - void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) - { - realloc_span(len); - m_mask->fill_vspan(x, y, &m_span[0], len); - m_pixf->blend_color_vspan(x, y, len, colors, &m_span[0], cover_full); - } - - //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, - unsigned len, - const color_type* colors, - const cover_type* covers, - cover_type cover = cover_full) - { - if(covers) - { - init_span(len, covers); - m_mask->combine_hspan(x, y, &m_span[0], len); - } - else - { - realloc_span(len); - m_mask->fill_hspan(x, y, &m_span[0], len); - } - m_pixf->blend_color_hspan(x, y, len, colors, &m_span[0], cover); - } - - - //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, - unsigned len, - const color_type* colors, - const cover_type* covers, - cover_type cover = cover_full) - { - if(covers) - { - init_span(len, covers); - m_mask->combine_vspan(x, y, &m_span[0], len); - } - else - { - realloc_span(len); - m_mask->fill_vspan(x, y, &m_span[0], len); - } - m_pixf->blend_color_vspan(x, y, len, colors, &m_span[0], cover); - } - - private: - pixfmt_type* m_pixf; - const amask_type* m_mask; - pod_array m_span; - }; - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_pixfmt_gray.h corsix-th-0.62/agg/include/agg_pixfmt_gray.h --- corsix-th-0.30/agg/include/agg_pixfmt_gray.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_pixfmt_gray.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,670 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_PIXFMT_GRAY_INCLUDED -#define AGG_PIXFMT_GRAY_INCLUDED - -#include -#include "agg_basics.h" -#include "agg_color_gray.h" -#include "agg_rendering_buffer.h" - -namespace agg -{ - - //============================================================blender_gray - template struct blender_gray - { - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e { base_shift = color_type::base_shift }; - - static AGG_INLINE void blend_pix(value_type* p, unsigned cv, - unsigned alpha, unsigned cover=0) - { - *p = (value_type)((((cv - calc_type(*p)) * alpha) + (calc_type(*p) << base_shift)) >> base_shift); - } - }; - - - //======================================================blender_gray_pre - template struct blender_gray_pre - { - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e { base_shift = color_type::base_shift }; - - static AGG_INLINE void blend_pix(value_type* p, unsigned cv, - unsigned alpha, unsigned cover) - { - alpha = color_type::base_mask - alpha; - cover = (cover + 1) << (base_shift - 8); - *p = (value_type)((*p * alpha + cv * cover) >> base_shift); - } - - static AGG_INLINE void blend_pix(value_type* p, unsigned cv, - unsigned alpha) - { - *p = (value_type)(((*p * (color_type::base_mask - alpha)) >> base_shift) + cv); - } - }; - - - - //=====================================================apply_gamma_dir_gray - template class apply_gamma_dir_gray - { - public: - typedef typename ColorT::value_type value_type; - - apply_gamma_dir_gray(const GammaLut& gamma) : m_gamma(gamma) {} - - AGG_INLINE void operator () (value_type* p) - { - *p = m_gamma.dir(*p); - } - - private: - const GammaLut& m_gamma; - }; - - - - //=====================================================apply_gamma_inv_gray - template class apply_gamma_inv_gray - { - public: - typedef typename ColorT::value_type value_type; - - apply_gamma_inv_gray(const GammaLut& gamma) : m_gamma(gamma) {} - - AGG_INLINE void operator () (value_type* p) - { - *p = m_gamma.inv(*p); - } - - private: - const GammaLut& m_gamma; - }; - - - - //=================================================pixfmt_alpha_blend_gray - template - class pixfmt_alpha_blend_gray - { - public: - typedef RenBuf rbuf_type; - typedef typename rbuf_type::row_data row_data; - typedef Blender blender_type; - typedef typename blender_type::color_type color_type; - typedef int order_type; // A fake one - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask, - pix_width = sizeof(value_type), - pix_step = Step, - pix_offset = Offset - }; - - private: - //-------------------------------------------------------------------- - static AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c, - unsigned cover) - { - if (c.a) - { - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - *p = c.v; - } - else - { - Blender::blend_pix(p, c.v, alpha, cover); - } - } - } - - - static AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c) - { - if (c.a) - { - if(c.a == base_mask) - { - *p = c.v; - } - else - { - Blender::blend_pix(p, c.v, c.a); - } - } - } - - - public: - //-------------------------------------------------------------------- - explicit pixfmt_alpha_blend_gray(rbuf_type& rb) : - m_rbuf(&rb) - {} - void attach(rbuf_type& rb) { m_rbuf = &rb; } - //-------------------------------------------------------------------- - - template - bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) - { - rect_i r(x1, y1, x2, y2); - if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) - { - int stride = pixf.stride(); - m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), - (r.x2 - r.x1) + 1, - (r.y2 - r.y1) + 1, - stride); - return true; - } - return false; - } - - //-------------------------------------------------------------------- - AGG_INLINE unsigned width() const { return m_rbuf->width(); } - AGG_INLINE unsigned height() const { return m_rbuf->height(); } - AGG_INLINE int stride() const { return m_rbuf->stride(); } - - //-------------------------------------------------------------------- - int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } - const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } - row_data row(int y) const { return m_rbuf->row(y); } - - const int8u* pix_ptr(int x, int y) const - { - return m_rbuf->row_ptr(y) + x * Step + Offset; - } - - int8u* pix_ptr(int x, int y) - { - return m_rbuf->row_ptr(y) + x * Step + Offset; - } - - //-------------------------------------------------------------------- - AGG_INLINE static void make_pix(int8u* p, const color_type& c) - { - *(value_type*)p = c.v; - } - - //-------------------------------------------------------------------- - AGG_INLINE color_type pixel(int x, int y) const - { - value_type* p = (value_type*)m_rbuf->row_ptr(y) + x * Step + Offset; - return color_type(*p); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_pixel(int x, int y, const color_type& c) - { - *((value_type*)m_rbuf->row_ptr(x, y, 1) + x * Step + Offset) = c.v; - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) - { - copy_or_blend_pix((value_type*) - m_rbuf->row_ptr(x, y, 1) + x * Step + Offset, - c, - cover); - } - - - //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, - const color_type& c) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - - do - { - *p = c.v; - p += Step; - } - while(--len); - } - - - //-------------------------------------------------------------------- - AGG_INLINE void copy_vline(int x, int y, - unsigned len, - const color_type& c) - { - do - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - *p = c.v; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void blend_hline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - if (c.a) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - do - { - *p = c.v; - p += Step; - } - while(--len); - } - else - { - do - { - Blender::blend_pix(p, c.v, alpha, cover); - p += Step; - } - while(--len); - } - } - } - - - //-------------------------------------------------------------------- - void blend_vline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - if (c.a) - { - value_type* p; - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - *p = c.v; - } - while(--len); - } - else - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - Blender::blend_pix(p, c.v, alpha, cover); - } - while(--len); - } - } - } - - - //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - if (c.a) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - - do - { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) - { - *p = c.v; - } - else - { - Blender::blend_pix(p, c.v, alpha, *covers); - } - p += Step; - ++covers; - } - while(--len); - } - } - - - //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - if (c.a) - { - do - { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - if(alpha == base_mask) - { - *p = c.v; - } - else - { - Blender::blend_pix(p, c.v, alpha, *covers); - } - ++covers; - } - while(--len); - } - } - - - //-------------------------------------------------------------------- - void copy_color_hspan(int x, int y, - unsigned len, - const color_type* colors) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - - do - { - *p = colors->v; - p += Step; - ++colors; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void copy_color_vspan(int x, int y, - unsigned len, - const color_type* colors) - { - do - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - *p = colors->v; - ++colors; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - - if(covers) - { - do - { - copy_or_blend_pix(p, *colors++, *covers++); - p += Step; - } - while(--len); - } - else - { - if(cover == 255) - { - do - { - if(colors->a == base_mask) - { - *p = colors->v; - } - else - { - copy_or_blend_pix(p, *colors); - } - p += Step; - ++colors; - } - while(--len); - } - else - { - do - { - copy_or_blend_pix(p, *colors++, cover); - p += Step; - } - while(--len); - } - } - } - - - - //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - value_type* p; - if(covers) - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - copy_or_blend_pix(p, *colors++, *covers++); - } - while(--len); - } - else - { - if(cover == 255) - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - if(colors->a == base_mask) - { - *p = colors->v; - } - else - { - copy_or_blend_pix(p, *colors); - } - ++colors; - } - while(--len); - } - else - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - copy_or_blend_pix(p, *colors++, cover); - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - template void for_each_pixel(Function f) - { - unsigned y; - for(y = 0; y < height(); ++y) - { - row_data r = m_rbuf->row(y); - if(r.ptr) - { - unsigned len = r.x2 - r.x1 + 1; - - value_type* p = (value_type*) - m_rbuf->row_ptr(r.x1, y, len) + r.x1 * Step + Offset; - - do - { - f(p); - p += Step; - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - template void apply_gamma_dir(const GammaLut& g) - { - for_each_pixel(apply_gamma_dir_gray(g)); - } - - //-------------------------------------------------------------------- - template void apply_gamma_inv(const GammaLut& g) - { - for_each_pixel(apply_gamma_inv_gray(g)); - } - - //-------------------------------------------------------------------- - template - void copy_from(const RenBuf2& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len) - { - const int8u* p = from.row_ptr(ysrc); - if(p) - { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, - len * pix_width); - } - } - - //-------------------------------------------------------------------- - template - void blend_from_color(const SrcPixelFormatRenderer& from, - const color_type& color, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; - do - { - copy_or_blend_pix(pdst, - color, - (*psrc * cover + base_mask) >> base_shift); - ++psrc; - ++pdst; - } - while(--len); - } - } - - //-------------------------------------------------------------------- - template - void blend_from_lut(const SrcPixelFormatRenderer& from, - const color_type* color_lut, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; - do - { - copy_or_blend_pix(pdst, color_lut[*psrc], cover); - ++psrc; - ++pdst; - } - while(--len); - } - } - - private: - rbuf_type* m_rbuf; - }; - - typedef blender_gray blender_gray8; - typedef blender_gray_pre blender_gray8_pre; - typedef blender_gray blender_gray16; - typedef blender_gray_pre blender_gray16_pre; - - typedef pixfmt_alpha_blend_gray pixfmt_gray8; //----pixfmt_gray8 - typedef pixfmt_alpha_blend_gray pixfmt_gray8_pre; //----pixfmt_gray8_pre - typedef pixfmt_alpha_blend_gray pixfmt_gray16; //----pixfmt_gray16 - typedef pixfmt_alpha_blend_gray pixfmt_gray16_pre; //----pixfmt_gray16_pre -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_pixfmt_rgba.h corsix-th-0.62/agg/include/agg_pixfmt_rgba.h --- corsix-th-0.30/agg/include/agg_pixfmt_rgba.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_pixfmt_rgba.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,2902 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_PIXFMT_RGBA_INCLUDED -#define AGG_PIXFMT_RGBA_INCLUDED - -#include -#include -#include "agg_basics.h" -#include "agg_color_rgba.h" -#include "agg_rendering_buffer.h" - -namespace agg -{ - - //=========================================================multiplier_rgba - template struct multiplier_rgba - { - typedef typename ColorT::value_type value_type; - typedef typename ColorT::calc_type calc_type; - - //-------------------------------------------------------------------- - static AGG_INLINE void premultiply(value_type* p) - { - calc_type a = p[Order::A]; - if(a < ColorT::base_mask) - { - if(a == 0) - { - p[Order::R] = p[Order::G] = p[Order::B] = 0; - return; - } - p[Order::R] = value_type((p[Order::R] * a + ColorT::base_mask) >> ColorT::base_shift); - p[Order::G] = value_type((p[Order::G] * a + ColorT::base_mask) >> ColorT::base_shift); - p[Order::B] = value_type((p[Order::B] * a + ColorT::base_mask) >> ColorT::base_shift); - } - } - - - //-------------------------------------------------------------------- - static AGG_INLINE void demultiply(value_type* p) - { - calc_type a = p[Order::A]; - if(a < ColorT::base_mask) - { - if(a == 0) - { - p[Order::R] = p[Order::G] = p[Order::B] = 0; - return; - } - calc_type r = (calc_type(p[Order::R]) * ColorT::base_mask) / a; - calc_type g = (calc_type(p[Order::G]) * ColorT::base_mask) / a; - calc_type b = (calc_type(p[Order::B]) * ColorT::base_mask) / a; - p[Order::R] = value_type((r > ColorT::base_mask) ? ColorT::base_mask : r); - p[Order::G] = value_type((g > ColorT::base_mask) ? ColorT::base_mask : g); - p[Order::B] = value_type((b > ColorT::base_mask) ? ColorT::base_mask : b); - } - } - }; - - //=====================================================apply_gamma_dir_rgba - template class apply_gamma_dir_rgba - { - public: - typedef typename ColorT::value_type value_type; - - apply_gamma_dir_rgba(const GammaLut& gamma) : m_gamma(gamma) {} - - AGG_INLINE void operator () (value_type* p) - { - p[Order::R] = m_gamma.dir(p[Order::R]); - p[Order::G] = m_gamma.dir(p[Order::G]); - p[Order::B] = m_gamma.dir(p[Order::B]); - } - - private: - const GammaLut& m_gamma; - }; - - //=====================================================apply_gamma_inv_rgba - template class apply_gamma_inv_rgba - { - public: - typedef typename ColorT::value_type value_type; - - apply_gamma_inv_rgba(const GammaLut& gamma) : m_gamma(gamma) {} - - AGG_INLINE void operator () (value_type* p) - { - p[Order::R] = m_gamma.inv(p[Order::R]); - p[Order::G] = m_gamma.inv(p[Order::G]); - p[Order::B] = m_gamma.inv(p[Order::B]); - } - - private: - const GammaLut& m_gamma; - }; - - - - - - - - - - - //=============================================================blender_rgba - template struct blender_rgba - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover=0) - { - calc_type r = p[Order::R]; - calc_type g = p[Order::G]; - calc_type b = p[Order::B]; - calc_type a = p[Order::A]; - p[Order::R] = (value_type)(((cr - r) * alpha + (r << base_shift)) >> base_shift); - p[Order::G] = (value_type)(((cg - g) * alpha + (g << base_shift)) >> base_shift); - p[Order::B] = (value_type)(((cb - b) * alpha + (b << base_shift)) >> base_shift); - p[Order::A] = (value_type)((alpha + a) - ((alpha * a + base_mask) >> base_shift)); - } - }; - - //=========================================================blender_rgba_pre - template struct blender_rgba_pre - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - alpha = color_type::base_mask - alpha; - cover = (cover + 1) << (base_shift - 8); - p[Order::R] = (value_type)((p[Order::R] * alpha + cr * cover) >> base_shift); - p[Order::G] = (value_type)((p[Order::G] * alpha + cg * cover) >> base_shift); - p[Order::B] = (value_type)((p[Order::B] * alpha + cb * cover) >> base_shift); - p[Order::A] = (value_type)(base_mask - ((alpha * (base_mask - p[Order::A])) >> base_shift)); - } - - //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha) - { - alpha = color_type::base_mask - alpha; - p[Order::R] = (value_type)(((p[Order::R] * alpha) >> base_shift) + cr); - p[Order::G] = (value_type)(((p[Order::G] * alpha) >> base_shift) + cg); - p[Order::B] = (value_type)(((p[Order::B] * alpha) >> base_shift) + cb); - p[Order::A] = (value_type)(base_mask - ((alpha * (base_mask - p[Order::A])) >> base_shift)); - } - }; - - //======================================================blender_rgba_plain - template struct blender_rgba_plain - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e { base_shift = color_type::base_shift }; - - //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover=0) - { - if(alpha == 0) return; - calc_type a = p[Order::A]; - calc_type r = p[Order::R] * a; - calc_type g = p[Order::G] * a; - calc_type b = p[Order::B] * a; - a = ((alpha + a) << base_shift) - alpha * a; - p[Order::A] = (value_type)(a >> base_shift); - p[Order::R] = (value_type)((((cr << base_shift) - r) * alpha + (r << base_shift)) / a); - p[Order::G] = (value_type)((((cg << base_shift) - g) * alpha + (g << base_shift)) / a); - p[Order::B] = (value_type)((((cb << base_shift) - b) * alpha + (b << base_shift)) / a); - } - }; - - - - - - - - - - - - //=========================================================comp_op_rgba_clear - template struct comp_op_rgba_clear - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - static AGG_INLINE void blend_pix(value_type* p, - unsigned, unsigned, unsigned, unsigned, - unsigned cover) - { - if(cover < 255) - { - cover = 255 - cover; - p[Order::R] = (value_type)((p[Order::R] * cover + 255) >> 8); - p[Order::G] = (value_type)((p[Order::G] * cover + 255) >> 8); - p[Order::B] = (value_type)((p[Order::B] * cover + 255) >> 8); - p[Order::A] = (value_type)((p[Order::A] * cover + 255) >> 8); - } - else - { - p[0] = p[1] = p[2] = p[3] = 0; - } - } - }; - - //===========================================================comp_op_rgba_src - template struct comp_op_rgba_src - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - unsigned alpha = 255 - cover; - p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((sr * cover + 255) >> 8)); - p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((sg * cover + 255) >> 8)); - p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((sb * cover + 255) >> 8)); - p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((sa * cover + 255) >> 8)); - } - else - { - p[Order::R] = sr; - p[Order::G] = sg; - p[Order::B] = sb; - p[Order::A] = sa; - } - } - }; - - //===========================================================comp_op_rgba_dst - template struct comp_op_rgba_dst - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - - static AGG_INLINE void blend_pix(value_type*, - unsigned, unsigned, unsigned, - unsigned, unsigned) - { - } - }; - - //======================================================comp_op_rgba_src_over - template struct comp_op_rgba_src_over - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Sca + Dca.(1 - Sa) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - calc_type s1a = base_mask - sa; - p[Order::R] = (value_type)(sr + ((p[Order::R] * s1a + base_mask) >> base_shift)); - p[Order::G] = (value_type)(sg + ((p[Order::G] * s1a + base_mask) >> base_shift)); - p[Order::B] = (value_type)(sb + ((p[Order::B] * s1a + base_mask) >> base_shift)); - p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); - } - }; - - //======================================================comp_op_rgba_dst_over - template struct comp_op_rgba_dst_over - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Dca + Sca.(1 - Da) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - calc_type d1a = base_mask - p[Order::A]; - p[Order::R] = (value_type)(p[Order::R] + ((sr * d1a + base_mask) >> base_shift)); - p[Order::G] = (value_type)(p[Order::G] + ((sg * d1a + base_mask) >> base_shift)); - p[Order::B] = (value_type)(p[Order::B] + ((sb * d1a + base_mask) >> base_shift)); - p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); - } - }; - - //======================================================comp_op_rgba_src_in - template struct comp_op_rgba_src_in - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Sca.Da - // Da' = Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - calc_type da = p[Order::A]; - if(cover < 255) - { - unsigned alpha = 255 - cover; - p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((((sr * da + base_mask) >> base_shift) * cover + 255) >> 8)); - p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((((sg * da + base_mask) >> base_shift) * cover + 255) >> 8)); - p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((((sb * da + base_mask) >> base_shift) * cover + 255) >> 8)); - p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((((sa * da + base_mask) >> base_shift) * cover + 255) >> 8)); - } - else - { - p[Order::R] = (value_type)((sr * da + base_mask) >> base_shift); - p[Order::G] = (value_type)((sg * da + base_mask) >> base_shift); - p[Order::B] = (value_type)((sb * da + base_mask) >> base_shift); - p[Order::A] = (value_type)((sa * da + base_mask) >> base_shift); - } - } - }; - - //======================================================comp_op_rgba_dst_in - template struct comp_op_rgba_dst_in - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Dca.Sa - // Da' = Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned, unsigned, unsigned, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sa = base_mask - ((cover * (base_mask - sa) + 255) >> 8); - } - p[Order::R] = (value_type)((p[Order::R] * sa + base_mask) >> base_shift); - p[Order::G] = (value_type)((p[Order::G] * sa + base_mask) >> base_shift); - p[Order::B] = (value_type)((p[Order::B] * sa + base_mask) >> base_shift); - p[Order::A] = (value_type)((p[Order::A] * sa + base_mask) >> base_shift); - } - }; - - //======================================================comp_op_rgba_src_out - template struct comp_op_rgba_src_out - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Sca.(1 - Da) - // Da' = Sa.(1 - Da) - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - calc_type da = base_mask - p[Order::A]; - if(cover < 255) - { - unsigned alpha = 255 - cover; - p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((((sr * da + base_mask) >> base_shift) * cover + 255) >> 8)); - p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((((sg * da + base_mask) >> base_shift) * cover + 255) >> 8)); - p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((((sb * da + base_mask) >> base_shift) * cover + 255) >> 8)); - p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((((sa * da + base_mask) >> base_shift) * cover + 255) >> 8)); - } - else - { - p[Order::R] = (value_type)((sr * da + base_mask) >> base_shift); - p[Order::G] = (value_type)((sg * da + base_mask) >> base_shift); - p[Order::B] = (value_type)((sb * da + base_mask) >> base_shift); - p[Order::A] = (value_type)((sa * da + base_mask) >> base_shift); - } - } - }; - - //======================================================comp_op_rgba_dst_out - template struct comp_op_rgba_dst_out - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Dca.(1 - Sa) - // Da' = Da.(1 - Sa) - static AGG_INLINE void blend_pix(value_type* p, - unsigned, unsigned, unsigned, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sa = (sa * cover + 255) >> 8; - } - sa = base_mask - sa; - p[Order::R] = (value_type)((p[Order::R] * sa + base_shift) >> base_shift); - p[Order::G] = (value_type)((p[Order::G] * sa + base_shift) >> base_shift); - p[Order::B] = (value_type)((p[Order::B] * sa + base_shift) >> base_shift); - p[Order::A] = (value_type)((p[Order::A] * sa + base_shift) >> base_shift); - } - }; - - //=====================================================comp_op_rgba_src_atop - template struct comp_op_rgba_src_atop - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Sca.Da + Dca.(1 - Sa) - // Da' = Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - calc_type da = p[Order::A]; - sa = base_mask - sa; - p[Order::R] = (value_type)((sr * da + p[Order::R] * sa + base_mask) >> base_shift); - p[Order::G] = (value_type)((sg * da + p[Order::G] * sa + base_mask) >> base_shift); - p[Order::B] = (value_type)((sb * da + p[Order::B] * sa + base_mask) >> base_shift); - } - }; - - //=====================================================comp_op_rgba_dst_atop - template struct comp_op_rgba_dst_atop - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Dca.Sa + Sca.(1 - Da) - // Da' = Sa - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - calc_type da = base_mask - p[Order::A]; - if(cover < 255) - { - unsigned alpha = 255 - cover; - sr = (p[Order::R] * sa + sr * da + base_mask) >> base_shift; - sg = (p[Order::G] * sa + sg * da + base_mask) >> base_shift; - sb = (p[Order::B] * sa + sb * da + base_mask) >> base_shift; - p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((sr * cover + 255) >> 8)); - p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((sg * cover + 255) >> 8)); - p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((sb * cover + 255) >> 8)); - p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((sa * cover + 255) >> 8)); - - } - else - { - p[Order::R] = (value_type)((p[Order::R] * sa + sr * da + base_mask) >> base_shift); - p[Order::G] = (value_type)((p[Order::G] * sa + sg * da + base_mask) >> base_shift); - p[Order::B] = (value_type)((p[Order::B] * sa + sb * da + base_mask) >> base_shift); - p[Order::A] = (value_type)sa; - } - } - }; - - //=========================================================comp_op_rgba_xor - template struct comp_op_rgba_xor - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Sca.(1 - Da) + Dca.(1 - Sa) - // Da' = Sa + Da - 2.Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type s1a = base_mask - sa; - calc_type d1a = base_mask - p[Order::A]; - p[Order::R] = (value_type)((p[Order::R] * s1a + sr * d1a + base_mask) >> base_shift); - p[Order::G] = (value_type)((p[Order::G] * s1a + sg * d1a + base_mask) >> base_shift); - p[Order::B] = (value_type)((p[Order::B] * s1a + sb * d1a + base_mask) >> base_shift); - p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask/2) >> (base_shift - 1))); - } - } - }; - - //=========================================================comp_op_rgba_plus - template struct comp_op_rgba_plus - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Sca + Dca - // Da' = Sa + Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type dr = p[Order::R] + sr; - calc_type dg = p[Order::G] + sg; - calc_type db = p[Order::B] + sb; - calc_type da = p[Order::A] + sa; - p[Order::R] = (dr > base_mask) ? (value_type)base_mask : dr; - p[Order::G] = (dg > base_mask) ? (value_type)base_mask : dg; - p[Order::B] = (db > base_mask) ? (value_type)base_mask : db; - p[Order::A] = (da > base_mask) ? (value_type)base_mask : da; - } - } - }; - - //========================================================comp_op_rgba_minus - template struct comp_op_rgba_minus - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Dca - Sca - // Da' = 1 - (1 - Sa).(1 - Da) - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type dr = p[Order::R] - sr; - calc_type dg = p[Order::G] - sg; - calc_type db = p[Order::B] - sb; - p[Order::R] = (dr > base_mask) ? 0 : dr; - p[Order::G] = (dg > base_mask) ? 0 : dg; - p[Order::B] = (db > base_mask) ? 0 : db; - p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); - //p[Order::A] = (value_type)(base_mask - (((base_mask - sa) * (base_mask - p[Order::A]) + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_multiply - template struct comp_op_rgba_multiply - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type s1a = base_mask - sa; - calc_type d1a = base_mask - p[Order::A]; - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - p[Order::R] = (value_type)((sr * dr + sr * d1a + dr * s1a + base_mask) >> base_shift); - p[Order::G] = (value_type)((sg * dg + sg * d1a + dg * s1a + base_mask) >> base_shift); - p[Order::B] = (value_type)((sb * db + sb * d1a + db * s1a + base_mask) >> base_shift); - p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_screen - template struct comp_op_rgba_screen - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = Sca + Dca - Sca.Dca - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - p[Order::R] = (value_type)(sr + dr - ((sr * dr + base_mask) >> base_shift)); - p[Order::G] = (value_type)(sg + dg - ((sg * dg + base_mask) >> base_shift)); - p[Order::B] = (value_type)(sb + db - ((sb * db + base_mask) >> base_shift)); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_overlay - template struct comp_op_rgba_overlay - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // if 2.Dca < Da - // Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - // otherwise - // Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) - // - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type d1a = base_mask - p[Order::A]; - calc_type s1a = base_mask - sa; - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - calc_type sada = sa * p[Order::A]; - - p[Order::R] = (value_type)(((2*dr < da) ? - 2*sr*dr + sr*d1a + dr*s1a : - sada - 2*(da - dr)*(sa - sr) + sr*d1a + dr*s1a + base_mask) >> base_shift); - - p[Order::G] = (value_type)(((2*dg < da) ? - 2*sg*dg + sg*d1a + dg*s1a : - sada - 2*(da - dg)*(sa - sg) + sg*d1a + dg*s1a + base_mask) >> base_shift); - - p[Order::B] = (value_type)(((2*db < da) ? - 2*sb*db + sb*d1a + db*s1a : - sada - 2*(da - db)*(sa - sb) + sb*d1a + db*s1a + base_mask) >> base_shift); - - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - - template inline T sd_min(T a, T b) { return (a < b) ? a : b; } - template inline T sd_max(T a, T b) { return (a > b) ? a : b; } - - //=====================================================comp_op_rgba_darken - template struct comp_op_rgba_darken - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type d1a = base_mask - p[Order::A]; - calc_type s1a = base_mask - sa; - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - - p[Order::R] = (value_type)((sd_min(sr * da, dr * sa) + sr * d1a + dr * s1a + base_mask) >> base_shift); - p[Order::G] = (value_type)((sd_min(sg * da, dg * sa) + sg * d1a + dg * s1a + base_mask) >> base_shift); - p[Order::B] = (value_type)((sd_min(sb * da, db * sa) + sb * d1a + db * s1a + base_mask) >> base_shift); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_lighten - template struct comp_op_rgba_lighten - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type d1a = base_mask - p[Order::A]; - calc_type s1a = base_mask - sa; - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - - p[Order::R] = (value_type)((sd_max(sr * da, dr * sa) + sr * d1a + dr * s1a + base_mask) >> base_shift); - p[Order::G] = (value_type)((sd_max(sg * da, dg * sa) + sg * d1a + dg * s1a + base_mask) >> base_shift); - p[Order::B] = (value_type)((sd_max(sb * da, db * sa) + sb * d1a + db * s1a + base_mask) >> base_shift); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_color_dodge - template struct comp_op_rgba_color_dodge - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // if Sca.Da + Dca.Sa >= Sa.Da - // Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) - // otherwise - // Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - // - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type d1a = base_mask - p[Order::A]; - calc_type s1a = base_mask - sa; - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - long_type drsa = dr * sa; - long_type dgsa = dg * sa; - long_type dbsa = db * sa; - long_type srda = sr * da; - long_type sgda = sg * da; - long_type sbda = sb * da; - long_type sada = sa * da; - - p[Order::R] = (value_type)((srda + drsa >= sada) ? - (sada + sr * d1a + dr * s1a + base_mask) >> base_shift : - drsa / (base_mask - (sr << base_shift) / sa) + ((sr * d1a + dr * s1a + base_mask) >> base_shift)); - - p[Order::G] = (value_type)((sgda + dgsa >= sada) ? - (sada + sg * d1a + dg * s1a + base_mask) >> base_shift : - dgsa / (base_mask - (sg << base_shift) / sa) + ((sg * d1a + dg * s1a + base_mask) >> base_shift)); - - p[Order::B] = (value_type)((sbda + dbsa >= sada) ? - (sada + sb * d1a + db * s1a + base_mask) >> base_shift : - dbsa / (base_mask - (sb << base_shift) / sa) + ((sb * d1a + db * s1a + base_mask) >> base_shift)); - - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_color_burn - template struct comp_op_rgba_color_burn - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // if Sca.Da + Dca.Sa <= Sa.Da - // Dca' = Sca.(1 - Da) + Dca.(1 - Sa) - // otherwise - // Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) - // - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type d1a = base_mask - p[Order::A]; - calc_type s1a = base_mask - sa; - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - long_type drsa = dr * sa; - long_type dgsa = dg * sa; - long_type dbsa = db * sa; - long_type srda = sr * da; - long_type sgda = sg * da; - long_type sbda = sb * da; - long_type sada = sa * da; - - p[Order::R] = (value_type)(((srda + drsa <= sada) ? - sr * d1a + dr * s1a : - sa * (srda + drsa - sada) / sr + sr * d1a + dr * s1a + base_mask) >> base_shift); - - p[Order::G] = (value_type)(((sgda + dgsa <= sada) ? - sg * d1a + dg * s1a : - sa * (sgda + dgsa - sada) / sg + sg * d1a + dg * s1a + base_mask) >> base_shift); - - p[Order::B] = (value_type)(((sbda + dbsa <= sada) ? - sb * d1a + db * s1a : - sa * (sbda + dbsa - sada) / sb + sb * d1a + db * s1a + base_mask) >> base_shift); - - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_hard_light - template struct comp_op_rgba_hard_light - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // if 2.Sca < Sa - // Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - // otherwise - // Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) - // - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type d1a = base_mask - p[Order::A]; - calc_type s1a = base_mask - sa; - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - calc_type sada = sa * da; - - p[Order::R] = (value_type)(((2*sr < sa) ? - 2*sr*dr + sr*d1a + dr*s1a : - sada - 2*(da - dr)*(sa - sr) + sr*d1a + dr*s1a + base_mask) >> base_shift); - - p[Order::G] = (value_type)(((2*sg < sa) ? - 2*sg*dg + sg*d1a + dg*s1a : - sada - 2*(da - dg)*(sa - sg) + sg*d1a + dg*s1a + base_mask) >> base_shift); - - p[Order::B] = (value_type)(((2*sb < sa) ? - 2*sb*db + sb*d1a + db*s1a : - sada - 2*(da - db)*(sa - sb) + sb*d1a + db*s1a + base_mask) >> base_shift); - - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_soft_light - template struct comp_op_rgba_soft_light - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // if 2.Sca < Sa - // Dca' = Dca.(Sa + (1 - Dca/Da).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) - // otherwise if 8.Dca <= Da - // Dca' = Dca.(Sa + (1 - Dca/Da).(2.Sca - Sa).(3 - 8.Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) - // otherwise - // Dca' = (Dca.Sa + ((Dca/Da)^(0.5).Da - Dca).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) - // - // Da' = Sa + Da - Sa.Da - - static AGG_INLINE void blend_pix(value_type* p, - unsigned r, unsigned g, unsigned b, - unsigned a, unsigned cover) - { - double sr = double(r * cover) / (base_mask * 255); - double sg = double(g * cover) / (base_mask * 255); - double sb = double(b * cover) / (base_mask * 255); - double sa = double(a * cover) / (base_mask * 255); - if(sa > 0) - { - double dr = double(p[Order::R]) / base_mask; - double dg = double(p[Order::G]) / base_mask; - double db = double(p[Order::B]) / base_mask; - double da = double(p[Order::A] ? p[Order::A] : 1) / base_mask; - if(cover < 255) - { - a = (a * cover + 255) >> 8; - } - - if(2*sr < sa) dr = dr*(sa + (1 - dr/da)*(2*sr - sa)) + sr*(1 - da) + dr*(1 - sa); - else if(8*dr <= da) dr = dr*(sa + (1 - dr/da)*(2*sr - sa)*(3 - 8*dr/da)) + sr*(1 - da) + dr*(1 - sa); - else dr = (dr*sa + (sqrt(dr/da)*da - dr)*(2*sr - sa)) + sr*(1 - da) + dr*(1 - sa); - - if(2*sg < sa) dg = dg*(sa + (1 - dg/da)*(2*sg - sa)) + sg*(1 - da) + dg*(1 - sa); - else if(8*dg <= da) dg = dg*(sa + (1 - dg/da)*(2*sg - sa)*(3 - 8*dg/da)) + sg*(1 - da) + dg*(1 - sa); - else dg = (dg*sa + (sqrt(dg/da)*da - dg)*(2*sg - sa)) + sg*(1 - da) + dg*(1 - sa); - - if(2*sb < sa) db = db*(sa + (1 - db/da)*(2*sb - sa)) + sb*(1 - da) + db*(1 - sa); - else if(8*db <= da) db = db*(sa + (1 - db/da)*(2*sb - sa)*(3 - 8*db/da)) + sb*(1 - da) + db*(1 - sa); - else db = (db*sa + (sqrt(db/da)*da - db)*(2*sb - sa)) + sb*(1 - da) + db*(1 - sa); - - p[Order::R] = (value_type)uround(dr * base_mask); - p[Order::G] = (value_type)uround(dg * base_mask); - p[Order::B] = (value_type)uround(db * base_mask); - p[Order::A] = (value_type)(a + p[Order::A] - ((a * p[Order::A] + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_difference - template struct comp_op_rgba_difference - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask - }; - - // Dca' = Sca + Dca - 2.min(Sca.Da, Dca.Sa) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - p[Order::R] = (value_type)(sr + dr - ((2 * sd_min(sr*da, dr*sa) + base_mask) >> base_shift)); - p[Order::G] = (value_type)(sg + dg - ((2 * sd_min(sg*da, dg*sa) + base_mask) >> base_shift)); - p[Order::B] = (value_type)(sb + db - ((2 * sd_min(sb*da, db*sa) + base_mask) >> base_shift)); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_exclusion - template struct comp_op_rgba_exclusion - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type d1a = base_mask - p[Order::A]; - calc_type s1a = base_mask - sa; - calc_type dr = p[Order::R]; - calc_type dg = p[Order::G]; - calc_type db = p[Order::B]; - calc_type da = p[Order::A]; - p[Order::R] = (value_type)((sr*da + dr*sa - 2*sr*dr + sr*d1a + dr*s1a + base_mask) >> base_shift); - p[Order::G] = (value_type)((sg*da + dg*sa - 2*sg*dg + sg*d1a + dg*s1a + base_mask) >> base_shift); - p[Order::B] = (value_type)((sb*da + db*sa - 2*sb*db + sb*d1a + db*s1a + base_mask) >> base_shift); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=====================================================comp_op_rgba_contrast - template struct comp_op_rgba_contrast - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - long_type dr = p[Order::R]; - long_type dg = p[Order::G]; - long_type db = p[Order::B]; - int da = p[Order::A]; - long_type d2a = da >> 1; - unsigned s2a = sa >> 1; - - int r = (int)((((dr - d2a) * int((sr - s2a)*2 + base_mask)) >> base_shift) + d2a); - int g = (int)((((dg - d2a) * int((sg - s2a)*2 + base_mask)) >> base_shift) + d2a); - int b = (int)((((db - d2a) * int((sb - s2a)*2 + base_mask)) >> base_shift) + d2a); - - r = (r < 0) ? 0 : r; - g = (g < 0) ? 0 : g; - b = (b < 0) ? 0 : b; - - p[Order::R] = (value_type)((r > da) ? da : r); - p[Order::G] = (value_type)((g > da) ? da : g); - p[Order::B] = (value_type)((b > da) ? da : b); - } - }; - - //=====================================================comp_op_rgba_invert - template struct comp_op_rgba_invert - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = (Da - Dca) * Sa + Dca.(1 - Sa) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - sa = (sa * cover + 255) >> 8; - if(sa) - { - calc_type da = p[Order::A]; - calc_type dr = ((da - p[Order::R]) * sa + base_mask) >> base_shift; - calc_type dg = ((da - p[Order::G]) * sa + base_mask) >> base_shift; - calc_type db = ((da - p[Order::B]) * sa + base_mask) >> base_shift; - calc_type s1a = base_mask - sa; - p[Order::R] = (value_type)(dr + ((p[Order::R] * s1a + base_mask) >> base_shift)); - p[Order::G] = (value_type)(dg + ((p[Order::G] * s1a + base_mask) >> base_shift)); - p[Order::B] = (value_type)(db + ((p[Order::B] * s1a + base_mask) >> base_shift)); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - //=================================================comp_op_rgba_invert_rgb - template struct comp_op_rgba_invert_rgb - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - // Dca' = (Da - Dca) * Sca + Dca.(1 - Sa) - // Da' = Sa + Da - Sa.Da - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) - { - if(cover < 255) - { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; - } - if(sa) - { - calc_type da = p[Order::A]; - calc_type dr = ((da - p[Order::R]) * sr + base_mask) >> base_shift; - calc_type dg = ((da - p[Order::G]) * sg + base_mask) >> base_shift; - calc_type db = ((da - p[Order::B]) * sb + base_mask) >> base_shift; - calc_type s1a = base_mask - sa; - p[Order::R] = (value_type)(dr + ((p[Order::R] * s1a + base_mask) >> base_shift)); - p[Order::G] = (value_type)(dg + ((p[Order::G] * s1a + base_mask) >> base_shift)); - p[Order::B] = (value_type)(db + ((p[Order::B] * s1a + base_mask) >> base_shift)); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); - } - } - }; - - - - - - //======================================================comp_op_table_rgba - template struct comp_op_table_rgba - { - typedef typename ColorT::value_type value_type; - typedef void (*comp_op_func_type)(value_type* p, - unsigned cr, - unsigned cg, - unsigned cb, - unsigned ca, - unsigned cover); - static comp_op_func_type g_comp_op_func[]; - }; - - //==========================================================g_comp_op_func - template - typename comp_op_table_rgba::comp_op_func_type - comp_op_table_rgba::g_comp_op_func[] = - { - comp_op_rgba_clear ::blend_pix, - comp_op_rgba_src ::blend_pix, - comp_op_rgba_dst ::blend_pix, - comp_op_rgba_src_over ::blend_pix, - comp_op_rgba_dst_over ::blend_pix, - comp_op_rgba_src_in ::blend_pix, - comp_op_rgba_dst_in ::blend_pix, - comp_op_rgba_src_out ::blend_pix, - comp_op_rgba_dst_out ::blend_pix, - comp_op_rgba_src_atop ::blend_pix, - comp_op_rgba_dst_atop ::blend_pix, - comp_op_rgba_xor ::blend_pix, - comp_op_rgba_plus ::blend_pix, - comp_op_rgba_minus ::blend_pix, - comp_op_rgba_multiply ::blend_pix, - comp_op_rgba_screen ::blend_pix, - comp_op_rgba_overlay ::blend_pix, - comp_op_rgba_darken ::blend_pix, - comp_op_rgba_lighten ::blend_pix, - comp_op_rgba_color_dodge::blend_pix, - comp_op_rgba_color_burn ::blend_pix, - comp_op_rgba_hard_light ::blend_pix, - comp_op_rgba_soft_light ::blend_pix, - comp_op_rgba_difference ::blend_pix, - comp_op_rgba_exclusion ::blend_pix, - comp_op_rgba_contrast ::blend_pix, - comp_op_rgba_invert ::blend_pix, - comp_op_rgba_invert_rgb ::blend_pix, - 0 - }; - - - //==============================================================comp_op_e - enum comp_op_e - { - comp_op_clear, //----comp_op_clear - comp_op_src, //----comp_op_src - comp_op_dst, //----comp_op_dst - comp_op_src_over, //----comp_op_src_over - comp_op_dst_over, //----comp_op_dst_over - comp_op_src_in, //----comp_op_src_in - comp_op_dst_in, //----comp_op_dst_in - comp_op_src_out, //----comp_op_src_out - comp_op_dst_out, //----comp_op_dst_out - comp_op_src_atop, //----comp_op_src_atop - comp_op_dst_atop, //----comp_op_dst_atop - comp_op_xor, //----comp_op_xor - comp_op_plus, //----comp_op_plus - comp_op_minus, //----comp_op_minus - comp_op_multiply, //----comp_op_multiply - comp_op_screen, //----comp_op_screen - comp_op_overlay, //----comp_op_overlay - comp_op_darken, //----comp_op_darken - comp_op_lighten, //----comp_op_lighten - comp_op_color_dodge, //----comp_op_color_dodge - comp_op_color_burn, //----comp_op_color_burn - comp_op_hard_light, //----comp_op_hard_light - comp_op_soft_light, //----comp_op_soft_light - comp_op_difference, //----comp_op_difference - comp_op_exclusion, //----comp_op_exclusion - comp_op_contrast, //----comp_op_contrast - comp_op_invert, //----comp_op_invert - comp_op_invert_rgb, //----comp_op_invert_rgb - - end_of_comp_op_e - }; - - - - - - - - //====================================================comp_op_adaptor_rgba - template struct comp_op_adaptor_rgba - { - typedef Order order_type; - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) - { - comp_op_table_rgba::g_comp_op_func[op] - (p, (cr * ca + base_mask) >> base_shift, - (cg * ca + base_mask) >> base_shift, - (cb * ca + base_mask) >> base_shift, - ca, cover); - } - }; - - //=========================================comp_op_adaptor_clip_to_dst_rgba - template struct comp_op_adaptor_clip_to_dst_rgba - { - typedef Order order_type; - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) - { - cr = (cr * ca + base_mask) >> base_shift; - cg = (cg * ca + base_mask) >> base_shift; - cb = (cb * ca + base_mask) >> base_shift; - unsigned da = p[Order::A]; - comp_op_table_rgba::g_comp_op_func[op] - (p, (cr * da + base_mask) >> base_shift, - (cg * da + base_mask) >> base_shift, - (cb * da + base_mask) >> base_shift, - (ca * da + base_mask) >> base_shift, - cover); - } - }; - - //================================================comp_op_adaptor_rgba_pre - template struct comp_op_adaptor_rgba_pre - { - typedef Order order_type; - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) - { - comp_op_table_rgba::g_comp_op_func[op](p, cr, cg, cb, ca, cover); - } - }; - - //=====================================comp_op_adaptor_clip_to_dst_rgba_pre - template struct comp_op_adaptor_clip_to_dst_rgba_pre - { - typedef Order order_type; - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) - { - unsigned da = p[Order::A]; - comp_op_table_rgba::g_comp_op_func[op] - (p, (cr * da + base_mask) >> base_shift, - (cg * da + base_mask) >> base_shift, - (cb * da + base_mask) >> base_shift, - (ca * da + base_mask) >> base_shift, - cover); - } - }; - - //=======================================================comp_adaptor_rgba - template struct comp_adaptor_rgba - { - typedef typename BlenderPre::order_type order_type; - typedef typename BlenderPre::color_type color_type; - typedef typename color_type::value_type value_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) - { - BlenderPre::blend_pix(p, - (cr * ca + base_mask) >> base_shift, - (cg * ca + base_mask) >> base_shift, - (cb * ca + base_mask) >> base_shift, - ca, cover); - } - }; - - //==========================================comp_adaptor_clip_to_dst_rgba - template struct comp_adaptor_clip_to_dst_rgba - { - typedef typename BlenderPre::order_type order_type; - typedef typename BlenderPre::color_type color_type; - typedef typename color_type::value_type value_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) - { - cr = (cr * ca + base_mask) >> base_shift; - cg = (cg * ca + base_mask) >> base_shift; - cb = (cb * ca + base_mask) >> base_shift; - unsigned da = p[order_type::A]; - BlenderPre::blend_pix(p, - (cr * da + base_mask) >> base_shift, - (cg * da + base_mask) >> base_shift, - (cb * da + base_mask) >> base_shift, - (ca * da + base_mask) >> base_shift, - cover); - } - }; - - //======================================comp_adaptor_clip_to_dst_rgba_pre - template struct comp_adaptor_clip_to_dst_rgba_pre - { - typedef typename BlenderPre::order_type order_type; - typedef typename BlenderPre::color_type color_type; - typedef typename color_type::value_type value_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) - { - unsigned da = p[order_type::A]; - BlenderPre::blend_pix(p, - (cr * da + base_mask) >> base_shift, - (cg * da + base_mask) >> base_shift, - (cb * da + base_mask) >> base_shift, - (ca * da + base_mask) >> base_shift, - cover); - } - }; - - - - - - - //===============================================copy_or_blend_rgba_wrapper - template struct copy_or_blend_rgba_wrapper - { - typedef typename Blender::color_type color_type; - typedef typename Blender::order_type order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - static AGG_INLINE void copy_or_blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha) - { - if(alpha) - { - if(alpha == base_mask) - { - p[order_type::R] = cr; - p[order_type::G] = cg; - p[order_type::B] = cb; - p[order_type::A] = base_mask; - } - else - { - Blender::blend_pix(p, cr, cg, cb, alpha); - } - } - } - - //-------------------------------------------------------------------- - static AGG_INLINE void copy_or_blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - if(cover == 255) - { - copy_or_blend_pix(p, cr, cg, cb, alpha); - } - else - { - if(alpha) - { - alpha = (alpha * (cover + 1)) >> 8; - if(alpha == base_mask) - { - p[order_type::R] = cr; - p[order_type::G] = cg; - p[order_type::B] = cb; - p[order_type::A] = base_mask; - } - else - { - Blender::blend_pix(p, cr, cg, cb, alpha, cover); - } - } - } - } - }; - - - - - - - //=================================================pixfmt_alpha_blend_rgba - template - class pixfmt_alpha_blend_rgba - { - public: - typedef RenBuf rbuf_type; - typedef typename rbuf_type::row_data row_data; - typedef PixelT pixel_type; - typedef Blender blender_type; - typedef typename blender_type::color_type color_type; - typedef typename blender_type::order_type order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - typedef copy_or_blend_rgba_wrapper cob_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask, - pix_width = sizeof(pixel_type) - }; - - //-------------------------------------------------------------------- - pixfmt_alpha_blend_rgba() : m_rbuf(0) {} - explicit pixfmt_alpha_blend_rgba(rbuf_type& rb) : m_rbuf(&rb) {} - void attach(rbuf_type& rb) { m_rbuf = &rb; } - - //-------------------------------------------------------------------- - template - bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) - { - rect_i r(x1, y1, x2, y2); - if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) - { - int stride = pixf.stride(); - m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), - (r.x2 - r.x1) + 1, - (r.y2 - r.y1) + 1, - stride); - return true; - } - return false; - } - - //-------------------------------------------------------------------- - AGG_INLINE unsigned width() const { return m_rbuf->width(); } - AGG_INLINE unsigned height() const { return m_rbuf->height(); } - AGG_INLINE int stride() const { return m_rbuf->stride(); } - - //-------------------------------------------------------------------- - AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } - AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } - AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } - - //-------------------------------------------------------------------- - AGG_INLINE int8u* pix_ptr(int x, int y) - { - return m_rbuf->row_ptr(y) + x * pix_width; - } - - AGG_INLINE const int8u* pix_ptr(int x, int y) const - { - return m_rbuf->row_ptr(y) + x * pix_width; - } - - - //-------------------------------------------------------------------- - AGG_INLINE static void make_pix(int8u* p, const color_type& c) - { - ((value_type*)p)[order_type::R] = c.r; - ((value_type*)p)[order_type::G] = c.g; - ((value_type*)p)[order_type::B] = c.b; - ((value_type*)p)[order_type::A] = c.a; - } - - //-------------------------------------------------------------------- - AGG_INLINE color_type pixel(int x, int y) const - { - const value_type* p = (const value_type*)m_rbuf->row_ptr(y); - if(p) - { - p += x << 2; - return color_type(p[order_type::R], - p[order_type::G], - p[order_type::B], - p[order_type::A]); - } - return color_type::no_color(); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_pixel(int x, int y, const color_type& c) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, 1) + (x << 2); - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - p[order_type::A] = c.a; - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) - { - cob_type::copy_or_blend_pix( - (value_type*)m_rbuf->row_ptr(x, y, 1) + (x << 2), - c.r, c.g, c.b, c.a, - cover); - } - - - //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, - const color_type& c) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - pixel_type v; - ((value_type*)&v)[order_type::R] = c.r; - ((value_type*)&v)[order_type::G] = c.g; - ((value_type*)&v)[order_type::B] = c.b; - ((value_type*)&v)[order_type::A] = c.a; - do - { - *(pixel_type*)p = v; - p += 4; - } - while(--len); - } - - - //-------------------------------------------------------------------- - AGG_INLINE void copy_vline(int x, int y, - unsigned len, - const color_type& c) - { - pixel_type v; - ((value_type*)&v)[order_type::R] = c.r; - ((value_type*)&v)[order_type::G] = c.g; - ((value_type*)&v)[order_type::B] = c.b; - ((value_type*)&v)[order_type::A] = c.a; - do - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - *(pixel_type*)p = v; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void blend_hline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - if (c.a) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - pixel_type v; - ((value_type*)&v)[order_type::R] = c.r; - ((value_type*)&v)[order_type::G] = c.g; - ((value_type*)&v)[order_type::B] = c.b; - ((value_type*)&v)[order_type::A] = c.a; - do - { - *(pixel_type*)p = v; - p += 4; - } - while(--len); - } - else - { - if(cover == 255) - { - do - { - blender_type::blend_pix(p, c.r, c.g, c.b, alpha); - p += 4; - } - while(--len); - } - else - { - do - { - blender_type::blend_pix(p, c.r, c.g, c.b, alpha, cover); - p += 4; - } - while(--len); - } - } - } - } - - - //-------------------------------------------------------------------- - void blend_vline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - if (c.a) - { - value_type* p; - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - pixel_type v; - ((value_type*)&v)[order_type::R] = c.r; - ((value_type*)&v)[order_type::G] = c.g; - ((value_type*)&v)[order_type::B] = c.b; - ((value_type*)&v)[order_type::A] = c.a; - do - { - p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - *(pixel_type*)p = v; - } - while(--len); - } - else - { - if(cover == 255) - { - do - { - p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - blender_type::blend_pix(p, c.r, c.g, c.b, alpha); - } - while(--len); - } - else - { - do - { - p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - blender_type::blend_pix(p, c.r, c.g, c.b, alpha, cover); - } - while(--len); - } - } - } - } - - - //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - if (c.a) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do - { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - p[order_type::A] = base_mask; - } - else - { - blender_type::blend_pix(p, c.r, c.g, c.b, alpha, *covers); - } - p += 4; - ++covers; - } - while(--len); - } - } - - - //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - if (c.a) - { - do - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - p[order_type::A] = base_mask; - } - else - { - blender_type::blend_pix(p, c.r, c.g, c.b, alpha, *covers); - } - ++covers; - } - while(--len); - } - } - - - //-------------------------------------------------------------------- - void copy_color_hspan(int x, int y, - unsigned len, - const color_type* colors) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do - { - p[order_type::R] = colors->r; - p[order_type::G] = colors->g; - p[order_type::B] = colors->b; - p[order_type::A] = colors->a; - ++colors; - p += 4; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void copy_color_vspan(int x, int y, - unsigned len, - const color_type* colors) - { - do - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - p[order_type::R] = colors->r; - p[order_type::G] = colors->g; - p[order_type::B] = colors->b; - p[order_type::A] = colors->a; - ++colors; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - if(covers) - { - do - { - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a, - *covers++); - p += 4; - ++colors; - } - while(--len); - } - else - { - if(cover == 255) - { - do - { - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a); - p += 4; - ++colors; - } - while(--len); - } - else - { - do - { - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a, - cover); - p += 4; - ++colors; - } - while(--len); - } - } - } - - - - //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - value_type* p; - if(covers) - { - do - { - p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a, - *covers++); - ++colors; - } - while(--len); - } - else - { - if(cover == 255) - { - do - { - p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a); - ++colors; - } - while(--len); - } - else - { - do - { - p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a, - cover); - ++colors; - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - template void for_each_pixel(Function f) - { - unsigned y; - for(y = 0; y < height(); ++y) - { - row_data r = m_rbuf->row(y); - if(r.ptr) - { - unsigned len = r.x2 - r.x1 + 1; - value_type* p = - (value_type*)m_rbuf->row_ptr(r.x1, y, len) + (r.x1 << 2); - do - { - f(p); - p += 4; - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - void premultiply() - { - for_each_pixel(multiplier_rgba::premultiply); - } - - //-------------------------------------------------------------------- - void demultiply() - { - for_each_pixel(multiplier_rgba::demultiply); - } - - //-------------------------------------------------------------------- - template void apply_gamma_dir(const GammaLut& g) - { - for_each_pixel(apply_gamma_dir_rgba(g)); - } - - //-------------------------------------------------------------------- - template void apply_gamma_inv(const GammaLut& g) - { - for_each_pixel(apply_gamma_inv_rgba(g)); - } - - //-------------------------------------------------------------------- - template void copy_from(const RenBuf2& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len) - { - const int8u* p = from.row_ptr(ysrc); - if(p) - { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, - len * pix_width); - } - } - - //-------------------------------------------------------------------- - template - void blend_from(const SrcPixelFormatRenderer& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::order_type src_order; - const value_type* psrc = (value_type*)from.row_ptr(ysrc); - if(psrc) - { - psrc += xsrc << 2; - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); - int incp = 4; - if(xdst > xsrc) - { - psrc += (len-1) << 2; - pdst += (len-1) << 2; - incp = -4; - } - - if(cover == 255) - { - do - { - cob_type::copy_or_blend_pix(pdst, - psrc[src_order::R], - psrc[src_order::G], - psrc[src_order::B], - psrc[src_order::A]); - psrc += incp; - pdst += incp; - } - while(--len); - } - else - { - do - { - cob_type::copy_or_blend_pix(pdst, - psrc[src_order::R], - psrc[src_order::G], - psrc[src_order::B], - psrc[src_order::A], - cover); - psrc += incp; - pdst += incp; - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - template - void blend_from_color(const SrcPixelFormatRenderer& from, - const color_type& color, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); - do - { - cob_type::copy_or_blend_pix(pdst, - color.r, color.g, color.b, color.a, - (*psrc * cover + base_mask) >> base_shift); - ++psrc; - pdst += 4; - } - while(--len); - } - } - - //-------------------------------------------------------------------- - template - void blend_from_lut(const SrcPixelFormatRenderer& from, - const color_type* color_lut, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); - - if(cover == 255) - { - do - { - const color_type& color = color_lut[*psrc]; - cob_type::copy_or_blend_pix(pdst, - color.r, color.g, color.b, color.a); - ++psrc; - pdst += 4; - } - while(--len); - } - else - { - do - { - const color_type& color = color_lut[*psrc]; - cob_type::copy_or_blend_pix(pdst, - color.r, color.g, color.b, color.a, - cover); - ++psrc; - pdst += 4; - } - while(--len); - } - } - } - - private: - rbuf_type* m_rbuf; - }; - - - - - //================================================pixfmt_custom_blend_rgba - template class pixfmt_custom_blend_rgba - { - public: - typedef RenBuf rbuf_type; - typedef typename rbuf_type::row_data row_data; - typedef Blender blender_type; - typedef typename blender_type::color_type color_type; - typedef typename blender_type::order_type order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask, - pix_width = sizeof(value_type) * 4 - }; - - - //-------------------------------------------------------------------- - pixfmt_custom_blend_rgba() : m_rbuf(0), m_comp_op(3) {} - explicit pixfmt_custom_blend_rgba(rbuf_type& rb, unsigned comp_op=3) : - m_rbuf(&rb), - m_comp_op(comp_op) - {} - void attach(rbuf_type& rb) { m_rbuf = &rb; } - - //-------------------------------------------------------------------- - template - bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) - { - rect_i r(x1, y1, x2, y2); - if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) - { - int stride = pixf.stride(); - m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), - (r.x2 - r.x1) + 1, - (r.y2 - r.y1) + 1, - stride); - return true; - } - return false; - } - - //-------------------------------------------------------------------- - AGG_INLINE unsigned width() const { return m_rbuf->width(); } - AGG_INLINE unsigned height() const { return m_rbuf->height(); } - AGG_INLINE int stride() const { return m_rbuf->stride(); } - - //-------------------------------------------------------------------- - AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } - AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } - AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } - - //-------------------------------------------------------------------- - AGG_INLINE int8u* pix_ptr(int x, int y) - { - return m_rbuf->row_ptr(y) + x * pix_width; - } - - AGG_INLINE const int8u* pix_ptr(int x, int y) const - { - return m_rbuf->row_ptr(y) + x * pix_width; - } - - //-------------------------------------------------------------------- - void comp_op(unsigned op) { m_comp_op = op; } - unsigned comp_op() const { return m_comp_op; } - - //-------------------------------------------------------------------- - AGG_INLINE static void make_pix(int8u* p, const color_type& c) - { - ((value_type*)p)[order_type::R] = c.r; - ((value_type*)p)[order_type::G] = c.g; - ((value_type*)p)[order_type::B] = c.b; - ((value_type*)p)[order_type::A] = c.a; - } - - //-------------------------------------------------------------------- - color_type pixel(int x, int y) const - { - const value_type* p = (value_type*)m_rbuf->row_ptr(y) + (x << 2); - return color_type(p[order_type::R], - p[order_type::G], - p[order_type::B], - p[order_type::A]); - } - - //-------------------------------------------------------------------- - void copy_pixel(int x, int y, const color_type& c) - { - blender_type::blend_pix( - m_comp_op, - (value_type*)m_rbuf->row_ptr(x, y, 1) + (x << 2), - c.r, c.g, c.b, c.a, 255); - } - - //-------------------------------------------------------------------- - void blend_pixel(int x, int y, const color_type& c, int8u cover) - { - blender_type::blend_pix( - m_comp_op, - (value_type*)m_rbuf->row_ptr(x, y, 1) + (x << 2), - c.r, c.g, c.b, c.a, - cover); - } - - //-------------------------------------------------------------------- - void copy_hline(int x, int y, unsigned len, const color_type& c) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2);; - do - { - blender_type::blend_pix(m_comp_op, p, c.r, c.g, c.b, c.a, 255); - p += 4; - } - while(--len); - } - - //-------------------------------------------------------------------- - void copy_vline(int x, int y, unsigned len, const color_type& c) - { - do - { - blender_type::blend_pix( - m_comp_op, - (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2), - c.r, c.g, c.b, c.a, 255); - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_hline(int x, int y, unsigned len, - const color_type& c, int8u cover) - { - - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do - { - blender_type::blend_pix(m_comp_op, p, c.r, c.g, c.b, c.a, cover); - p += 4; - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_vline(int x, int y, unsigned len, - const color_type& c, int8u cover) - { - - do - { - blender_type::blend_pix( - m_comp_op, - (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2), - c.r, c.g, c.b, c.a, - cover); - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, unsigned len, - const color_type& c, const int8u* covers) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do - { - blender_type::blend_pix(m_comp_op, - p, c.r, c.g, c.b, c.a, - *covers++); - p += 4; - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, unsigned len, - const color_type& c, const int8u* covers) - { - do - { - blender_type::blend_pix( - m_comp_op, - (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2), - c.r, c.g, c.b, c.a, - *covers++); - } - while(--len); - } - - //-------------------------------------------------------------------- - void copy_color_hspan(int x, int y, - unsigned len, - const color_type* colors) - { - - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do - { - p[order_type::R] = colors->r; - p[order_type::G] = colors->g; - p[order_type::B] = colors->b; - p[order_type::A] = colors->a; - ++colors; - p += 4; - } - while(--len); - } - - //-------------------------------------------------------------------- - void copy_color_vspan(int x, int y, - unsigned len, - const color_type* colors) - { - do - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - p[order_type::R] = colors->r; - p[order_type::G] = colors->g; - p[order_type::B] = colors->b; - p[order_type::A] = colors->a; - ++colors; - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do - { - blender_type::blend_pix(m_comp_op, - p, - colors->r, - colors->g, - colors->b, - colors->a, - covers ? *covers++ : cover); - p += 4; - ++colors; - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - do - { - blender_type::blend_pix( - m_comp_op, - (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2), - colors->r, - colors->g, - colors->b, - colors->a, - covers ? *covers++ : cover); - ++colors; - } - while(--len); - - } - - //-------------------------------------------------------------------- - template void for_each_pixel(Function f) - { - unsigned y; - for(y = 0; y < height(); ++y) - { - row_data r = m_rbuf->row(y); - if(r.ptr) - { - unsigned len = r.x2 - r.x1 + 1; - value_type* p = - (value_type*)m_rbuf->row_ptr(r.x1, y, len) + (r.x1 << 2); - do - { - f(p); - p += 4; - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - void premultiply() - { - for_each_pixel(multiplier_rgba::premultiply); - } - - //-------------------------------------------------------------------- - void demultiply() - { - for_each_pixel(multiplier_rgba::demultiply); - } - - //-------------------------------------------------------------------- - template void apply_gamma_dir(const GammaLut& g) - { - for_each_pixel(apply_gamma_dir_rgba(g)); - } - - //-------------------------------------------------------------------- - template void apply_gamma_inv(const GammaLut& g) - { - for_each_pixel(apply_gamma_inv_rgba(g)); - } - - //-------------------------------------------------------------------- - template void copy_from(const RenBuf2& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len) - { - const int8u* p = from.row_ptr(ysrc); - if(p) - { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, - len * pix_width); - } - } - - //-------------------------------------------------------------------- - template - void blend_from(const SrcPixelFormatRenderer& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::order_type src_order; - const value_type* psrc = (const value_type*)from.row_ptr(ysrc); - if(psrc) - { - psrc += xsrc << 2; - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); - - int incp = 4; - if(xdst > xsrc) - { - psrc += (len-1) << 2; - pdst += (len-1) << 2; - incp = -4; - } - - do - { - blender_type::blend_pix(m_comp_op, - pdst, - psrc[src_order::R], - psrc[src_order::G], - psrc[src_order::B], - psrc[src_order::A], - cover); - psrc += incp; - pdst += incp; - } - while(--len); - } - } - - //-------------------------------------------------------------------- - template - void blend_from_color(const SrcPixelFormatRenderer& from, - const color_type& color, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); - do - { - blender_type::blend_pix(m_comp_op, - pdst, - color.r, color.g, color.b, color.a, - (*psrc * cover + base_mask) >> base_shift); - ++psrc; - pdst += 4; - } - while(--len); - } - } - - //-------------------------------------------------------------------- - template - void blend_from_lut(const SrcPixelFormatRenderer& from, - const color_type* color_lut, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); - do - { - const color_type& color = color_lut[*psrc]; - blender_type::blend_pix(m_comp_op, - pdst, - color.r, color.g, color.b, color.a, - cover); - ++psrc; - pdst += 4; - } - while(--len); - } - } - - private: - rbuf_type* m_rbuf; - unsigned m_comp_op; - }; - - - - - //----------------------------------------------------------------------- - typedef blender_rgba blender_rgba32; //----blender_rgba32 - typedef blender_rgba blender_argb32; //----blender_argb32 - typedef blender_rgba blender_abgr32; //----blender_abgr32 - typedef blender_rgba blender_bgra32; //----blender_bgra32 - - typedef blender_rgba_pre blender_rgba32_pre; //----blender_rgba32_pre - typedef blender_rgba_pre blender_argb32_pre; //----blender_argb32_pre - typedef blender_rgba_pre blender_abgr32_pre; //----blender_abgr32_pre - typedef blender_rgba_pre blender_bgra32_pre; //----blender_bgra32_pre - - typedef blender_rgba_plain blender_rgba32_plain; //----blender_rgba32_plain - typedef blender_rgba_plain blender_argb32_plain; //----blender_argb32_plain - typedef blender_rgba_plain blender_abgr32_plain; //----blender_abgr32_plain - typedef blender_rgba_plain blender_bgra32_plain; //----blender_bgra32_plain - - typedef blender_rgba blender_rgba64; //----blender_rgba64 - typedef blender_rgba blender_argb64; //----blender_argb64 - typedef blender_rgba blender_abgr64; //----blender_abgr64 - typedef blender_rgba blender_bgra64; //----blender_bgra64 - - typedef blender_rgba_pre blender_rgba64_pre; //----blender_rgba64_pre - typedef blender_rgba_pre blender_argb64_pre; //----blender_argb64_pre - typedef blender_rgba_pre blender_abgr64_pre; //----blender_abgr64_pre - typedef blender_rgba_pre blender_bgra64_pre; //----blender_bgra64_pre - - - //----------------------------------------------------------------------- - typedef int32u pixel32_type; - typedef pixfmt_alpha_blend_rgba pixfmt_rgba32; //----pixfmt_rgba32 - typedef pixfmt_alpha_blend_rgba pixfmt_argb32; //----pixfmt_argb32 - typedef pixfmt_alpha_blend_rgba pixfmt_abgr32; //----pixfmt_abgr32 - typedef pixfmt_alpha_blend_rgba pixfmt_bgra32; //----pixfmt_bgra32 - - typedef pixfmt_alpha_blend_rgba pixfmt_rgba32_pre; //----pixfmt_rgba32_pre - typedef pixfmt_alpha_blend_rgba pixfmt_argb32_pre; //----pixfmt_argb32_pre - typedef pixfmt_alpha_blend_rgba pixfmt_abgr32_pre; //----pixfmt_abgr32_pre - typedef pixfmt_alpha_blend_rgba pixfmt_bgra32_pre; //----pixfmt_bgra32_pre - - typedef pixfmt_alpha_blend_rgba pixfmt_rgba32_plain; //----pixfmt_rgba32_plain - typedef pixfmt_alpha_blend_rgba pixfmt_argb32_plain; //----pixfmt_argb32_plain - typedef pixfmt_alpha_blend_rgba pixfmt_abgr32_plain; //----pixfmt_abgr32_plain - typedef pixfmt_alpha_blend_rgba pixfmt_bgra32_plain; //----pixfmt_bgra32_plain - - struct pixel64_type { int16u c[4]; }; - typedef pixfmt_alpha_blend_rgba pixfmt_rgba64; //----pixfmt_rgba64 - typedef pixfmt_alpha_blend_rgba pixfmt_argb64; //----pixfmt_argb64 - typedef pixfmt_alpha_blend_rgba pixfmt_abgr64; //----pixfmt_abgr64 - typedef pixfmt_alpha_blend_rgba pixfmt_bgra64; //----pixfmt_bgra64 - - typedef pixfmt_alpha_blend_rgba pixfmt_rgba64_pre; //----pixfmt_rgba64_pre - typedef pixfmt_alpha_blend_rgba pixfmt_argb64_pre; //----pixfmt_argb64_pre - typedef pixfmt_alpha_blend_rgba pixfmt_abgr64_pre; //----pixfmt_abgr64_pre - typedef pixfmt_alpha_blend_rgba pixfmt_bgra64_pre; //----pixfmt_bgra64_pre -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_pixfmt_rgb.h corsix-th-0.62/agg/include/agg_pixfmt_rgb.h --- corsix-th-0.30/agg/include/agg_pixfmt_rgb.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_pixfmt_rgb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,860 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_PIXFMT_RGB_INCLUDED -#define AGG_PIXFMT_RGB_INCLUDED - -#include -#include "agg_basics.h" -#include "agg_color_rgba.h" -#include "agg_rendering_buffer.h" - -namespace agg -{ - - //=====================================================apply_gamma_dir_rgb - template class apply_gamma_dir_rgb - { - public: - typedef typename ColorT::value_type value_type; - - apply_gamma_dir_rgb(const GammaLut& gamma) : m_gamma(gamma) {} - - AGG_INLINE void operator () (value_type* p) - { - p[Order::R] = m_gamma.dir(p[Order::R]); - p[Order::G] = m_gamma.dir(p[Order::G]); - p[Order::B] = m_gamma.dir(p[Order::B]); - } - - private: - const GammaLut& m_gamma; - }; - - - - //=====================================================apply_gamma_inv_rgb - template class apply_gamma_inv_rgb - { - public: - typedef typename ColorT::value_type value_type; - - apply_gamma_inv_rgb(const GammaLut& gamma) : m_gamma(gamma) {} - - AGG_INLINE void operator () (value_type* p) - { - p[Order::R] = m_gamma.inv(p[Order::R]); - p[Order::G] = m_gamma.inv(p[Order::G]); - p[Order::B] = m_gamma.inv(p[Order::B]); - } - - private: - const GammaLut& m_gamma; - }; - - - //=========================================================blender_rgb - template struct blender_rgb - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e { base_shift = color_type::base_shift }; - - //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover=0) - { - p[Order::R] += (value_type)(((cr - p[Order::R]) * alpha) >> base_shift); - p[Order::G] += (value_type)(((cg - p[Order::G]) * alpha) >> base_shift); - p[Order::B] += (value_type)(((cb - p[Order::B]) * alpha) >> base_shift); - } - }; - - - //======================================================blender_rgb_pre - template struct blender_rgb_pre - { - typedef ColorT color_type; - typedef Order order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e { base_shift = color_type::base_shift }; - - //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - alpha = color_type::base_mask - alpha; - cover = (cover + 1) << (base_shift - 8); - p[Order::R] = (value_type)((p[Order::R] * alpha + cr * cover) >> base_shift); - p[Order::G] = (value_type)((p[Order::G] * alpha + cg * cover) >> base_shift); - p[Order::B] = (value_type)((p[Order::B] * alpha + cb * cover) >> base_shift); - } - - //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha) - { - alpha = color_type::base_mask - alpha; - p[Order::R] = (value_type)(((p[Order::R] * alpha) >> base_shift) + cr); - p[Order::G] = (value_type)(((p[Order::G] * alpha) >> base_shift) + cg); - p[Order::B] = (value_type)(((p[Order::B] * alpha) >> base_shift) + cb); - } - - }; - - - - //===================================================blender_rgb_gamma - template class blender_rgb_gamma - { - public: - typedef ColorT color_type; - typedef Order order_type; - typedef Gamma gamma_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e { base_shift = color_type::base_shift }; - - //-------------------------------------------------------------------- - blender_rgb_gamma() : m_gamma(0) {} - void gamma(const gamma_type& g) { m_gamma = &g; } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover=0) - { - calc_type r = m_gamma->dir(p[Order::R]); - calc_type g = m_gamma->dir(p[Order::G]); - calc_type b = m_gamma->dir(p[Order::B]); - p[Order::R] = m_gamma->inv((((m_gamma->dir(cr) - r) * alpha) >> base_shift) + r); - p[Order::G] = m_gamma->inv((((m_gamma->dir(cg) - g) * alpha) >> base_shift) + g); - p[Order::B] = m_gamma->inv((((m_gamma->dir(cb) - b) * alpha) >> base_shift) + b); - } - - private: - const gamma_type* m_gamma; - }; - - - - - //==================================================pixfmt_alpha_blend_rgb - template class pixfmt_alpha_blend_rgb - { - public: - typedef RenBuf rbuf_type; - typedef Blender blender_type; - typedef typename rbuf_type::row_data row_data; - typedef typename blender_type::color_type color_type; - typedef typename blender_type::order_type order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask, - pix_width = sizeof(value_type) * 3 - }; - - private: - //-------------------------------------------------------------------- - AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c, - unsigned cover) - { - if (c.a) - { - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - } - else - { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); - } - } - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c) - { - if (c.a) - { - if(c.a == base_mask) - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - } - else - { - m_blender.blend_pix(p, c.r, c.g, c.b, c.a); - } - } - } - - - public: - //-------------------------------------------------------------------- - explicit pixfmt_alpha_blend_rgb(rbuf_type& rb) : - m_rbuf(&rb) - {} - void attach(rbuf_type& rb) { m_rbuf = &rb; } - - //-------------------------------------------------------------------- - template - bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) - { - rect_i r(x1, y1, x2, y2); - if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) - { - int stride = pixf.stride(); - m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), - (r.x2 - r.x1) + 1, - (r.y2 - r.y1) + 1, - stride); - return true; - } - return false; - } - - //-------------------------------------------------------------------- - Blender& blender() { return m_blender; } - - //-------------------------------------------------------------------- - AGG_INLINE unsigned width() const { return m_rbuf->width(); } - AGG_INLINE unsigned height() const { return m_rbuf->height(); } - AGG_INLINE int stride() const { return m_rbuf->stride(); } - - //-------------------------------------------------------------------- - AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } - AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } - AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } - - //-------------------------------------------------------------------- - AGG_INLINE int8u* pix_ptr(int x, int y) - { - return m_rbuf->row_ptr(y) + x * pix_width; - } - - AGG_INLINE const int8u* pix_ptr(int x, int y) const - { - return m_rbuf->row_ptr(y) + x * pix_width; - } - - //-------------------------------------------------------------------- - AGG_INLINE static void make_pix(int8u* p, const color_type& c) - { - ((value_type*)p)[order_type::R] = c.r; - ((value_type*)p)[order_type::G] = c.g; - ((value_type*)p)[order_type::B] = c.b; - } - - //-------------------------------------------------------------------- - AGG_INLINE color_type pixel(int x, int y) const - { - value_type* p = (value_type*)m_rbuf->row_ptr(y) + x + x + x; - return color_type(p[order_type::R], - p[order_type::G], - p[order_type::B]); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_pixel(int x, int y, const color_type& c) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, 1) + x + x + x; - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) - { - copy_or_blend_pix((value_type*)m_rbuf->row_ptr(x, y, 1) + x + x + x, c, cover); - } - - - //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, - const color_type& c) - { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + x + x + x; - do - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - p += 3; - } - while(--len); - } - - - //-------------------------------------------------------------------- - AGG_INLINE void copy_vline(int x, int y, - unsigned len, - const color_type& c) - { - do - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void blend_hline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - if (c.a) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x + x + x; - - calc_type alpha = (calc_type(c.a) * (calc_type(cover) + 1)) >> 8; - if(alpha == base_mask) - { - do - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - p += 3; - } - while(--len); - } - else - { - do - { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); - p += 3; - } - while(--len); - } - } - } - - - //-------------------------------------------------------------------- - void blend_vline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - if (c.a) - { - value_type* p; - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - } - while(--len); - } - else - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); - } - while(--len); - } - } - } - - - //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - if (c.a) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x + x + x; - - do - { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - } - else - { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, *covers); - } - p += 3; - ++covers; - } - while(--len); - } - } - - - //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - if (c.a) - { - do - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - } - else - { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, *covers); - } - ++covers; - } - while(--len); - } - } - - - //-------------------------------------------------------------------- - void copy_color_hspan(int x, int y, - unsigned len, - const color_type* colors) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x + x + x; - - do - { - p[order_type::R] = colors->r; - p[order_type::G] = colors->g; - p[order_type::B] = colors->b; - ++colors; - p += 3; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void copy_color_vspan(int x, int y, - unsigned len, - const color_type* colors) - { - do - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - p[order_type::R] = colors->r; - p[order_type::G] = colors->g; - p[order_type::B] = colors->b; - ++colors; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x + x + x; - - if(covers) - { - do - { - copy_or_blend_pix(p, *colors++, *covers++); - p += 3; - } - while(--len); - } - else - { - if(cover == 255) - { - do - { - copy_or_blend_pix(p, *colors++); - p += 3; - } - while(--len); - } - else - { - do - { - copy_or_blend_pix(p, *colors++, cover); - p += 3; - } - while(--len); - } - } - } - - - - //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - value_type* p; - if(covers) - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - copy_or_blend_pix(p, *colors++, *covers++); - } - while(--len); - } - else - { - if(cover == 255) - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - copy_or_blend_pix(p, *colors++); - } - while(--len); - } - else - { - do - { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - copy_or_blend_pix(p, *colors++, cover); - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - template void for_each_pixel(Function f) - { - unsigned y; - for(y = 0; y < height(); ++y) - { - row_data r = m_rbuf->row(y); - if(r.ptr) - { - unsigned len = r.x2 - r.x1 + 1; - value_type* p = (value_type*) - m_rbuf->row_ptr(r.x1, y, len) + r.x1 * 3; - do - { - f(p); - p += 3; - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - template void apply_gamma_dir(const GammaLut& g) - { - for_each_pixel(apply_gamma_dir_rgb(g)); - } - - //-------------------------------------------------------------------- - template void apply_gamma_inv(const GammaLut& g) - { - for_each_pixel(apply_gamma_inv_rgb(g)); - } - - //-------------------------------------------------------------------- - template - void copy_from(const RenBuf2& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len) - { - const int8u* p = from.row_ptr(ysrc); - if(p) - { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, - len * pix_width); - } - } - - - //-------------------------------------------------------------------- - template - void blend_from(const SrcPixelFormatRenderer& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::order_type src_order; - - const value_type* psrc = (const value_type*)from.row_ptr(ysrc); - if(psrc) - { - psrc += xsrc * 4; - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst * 3; - - if(cover == 255) - { - do - { - value_type alpha = psrc[src_order::A]; - if(alpha) - { - if(alpha == base_mask) - { - pdst[order_type::R] = psrc[src_order::R]; - pdst[order_type::G] = psrc[src_order::G]; - pdst[order_type::B] = psrc[src_order::B]; - } - else - { - m_blender.blend_pix(pdst, - psrc[src_order::R], - psrc[src_order::G], - psrc[src_order::B], - alpha); - } - } - psrc += 4; - pdst += 3; - } - while(--len); - } - else - { - color_type color; - do - { - color.r = psrc[src_order::R]; - color.g = psrc[src_order::G]; - color.b = psrc[src_order::B]; - color.a = psrc[src_order::A]; - copy_or_blend_pix(pdst, color, cover); - psrc += 4; - pdst += 3; - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - template - void blend_from_color(const SrcPixelFormatRenderer& from, - const color_type& color, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst * 3; - do - { - copy_or_blend_pix(pdst, - color, - (*psrc * cover + base_mask) >> base_shift); - ++psrc; - pdst += 3; - } - while(--len); - } - } - - //-------------------------------------------------------------------- - template - void blend_from_lut(const SrcPixelFormatRenderer& from, - const color_type* color_lut, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst * 3; - - if(cover == 255) - { - do - { - const color_type& color = color_lut[*psrc]; - m_blender.blend_pix(pdst, - color.r, color.g, color.b, color.a); - ++psrc; - pdst += 3; - } - while(--len); - } - else - { - do - { - copy_or_blend_pix(pdst, color_lut[*psrc], cover); - ++psrc; - pdst += 3; - } - while(--len); - } - } - } - - private: - rbuf_type* m_rbuf; - Blender m_blender; - }; - - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_rgb24; //----pixfmt_rgb24 - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_bgr24; //----pixfmt_bgr24 - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_rgb48; //----pixfmt_rgb48 - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_bgr48; //----pixfmt_bgr48 - - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_rgb24_pre; //----pixfmt_rgb24_pre - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_bgr24_pre; //----pixfmt_bgr24_pre - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_rgb48_pre; //----pixfmt_rgb48_pre - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_bgr48_pre; //----pixfmt_bgr48_pre - - //-----------------------------------------------------pixfmt_rgb24_gamma - template class pixfmt_rgb24_gamma : - public pixfmt_alpha_blend_rgb, rendering_buffer> - { - public: - pixfmt_rgb24_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - //-----------------------------------------------------pixfmt_bgr24_gamma - template class pixfmt_bgr24_gamma : - public pixfmt_alpha_blend_rgb, rendering_buffer> - { - public: - pixfmt_bgr24_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - //-----------------------------------------------------pixfmt_rgb48_gamma - template class pixfmt_rgb48_gamma : - public pixfmt_alpha_blend_rgb, rendering_buffer> - { - public: - pixfmt_rgb48_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - //-----------------------------------------------------pixfmt_bgr48_gamma - template class pixfmt_bgr48_gamma : - public pixfmt_alpha_blend_rgb, rendering_buffer> - { - public: - pixfmt_bgr48_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_pixfmt_rgb_packed.h corsix-th-0.62/agg/include/agg_pixfmt_rgb_packed.h --- corsix-th-0.30/agg/include/agg_pixfmt_rgb_packed.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_pixfmt_rgb_packed.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1309 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_PIXFMT_RGB_PACKED_INCLUDED -#define AGG_PIXFMT_RGB_PACKED_INCLUDED - -#include -#include "agg_basics.h" -#include "agg_color_rgba.h" -#include "agg_rendering_buffer.h" - -namespace agg -{ - //=========================================================blender_rgb555 - struct blender_rgb555 - { - typedef rgba8 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int16u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type rgb = *p; - calc_type r = (rgb >> 7) & 0xF8; - calc_type g = (rgb >> 2) & 0xF8; - calc_type b = (rgb << 3) & 0xF8; - *p = (pixel_type) - (((((cr - r) * alpha + (r << 8)) >> 1) & 0x7C00) | - ((((cg - g) * alpha + (g << 8)) >> 6) & 0x03E0) | - (((cb - b) * alpha + (b << 8)) >> 11) | 0x8000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xF8) << 7) | - ((g & 0xF8) << 2) | - (b >> 3) | 0x8000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 7) & 0xF8, - (p >> 2) & 0xF8, - (p << 3) & 0xF8); - } - }; - - - //=====================================================blender_rgb555_pre - struct blender_rgb555_pre - { - typedef rgba8 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int16u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - alpha = color_type::base_mask - alpha; - pixel_type rgb = *p; - calc_type r = (rgb >> 7) & 0xF8; - calc_type g = (rgb >> 2) & 0xF8; - calc_type b = (rgb << 3) & 0xF8; - *p = (pixel_type) - ((((r * alpha + cr * cover) >> 1) & 0x7C00) | - (((g * alpha + cg * cover) >> 6) & 0x03E0) | - ((b * alpha + cb * cover) >> 11) | 0x8000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xF8) << 7) | - ((g & 0xF8) << 2) | - (b >> 3) | 0x8000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 7) & 0xF8, - (p >> 2) & 0xF8, - (p << 3) & 0xF8); - } - }; - - - - - //=====================================================blender_rgb555_gamma - template class blender_rgb555_gamma - { - public: - typedef rgba8 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int16u pixel_type; - typedef Gamma gamma_type; - - blender_rgb555_gamma() : m_gamma(0) {} - void gamma(const gamma_type& g) { m_gamma = &g; } - - AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type rgb = *p; - calc_type r = m_gamma->dir((rgb >> 7) & 0xF8); - calc_type g = m_gamma->dir((rgb >> 2) & 0xF8); - calc_type b = m_gamma->dir((rgb << 3) & 0xF8); - *p = (pixel_type) - (((m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 8)) >> 8) << 7) & 0x7C00) | - ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 8)) >> 8) << 2) & 0x03E0) | - (m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 8)) >> 8) >> 3) | 0x8000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xF8) << 7) | - ((g & 0xF8) << 2) | - (b >> 3) | 0x8000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 7) & 0xF8, - (p >> 2) & 0xF8, - (p << 3) & 0xF8); - } - - private: - const Gamma* m_gamma; - }; - - - - - - //=========================================================blender_rgb565 - struct blender_rgb565 - { - typedef rgba8 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int16u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type rgb = *p; - calc_type r = (rgb >> 8) & 0xF8; - calc_type g = (rgb >> 3) & 0xFC; - calc_type b = (rgb << 3) & 0xF8; - *p = (pixel_type) - (((((cr - r) * alpha + (r << 8)) ) & 0xF800) | - ((((cg - g) * alpha + (g << 8)) >> 5) & 0x07E0) | - (((cb - b) * alpha + (b << 8)) >> 11)); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 8) & 0xF8, - (p >> 3) & 0xFC, - (p << 3) & 0xF8); - } - }; - - - - //=====================================================blender_rgb565_pre - struct blender_rgb565_pre - { - typedef rgba8 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int16u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - alpha = color_type::base_mask - alpha; - pixel_type rgb = *p; - calc_type r = (rgb >> 8) & 0xF8; - calc_type g = (rgb >> 3) & 0xFC; - calc_type b = (rgb << 3) & 0xF8; - *p = (pixel_type) - ((((r * alpha + cr * cover) ) & 0xF800) | - (((g * alpha + cg * cover) >> 5 ) & 0x07E0) | - ((b * alpha + cb * cover) >> 11)); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 8) & 0xF8, - (p >> 3) & 0xFC, - (p << 3) & 0xF8); - } - }; - - - - //=====================================================blender_rgb565_gamma - template class blender_rgb565_gamma - { - public: - typedef rgba8 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int16u pixel_type; - typedef Gamma gamma_type; - - blender_rgb565_gamma() : m_gamma(0) {} - void gamma(const gamma_type& g) { m_gamma = &g; } - - AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type rgb = *p; - calc_type r = m_gamma->dir((rgb >> 8) & 0xF8); - calc_type g = m_gamma->dir((rgb >> 3) & 0xFC); - calc_type b = m_gamma->dir((rgb << 3) & 0xF8); - *p = (pixel_type) - (((m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 8)) >> 8) << 8) & 0xF800) | - ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 8)) >> 8) << 3) & 0x07E0) | - (m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 8)) >> 8) >> 3)); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 8) & 0xF8, - (p >> 3) & 0xFC, - (p << 3) & 0xF8); - } - - private: - const Gamma* m_gamma; - }; - - - - //=====================================================blender_rgbAAA - struct blender_rgbAAA - { - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type rgb = *p; - calc_type r = (rgb >> 14) & 0xFFC0; - calc_type g = (rgb >> 4) & 0xFFC0; - calc_type b = (rgb << 6) & 0xFFC0; - *p = (pixel_type) - (((((cr - r) * alpha + (r << 16)) >> 2) & 0x3FF00000) | - ((((cg - g) * alpha + (g << 16)) >> 12) & 0x000FFC00) | - (((cb - b) * alpha + (b << 16)) >> 22) | 0xC0000000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xFFC0) << 14) | - ((g & 0xFFC0) << 4) | - (b >> 6) | 0xC0000000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 14) & 0xFFC0, - (p >> 4) & 0xFFC0, - (p << 6) & 0xFFC0); - } - }; - - - - //==================================================blender_rgbAAA_pre - struct blender_rgbAAA_pre - { - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - alpha = color_type::base_mask - alpha; - cover = (cover + 1) << (color_type::base_shift - 8); - pixel_type rgb = *p; - calc_type r = (rgb >> 14) & 0xFFC0; - calc_type g = (rgb >> 4) & 0xFFC0; - calc_type b = (rgb << 6) & 0xFFC0; - *p = (pixel_type) - ((((r * alpha + cr * cover) >> 2) & 0x3FF00000) | - (((g * alpha + cg * cover) >> 12) & 0x000FFC00) | - ((b * alpha + cb * cover) >> 22) | 0xC0000000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xFFC0) << 14) | - ((g & 0xFFC0) << 4) | - (b >> 6) | 0xC0000000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 14) & 0xFFC0, - (p >> 4) & 0xFFC0, - (p << 6) & 0xFFC0); - } - }; - - - - //=================================================blender_rgbAAA_gamma - template class blender_rgbAAA_gamma - { - public: - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - typedef Gamma gamma_type; - - blender_rgbAAA_gamma() : m_gamma(0) {} - void gamma(const gamma_type& g) { m_gamma = &g; } - - AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type rgb = *p; - calc_type r = m_gamma->dir((rgb >> 14) & 0xFFC0); - calc_type g = m_gamma->dir((rgb >> 4) & 0xFFC0); - calc_type b = m_gamma->dir((rgb << 6) & 0xFFC0); - *p = (pixel_type) - (((m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 16)) >> 16) << 14) & 0x3FF00000) | - ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 16)) >> 16) << 4 ) & 0x000FFC00) | - (m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 16)) >> 16) >> 6 ) | 0xC0000000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xFFC0) << 14) | - ((g & 0xFFC0) << 4) | - (b >> 6) | 0xC0000000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 14) & 0xFFC0, - (p >> 4) & 0xFFC0, - (p << 6) & 0xFFC0); - } - private: - const Gamma* m_gamma; - }; - - - //=====================================================blender_bgrAAA - struct blender_bgrAAA - { - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type bgr = *p; - calc_type b = (bgr >> 14) & 0xFFC0; - calc_type g = (bgr >> 4) & 0xFFC0; - calc_type r = (bgr << 6) & 0xFFC0; - *p = (pixel_type) - (((((cb - b) * alpha + (b << 16)) >> 2) & 0x3FF00000) | - ((((cg - g) * alpha + (g << 16)) >> 12) & 0x000FFC00) | - (((cr - r) * alpha + (r << 16)) >> 22) | 0xC0000000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((b & 0xFFC0) << 14) | - ((g & 0xFFC0) << 4) | - (r >> 6) | 0xC0000000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p << 6) & 0xFFC0, - (p >> 4) & 0xFFC0, - (p >> 14) & 0xFFC0); - } - }; - - - - //=================================================blender_bgrAAA_pre - struct blender_bgrAAA_pre - { - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - alpha = color_type::base_mask - alpha; - cover = (cover + 1) << (color_type::base_shift - 8); - pixel_type bgr = *p; - calc_type b = (bgr >> 14) & 0xFFC0; - calc_type g = (bgr >> 4) & 0xFFC0; - calc_type r = (bgr << 6) & 0xFFC0; - *p = (pixel_type) - ((((b * alpha + cb * cover) >> 2) & 0x3FF00000) | - (((g * alpha + cg * cover) >> 12) & 0x000FFC00) | - ((r * alpha + cr * cover) >> 22) | 0xC0000000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((b & 0xFFC0) << 14) | - ((g & 0xFFC0) << 4) | - (r >> 6) | 0xC0000000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p << 6) & 0xFFC0, - (p >> 4) & 0xFFC0, - (p >> 14) & 0xFFC0); - } - }; - - - - //=================================================blender_bgrAAA_gamma - template class blender_bgrAAA_gamma - { - public: - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - typedef Gamma gamma_type; - - blender_bgrAAA_gamma() : m_gamma(0) {} - void gamma(const gamma_type& g) { m_gamma = &g; } - - AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type bgr = *p; - calc_type b = m_gamma->dir((bgr >> 14) & 0xFFC0); - calc_type g = m_gamma->dir((bgr >> 4) & 0xFFC0); - calc_type r = m_gamma->dir((bgr << 6) & 0xFFC0); - *p = (pixel_type) - (((m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 16)) >> 16) << 14) & 0x3FF00000) | - ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 16)) >> 16) << 4 ) & 0x000FFC00) | - (m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 16)) >> 16) >> 6 ) | 0xC0000000); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((b & 0xFFC0) << 14) | - ((g & 0xFFC0) << 4) | - (r >> 6) | 0xC0000000); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p << 6) & 0xFFC0, - (p >> 4) & 0xFFC0, - (p >> 14) & 0xFFC0); - } - - private: - const Gamma* m_gamma; - }; - - - - //=====================================================blender_rgbBBA - struct blender_rgbBBA - { - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type rgb = *p; - calc_type r = (rgb >> 16) & 0xFFE0; - calc_type g = (rgb >> 5) & 0xFFE0; - calc_type b = (rgb << 6) & 0xFFC0; - *p = (pixel_type) - (((((cr - r) * alpha + (r << 16)) ) & 0xFFE00000) | - ((((cg - g) * alpha + (g << 16)) >> 11) & 0x001FFC00) | - (((cb - b) * alpha + (b << 16)) >> 22)); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xFFE0) << 16) | ((g & 0xFFE0) << 5) | (b >> 6)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 16) & 0xFFE0, - (p >> 5) & 0xFFE0, - (p << 6) & 0xFFC0); - } - }; - - - //=================================================blender_rgbBBA_pre - struct blender_rgbBBA_pre - { - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - alpha = color_type::base_mask - alpha; - cover = (cover + 1) << (color_type::base_shift - 8); - pixel_type rgb = *p; - calc_type r = (rgb >> 16) & 0xFFE0; - calc_type g = (rgb >> 5) & 0xFFE0; - calc_type b = (rgb << 6) & 0xFFC0; - *p = (pixel_type) - ((((r * alpha + cr * cover) ) & 0xFFE00000) | - (((g * alpha + cg * cover) >> 11) & 0x001FFC00) | - ((b * alpha + cb * cover) >> 22)); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xFFE0) << 16) | ((g & 0xFFE0) << 5) | (b >> 6)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 16) & 0xFFE0, - (p >> 5) & 0xFFE0, - (p << 6) & 0xFFC0); - } - }; - - - - //=================================================blender_rgbBBA_gamma - template class blender_rgbBBA_gamma - { - public: - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - typedef Gamma gamma_type; - - blender_rgbBBA_gamma() : m_gamma(0) {} - void gamma(const gamma_type& g) { m_gamma = &g; } - - AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type rgb = *p; - calc_type r = m_gamma->dir((rgb >> 16) & 0xFFE0); - calc_type g = m_gamma->dir((rgb >> 5) & 0xFFE0); - calc_type b = m_gamma->dir((rgb << 6) & 0xFFC0); - *p = (pixel_type) - (((m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 16)) >> 16) << 16) & 0xFFE00000) | - ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 16)) >> 16) << 5 ) & 0x001FFC00) | - (m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 16)) >> 16) >> 6 )); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((r & 0xFFE0) << 16) | ((g & 0xFFE0) << 5) | (b >> 6)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p >> 16) & 0xFFE0, - (p >> 5) & 0xFFE0, - (p << 6) & 0xFFC0); - } - - private: - const Gamma* m_gamma; - }; - - - //=====================================================blender_bgrABB - struct blender_bgrABB - { - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type bgr = *p; - calc_type b = (bgr >> 16) & 0xFFC0; - calc_type g = (bgr >> 6) & 0xFFE0; - calc_type r = (bgr << 5) & 0xFFE0; - *p = (pixel_type) - (((((cb - b) * alpha + (b << 16)) ) & 0xFFC00000) | - ((((cg - g) * alpha + (g << 16)) >> 10) & 0x003FF800) | - (((cr - r) * alpha + (r << 16)) >> 21)); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((b & 0xFFC0) << 16) | ((g & 0xFFE0) << 6) | (r >> 5)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p << 5) & 0xFFE0, - (p >> 6) & 0xFFE0, - (p >> 16) & 0xFFC0); - } - }; - - - //=================================================blender_bgrABB_pre - struct blender_bgrABB_pre - { - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - - static AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) - { - alpha = color_type::base_mask - alpha; - cover = (cover + 1) << (color_type::base_shift - 8); - pixel_type bgr = *p; - calc_type b = (bgr >> 16) & 0xFFC0; - calc_type g = (bgr >> 6) & 0xFFE0; - calc_type r = (bgr << 5) & 0xFFE0; - *p = (pixel_type) - ((((b * alpha + cb * cover) ) & 0xFFC00000) | - (((g * alpha + cg * cover) >> 10) & 0x003FF800) | - ((r * alpha + cr * cover) >> 21)); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((b & 0xFFC0) << 16) | ((g & 0xFFE0) << 6) | (r >> 5)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p << 5) & 0xFFE0, - (p >> 6) & 0xFFE0, - (p >> 16) & 0xFFC0); - } - }; - - - - //=================================================blender_bgrABB_gamma - template class blender_bgrABB_gamma - { - public: - typedef rgba16 color_type; - typedef color_type::value_type value_type; - typedef color_type::calc_type calc_type; - typedef int32u pixel_type; - typedef Gamma gamma_type; - - blender_bgrABB_gamma() : m_gamma(0) {} - void gamma(const gamma_type& g) { m_gamma = &g; } - - AGG_INLINE void blend_pix(pixel_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned) - { - pixel_type bgr = *p; - calc_type b = m_gamma->dir((bgr >> 16) & 0xFFC0); - calc_type g = m_gamma->dir((bgr >> 6) & 0xFFE0); - calc_type r = m_gamma->dir((bgr << 5) & 0xFFE0); - *p = (pixel_type) - (((m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 16)) >> 16) << 16) & 0xFFC00000) | - ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 16)) >> 16) << 6 ) & 0x003FF800) | - (m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 16)) >> 16) >> 5 )); - } - - static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) - { - return (pixel_type)(((b & 0xFFC0) << 16) | ((g & 0xFFE0) << 6) | (r >> 5)); - } - - static AGG_INLINE color_type make_color(pixel_type p) - { - return color_type((p << 5) & 0xFFE0, - (p >> 6) & 0xFFE0, - (p >> 16) & 0xFFC0); - } - - private: - const Gamma* m_gamma; - }; - - - - //===========================================pixfmt_alpha_blend_rgb_packed - template class pixfmt_alpha_blend_rgb_packed - { - public: - typedef RenBuf rbuf_type; - typedef typename rbuf_type::row_data row_data; - typedef Blender blender_type; - typedef typename blender_type::color_type color_type; - typedef typename blender_type::pixel_type pixel_type; - typedef int order_type; // A fake one - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask, - pix_width = sizeof(pixel_type) - }; - - private: - //-------------------------------------------------------------------- - AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) - { - if (c.a) - { - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - *p = m_blender.make_pix(c.r, c.g, c.b); - } - else - { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); - } - } - } - - public: - //-------------------------------------------------------------------- - explicit pixfmt_alpha_blend_rgb_packed(rbuf_type& rb) : m_rbuf(&rb) {} - void attach(rbuf_type& rb) { m_rbuf = &rb; } - - //-------------------------------------------------------------------- - template - bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) - { - rect_i r(x1, y1, x2, y2); - if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) - { - int stride = pixf.stride(); - m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), - (r.x2 - r.x1) + 1, - (r.y2 - r.y1) + 1, - stride); - return true; - } - return false; - } - - Blender& blender() { return m_blender; } - - //-------------------------------------------------------------------- - AGG_INLINE unsigned width() const { return m_rbuf->width(); } - AGG_INLINE unsigned height() const { return m_rbuf->height(); } - AGG_INLINE int stride() const { return m_rbuf->stride(); } - - //-------------------------------------------------------------------- - AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } - AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } - AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } - - //-------------------------------------------------------------------- - AGG_INLINE int8u* pix_ptr(int x, int y) - { - return m_rbuf->row_ptr(y) + x * pix_width; - } - - AGG_INLINE const int8u* pix_ptr(int x, int y) const - { - return m_rbuf->row_ptr(y) + x * pix_width; - } - - //-------------------------------------------------------------------- - AGG_INLINE void make_pix(int8u* p, const color_type& c) - { - *(pixel_type*)p = m_blender.make_pix(c.r, c.g, c.b); - } - - //-------------------------------------------------------------------- - AGG_INLINE color_type pixel(int x, int y) const - { - return m_blender.make_color(((pixel_type*)m_rbuf->row_ptr(y))[x]); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_pixel(int x, int y, const color_type& c) - { - ((pixel_type*) - m_rbuf->row_ptr(x, y, 1))[x] = - m_blender.make_pix(c.r, c.g, c.b); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) - { - copy_or_blend_pix((pixel_type*)m_rbuf->row_ptr(x, y, 1) + x, c, cover); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, - const color_type& c) - { - pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; - pixel_type v = m_blender.make_pix(c.r, c.g, c.b); - do - { - *p++ = v; - } - while(--len); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_vline(int x, int y, - unsigned len, - const color_type& c) - { - pixel_type v = m_blender.make_pix(c.r, c.g, c.b); - do - { - pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x; - *p = v; - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_hline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - if (c.a) - { - pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - pixel_type v = m_blender.make_pix(c.r, c.g, c.b); - do - { - *p++ = v; - } - while(--len); - } - else - { - do - { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); - ++p; - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - void blend_vline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - if (c.a) - { - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) - { - pixel_type v = m_blender.make_pix(c.r, c.g, c.b); - do - { - ((pixel_type*)m_rbuf->row_ptr(x, y++, 1))[x] = v; - } - while(--len); - } - else - { - do - { - m_blender.blend_pix( - (pixel_type*)m_rbuf->row_ptr(x, y++, 1), - c.r, c.g, c.b, alpha, cover); - } - while(--len); - } - } - } - - //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; - do - { - copy_or_blend_pix(p, c, *covers++); - ++p; - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - do - { - copy_or_blend_pix((pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x, - c, *covers++); - } - while(--len); - } - - //-------------------------------------------------------------------- - void copy_color_hspan(int x, int y, - unsigned len, - const color_type* colors) - { - pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; - do - { - *p++ = m_blender.make_pix(colors->r, colors->g, colors->b); - ++colors; - } - while(--len); - } - - //-------------------------------------------------------------------- - void copy_color_vspan(int x, int y, - unsigned len, - const color_type* colors) - { - do - { - pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x; - *p = m_blender.make_pix(colors->r, colors->g, colors->b); - ++colors; - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; - do - { - copy_or_blend_pix(p++, *colors++, covers ? *covers++ : cover); - } - while(--len); - } - - //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - do - { - copy_or_blend_pix((pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x, - *colors++, covers ? *covers++ : cover); - } - while(--len); - } - - //-------------------------------------------------------------------- - template - void copy_from(const RenBuf2& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len) - { - const int8u* p = from.row_ptr(ysrc); - if(p) - { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, - len * pix_width); - } - } - - //-------------------------------------------------------------------- - template - void blend_from(const SrcPixelFormatRenderer& from, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::order_type src_order; - - const value_type* psrc = (const value_type*)from.row_ptr(ysrc); - if(psrc) - { - psrc += xsrc * 4; - pixel_type* pdst = - (pixel_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; - do - { - value_type alpha = psrc[src_order::A]; - if(alpha) - { - if(alpha == base_mask && cover == 255) - { - *pdst = m_blender.make_pix(psrc[src_order::R], - psrc[src_order::G], - psrc[src_order::B]); - } - else - { - m_blender.blend_pix(pdst, - psrc[src_order::R], - psrc[src_order::G], - psrc[src_order::B], - alpha, - cover); - } - } - psrc += 4; - ++pdst; - } - while(--len); - } - } - - //-------------------------------------------------------------------- - template - void blend_from_color(const SrcPixelFormatRenderer& from, - const color_type& color, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - pixel_type* pdst = - (pixel_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; - - do - { - m_blender.blend_pix(pdst, - color.r, color.g, color.b, color.a, - cover); - ++psrc; - ++pdst; - } - while(--len); - } - } - - //-------------------------------------------------------------------- - template - void blend_from_lut(const SrcPixelFormatRenderer& from, - const color_type* color_lut, - int xdst, int ydst, - int xsrc, int ysrc, - unsigned len, - int8u cover) - { - typedef typename SrcPixelFormatRenderer::value_type src_value_type; - const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); - if(psrc) - { - pixel_type* pdst = - (pixel_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; - - do - { - const color_type& color = color_lut[*psrc]; - m_blender.blend_pix(pdst, - color.r, color.g, color.b, color.a, - cover); - ++psrc; - ++pdst; - } - while(--len); - } - } - - - - private: - rbuf_type* m_rbuf; - Blender m_blender; - }; - - typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgb555; //----pixfmt_rgb555 - typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgb565; //----pixfmt_rgb565 - - typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgb555_pre; //----pixfmt_rgb555_pre - typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgb565_pre; //----pixfmt_rgb565_pre - - typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgbAAA; //----pixfmt_rgbAAA - typedef pixfmt_alpha_blend_rgb_packed pixfmt_bgrAAA; //----pixfmt_bgrAAA - typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgbBBA; //----pixfmt_rgbBBA - typedef pixfmt_alpha_blend_rgb_packed pixfmt_bgrABB; //----pixfmt_bgrABB - - typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgbAAA_pre; //----pixfmt_rgbAAA_pre - typedef pixfmt_alpha_blend_rgb_packed pixfmt_bgrAAA_pre; //----pixfmt_bgrAAA_pre - typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgbBBA_pre; //----pixfmt_rgbBBA_pre - typedef pixfmt_alpha_blend_rgb_packed pixfmt_bgrABB_pre; //----pixfmt_bgrABB_pre - - - //-----------------------------------------------------pixfmt_rgb555_gamma - template class pixfmt_rgb555_gamma : - public pixfmt_alpha_blend_rgb_packed, - rendering_buffer> - { - public: - pixfmt_rgb555_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb_packed, - rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - - //-----------------------------------------------------pixfmt_rgb565_gamma - template class pixfmt_rgb565_gamma : - public pixfmt_alpha_blend_rgb_packed, rendering_buffer> - { - public: - pixfmt_rgb565_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb_packed, rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - - //-----------------------------------------------------pixfmt_rgbAAA_gamma - template class pixfmt_rgbAAA_gamma : - public pixfmt_alpha_blend_rgb_packed, - rendering_buffer> - { - public: - pixfmt_rgbAAA_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb_packed, - rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - - //-----------------------------------------------------pixfmt_bgrAAA_gamma - template class pixfmt_bgrAAA_gamma : - public pixfmt_alpha_blend_rgb_packed, - rendering_buffer> - { - public: - pixfmt_bgrAAA_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb_packed, - rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - - //-----------------------------------------------------pixfmt_rgbBBA_gamma - template class pixfmt_rgbBBA_gamma : - public pixfmt_alpha_blend_rgb_packed, - rendering_buffer> - { - public: - pixfmt_rgbBBA_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb_packed, - rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - - //-----------------------------------------------------pixfmt_bgrABB_gamma - template class pixfmt_bgrABB_gamma : - public pixfmt_alpha_blend_rgb_packed, - rendering_buffer> - { - public: - pixfmt_bgrABB_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb_packed, - rendering_buffer>(rb) - { - this->blender().gamma(g); - } - }; - - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_pixfmt_transposer.h corsix-th-0.62/agg/include/agg_pixfmt_transposer.h --- corsix-th-0.30/agg/include/agg_pixfmt_transposer.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_pixfmt_transposer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_PIXFMT_TRANSPOSER_INCLUDED -#define AGG_PIXFMT_TRANSPOSER_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - //=======================================================pixfmt_transposer - template class pixfmt_transposer - { - public: - typedef PixFmt pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::row_data row_data; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - - //-------------------------------------------------------------------- - pixfmt_transposer() : m_pixf(0) {} - explicit pixfmt_transposer(pixfmt_type& pixf) : m_pixf(&pixf) {} - void attach(pixfmt_type& pixf) { m_pixf = &pixf; } - - //-------------------------------------------------------------------- - AGG_INLINE unsigned width() const { return m_pixf->height(); } - AGG_INLINE unsigned height() const { return m_pixf->width(); } - - //-------------------------------------------------------------------- - AGG_INLINE color_type pixel(int x, int y) const - { - return m_pixf->pixel(y, x); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_pixel(int x, int y, const color_type& c) - { - m_pixf->copy_pixel(y, x, c); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pixel(int x, int y, - const color_type& c, - int8u cover) - { - m_pixf->blend_pixel(y, x, c, cover); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, - const color_type& c) - { - m_pixf->copy_vline(y, x, len, c); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_vline(int x, int y, - unsigned len, - const color_type& c) - { - m_pixf->copy_hline(y, x, len, c); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_hline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - m_pixf->blend_vline(y, x, len, c, cover); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_vline(int x, int y, - unsigned len, - const color_type& c, - int8u cover) - { - m_pixf->blend_hline(y, x, len, c, cover); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_solid_hspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - m_pixf->blend_solid_vspan(y, x, len, c, covers); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_solid_vspan(int x, int y, - unsigned len, - const color_type& c, - const int8u* covers) - { - m_pixf->blend_solid_hspan(y, x, len, c, covers); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_color_hspan(int x, int y, - unsigned len, - const color_type* colors) - { - m_pixf->copy_color_vspan(y, x, len, colors); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_color_vspan(int x, int y, - unsigned len, - const color_type* colors) - { - m_pixf->copy_color_hspan(y, x, len, colors); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_color_hspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - m_pixf->blend_color_vspan(y, x, len, colors, covers, cover); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_color_vspan(int x, int y, - unsigned len, - const color_type* colors, - const int8u* covers, - int8u cover) - { - m_pixf->blend_color_hspan(y, x, len, colors, covers, cover); - } - - private: - pixfmt_type* m_pixf; - }; -} - -#endif - - diff -Nru corsix-th-0.30/agg/include/agg_rasterizer_cells_aa.h corsix-th-0.62/agg/include/agg_rasterizer_cells_aa.h --- corsix-th-0.30/agg/include/agg_rasterizer_cells_aa.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rasterizer_cells_aa.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,754 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// -// The author gratefully acknowleges the support of David Turner, -// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType -// libray - in producing this work. See http://www.freetype.org for details. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for 32-bit screen coordinates has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -#ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED -#define AGG_RASTERIZER_CELLS_AA_INCLUDED - -#include -#include -#include "agg_math.h" -#include "agg_array.h" - - -namespace agg -{ - - //-----------------------------------------------------rasterizer_cells_aa - // An internal class that implements the main rasterization algorithm. - // Used in the rasterizer. Should not be used direcly. - template class rasterizer_cells_aa - { - enum cell_block_scale_e - { - cell_block_shift = 12, - cell_block_size = 1 << cell_block_shift, - cell_block_mask = cell_block_size - 1, - cell_block_pool = 256, - cell_block_limit = 1024 - }; - - struct sorted_y - { - unsigned start; - unsigned num; - }; - - public: - typedef Cell cell_type; - typedef rasterizer_cells_aa self_type; - - ~rasterizer_cells_aa(); - rasterizer_cells_aa(); - - void reset(); - void style(const cell_type& style_cell); - void line(int x1, int y1, int x2, int y2); - - int min_x() const { return m_min_x; } - int min_y() const { return m_min_y; } - int max_x() const { return m_max_x; } - int max_y() const { return m_max_y; } - - void sort_cells(); - - unsigned total_cells() const - { - return m_num_cells; - } - - unsigned scanline_num_cells(unsigned y) const - { - return m_sorted_y[y - m_min_y].num; - } - - const cell_type* const* scanline_cells(unsigned y) const - { - return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start; - } - - bool sorted() const { return m_sorted; } - - private: - rasterizer_cells_aa(const self_type&); - const self_type& operator = (const self_type&); - - void set_curr_cell(int x, int y); - void add_curr_cell(); - void render_hline(int ey, int x1, int y1, int x2, int y2); - void allocate_block(); - - private: - unsigned m_num_blocks; - unsigned m_max_blocks; - unsigned m_curr_block; - unsigned m_num_cells; - cell_type** m_cells; - cell_type* m_curr_cell_ptr; - pod_vector m_sorted_cells; - pod_vector m_sorted_y; - cell_type m_curr_cell; - cell_type m_style_cell; - int m_min_x; - int m_min_y; - int m_max_x; - int m_max_y; - bool m_sorted; - }; - - - - - //------------------------------------------------------------------------ - template - rasterizer_cells_aa::~rasterizer_cells_aa() - { - if(m_num_blocks) - { - cell_type** ptr = m_cells + m_num_blocks - 1; - while(m_num_blocks--) - { - pod_allocator::deallocate(*ptr, cell_block_size); - ptr--; - } - pod_allocator::deallocate(m_cells, m_max_blocks); - } - } - - //------------------------------------------------------------------------ - template - rasterizer_cells_aa::rasterizer_cells_aa() : - m_num_blocks(0), - m_max_blocks(0), - m_curr_block(0), - m_num_cells(0), - m_cells(0), - m_curr_cell_ptr(0), - m_sorted_cells(), - m_sorted_y(), - m_min_x(0x7FFFFFFF), - m_min_y(0x7FFFFFFF), - m_max_x(-0x7FFFFFFF), - m_max_y(-0x7FFFFFFF), - m_sorted(false) - { - m_style_cell.initial(); - m_curr_cell.initial(); - } - - //------------------------------------------------------------------------ - template - void rasterizer_cells_aa::reset() - { - m_num_cells = 0; - m_curr_block = 0; - m_curr_cell.initial(); - m_style_cell.initial(); - m_sorted = false; - m_min_x = 0x7FFFFFFF; - m_min_y = 0x7FFFFFFF; - m_max_x = -0x7FFFFFFF; - m_max_y = -0x7FFFFFFF; - } - - //------------------------------------------------------------------------ - template - AGG_INLINE void rasterizer_cells_aa::add_curr_cell() - { - if(m_curr_cell.area | m_curr_cell.cover) - { - if((m_num_cells & cell_block_mask) == 0) - { - if(m_num_blocks >= cell_block_limit) return; - allocate_block(); - } - *m_curr_cell_ptr++ = m_curr_cell; - ++m_num_cells; - } - } - - //------------------------------------------------------------------------ - template - AGG_INLINE void rasterizer_cells_aa::set_curr_cell(int x, int y) - { - if(m_curr_cell.not_equal(x, y, m_style_cell)) - { - add_curr_cell(); - m_curr_cell.style(m_style_cell); - m_curr_cell.x = x; - m_curr_cell.y = y; - m_curr_cell.cover = 0; - m_curr_cell.area = 0; - } - } - - //------------------------------------------------------------------------ - template - AGG_INLINE void rasterizer_cells_aa::render_hline(int ey, - int x1, int y1, - int x2, int y2) - { - int ex1 = x1 >> poly_subpixel_shift; - int ex2 = x2 >> poly_subpixel_shift; - int fx1 = x1 & poly_subpixel_mask; - int fx2 = x2 & poly_subpixel_mask; - - int delta, p, first, dx; - int incr, lift, mod, rem; - - //trivial case. Happens often - if(y1 == y2) - { - set_curr_cell(ex2, ey); - return; - } - - //everything is located in a single cell. That is easy! - if(ex1 == ex2) - { - delta = y2 - y1; - m_curr_cell.cover += delta; - m_curr_cell.area += (fx1 + fx2) * delta; - return; - } - - //ok, we'll have to render a run of adjacent cells on the same - //hline... - p = (poly_subpixel_scale - fx1) * (y2 - y1); - first = poly_subpixel_scale; - incr = 1; - - dx = x2 - x1; - - if(dx < 0) - { - p = fx1 * (y2 - y1); - first = 0; - incr = -1; - dx = -dx; - } - - delta = p / dx; - mod = p % dx; - - if(mod < 0) - { - delta--; - mod += dx; - } - - m_curr_cell.cover += delta; - m_curr_cell.area += (fx1 + first) * delta; - - ex1 += incr; - set_curr_cell(ex1, ey); - y1 += delta; - - if(ex1 != ex2) - { - p = poly_subpixel_scale * (y2 - y1 + delta); - lift = p / dx; - rem = p % dx; - - if (rem < 0) - { - lift--; - rem += dx; - } - - mod -= dx; - - while (ex1 != ex2) - { - delta = lift; - mod += rem; - if(mod >= 0) - { - mod -= dx; - delta++; - } - - m_curr_cell.cover += delta; - m_curr_cell.area += poly_subpixel_scale * delta; - y1 += delta; - ex1 += incr; - set_curr_cell(ex1, ey); - } - } - delta = y2 - y1; - m_curr_cell.cover += delta; - m_curr_cell.area += (fx2 + poly_subpixel_scale - first) * delta; - } - - //------------------------------------------------------------------------ - template - AGG_INLINE void rasterizer_cells_aa::style(const cell_type& style_cell) - { - m_style_cell.style(style_cell); - } - - //------------------------------------------------------------------------ - template - void rasterizer_cells_aa::line(int x1, int y1, int x2, int y2) - { - enum dx_limit_e { dx_limit = 16384 << poly_subpixel_shift }; - - int dx = x2 - x1; - - if(dx >= dx_limit || dx <= -dx_limit) - { - int cx = (x1 + x2) >> 1; - int cy = (y1 + y2) >> 1; - line(x1, y1, cx, cy); - line(cx, cy, x2, y2); - } - - int dy = y2 - y1; - int ex1 = x1 >> poly_subpixel_shift; - int ex2 = x2 >> poly_subpixel_shift; - int ey1 = y1 >> poly_subpixel_shift; - int ey2 = y2 >> poly_subpixel_shift; - int fy1 = y1 & poly_subpixel_mask; - int fy2 = y2 & poly_subpixel_mask; - - int x_from, x_to; - int p, rem, mod, lift, delta, first, incr; - - if(ex1 < m_min_x) m_min_x = ex1; - if(ex1 > m_max_x) m_max_x = ex1; - if(ey1 < m_min_y) m_min_y = ey1; - if(ey1 > m_max_y) m_max_y = ey1; - if(ex2 < m_min_x) m_min_x = ex2; - if(ex2 > m_max_x) m_max_x = ex2; - if(ey2 < m_min_y) m_min_y = ey2; - if(ey2 > m_max_y) m_max_y = ey2; - - set_curr_cell(ex1, ey1); - - //everything is on a single hline - if(ey1 == ey2) - { - render_hline(ey1, x1, fy1, x2, fy2); - return; - } - - //Vertical line - we have to calculate start and end cells, - //and then - the common values of the area and coverage for - //all cells of the line. We know exactly there's only one - //cell, so, we don't have to call render_hline(). - incr = 1; - if(dx == 0) - { - int ex = x1 >> poly_subpixel_shift; - int two_fx = (x1 - (ex << poly_subpixel_shift)) << 1; - int area; - - first = poly_subpixel_scale; - if(dy < 0) - { - first = 0; - incr = -1; - } - - x_from = x1; - - //render_hline(ey1, x_from, fy1, x_from, first); - delta = first - fy1; - m_curr_cell.cover += delta; - m_curr_cell.area += two_fx * delta; - - ey1 += incr; - set_curr_cell(ex, ey1); - - delta = first + first - poly_subpixel_scale; - area = two_fx * delta; - while(ey1 != ey2) - { - //render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, first); - m_curr_cell.cover = delta; - m_curr_cell.area = area; - ey1 += incr; - set_curr_cell(ex, ey1); - } - //render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, fy2); - delta = fy2 - poly_subpixel_scale + first; - m_curr_cell.cover += delta; - m_curr_cell.area += two_fx * delta; - return; - } - - //ok, we have to render several hlines - p = (poly_subpixel_scale - fy1) * dx; - first = poly_subpixel_scale; - - if(dy < 0) - { - p = fy1 * dx; - first = 0; - incr = -1; - dy = -dy; - } - - delta = p / dy; - mod = p % dy; - - if(mod < 0) - { - delta--; - mod += dy; - } - - x_from = x1 + delta; - render_hline(ey1, x1, fy1, x_from, first); - - ey1 += incr; - set_curr_cell(x_from >> poly_subpixel_shift, ey1); - - if(ey1 != ey2) - { - p = poly_subpixel_scale * dx; - lift = p / dy; - rem = p % dy; - - if(rem < 0) - { - lift--; - rem += dy; - } - mod -= dy; - - while(ey1 != ey2) - { - delta = lift; - mod += rem; - if (mod >= 0) - { - mod -= dy; - delta++; - } - - x_to = x_from + delta; - render_hline(ey1, x_from, poly_subpixel_scale - first, x_to, first); - x_from = x_to; - - ey1 += incr; - set_curr_cell(x_from >> poly_subpixel_shift, ey1); - } - } - render_hline(ey1, x_from, poly_subpixel_scale - first, x2, fy2); - } - - //------------------------------------------------------------------------ - template - void rasterizer_cells_aa::allocate_block() - { - if(m_curr_block >= m_num_blocks) - { - if(m_num_blocks >= m_max_blocks) - { - cell_type** new_cells = - pod_allocator::allocate(m_max_blocks + - cell_block_pool); - - if(m_cells) - { - memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_type*)); - pod_allocator::deallocate(m_cells, m_max_blocks); - } - m_cells = new_cells; - m_max_blocks += cell_block_pool; - } - - m_cells[m_num_blocks++] = - pod_allocator::allocate(cell_block_size); - - } - m_curr_cell_ptr = m_cells[m_curr_block++]; - } - - - - //------------------------------------------------------------------------ - template static AGG_INLINE void swap_cells(T* a, T* b) - { - T temp = *a; - *a = *b; - *b = temp; - } - - - //------------------------------------------------------------------------ - enum - { - qsort_threshold = 9 - }; - - - //------------------------------------------------------------------------ - template - void qsort_cells(Cell** start, unsigned num) - { - Cell** stack[80]; - Cell*** top; - Cell** limit; - Cell** base; - - limit = start + num; - base = start; - top = stack; - - for (;;) - { - int len = int(limit - base); - - Cell** i; - Cell** j; - Cell** pivot; - - if(len > qsort_threshold) - { - // we use base + len/2 as the pivot - pivot = base + len / 2; - swap_cells(base, pivot); - - i = base + 1; - j = limit - 1; - - // now ensure that *i <= *base <= *j - if((*j)->x < (*i)->x) - { - swap_cells(i, j); - } - - if((*base)->x < (*i)->x) - { - swap_cells(base, i); - } - - if((*j)->x < (*base)->x) - { - swap_cells(base, j); - } - - for(;;) - { - int x = (*base)->x; - do i++; while( (*i)->x < x ); - do j--; while( x < (*j)->x ); - - if(i > j) - { - break; - } - - swap_cells(i, j); - } - - swap_cells(base, j); - - // now, push the largest sub-array - if(j - base > limit - i) - { - top[0] = base; - top[1] = j; - base = i; - } - else - { - top[0] = i; - top[1] = limit; - limit = j; - } - top += 2; - } - else - { - // the sub-array is small, perform insertion sort - j = base; - i = j + 1; - - for(; i < limit; j = i, i++) - { - for(; j[1]->x < (*j)->x; j--) - { - swap_cells(j + 1, j); - if (j == base) - { - break; - } - } - } - - if(top > stack) - { - top -= 2; - base = top[0]; - limit = top[1]; - } - else - { - break; - } - } - } - } - - - //------------------------------------------------------------------------ - template - void rasterizer_cells_aa::sort_cells() - { - if(m_sorted) return; //Perform sort only the first time. - - add_curr_cell(); - m_curr_cell.x = 0x7FFFFFFF; - m_curr_cell.y = 0x7FFFFFFF; - m_curr_cell.cover = 0; - m_curr_cell.area = 0; - - if(m_num_cells == 0) return; - -// DBG: Check to see if min/max works well. -//for(unsigned nc = 0; nc < m_num_cells; nc++) -//{ -// cell_type* cell = m_cells[nc >> cell_block_shift] + (nc & cell_block_mask); -// if(cell->x < m_min_x || -// cell->y < m_min_y || -// cell->x > m_max_x || -// cell->y > m_max_y) -// { -// cell = cell; // Breakpoint here -// } -//} - // Allocate the array of cell pointers - m_sorted_cells.allocate(m_num_cells, 16); - - // Allocate and zero the Y array - m_sorted_y.allocate(m_max_y - m_min_y + 1, 16); - m_sorted_y.zero(); - - // Create the Y-histogram (count the numbers of cells for each Y) - cell_type** block_ptr = m_cells; - cell_type* cell_ptr; - unsigned nb = m_num_cells >> cell_block_shift; - unsigned i; - while(nb--) - { - cell_ptr = *block_ptr++; - i = cell_block_size; - while(i--) - { - m_sorted_y[cell_ptr->y - m_min_y].start++; - ++cell_ptr; - } - } - - cell_ptr = *block_ptr++; - i = m_num_cells & cell_block_mask; - while(i--) - { - m_sorted_y[cell_ptr->y - m_min_y].start++; - ++cell_ptr; - } - - // Convert the Y-histogram into the array of starting indexes - unsigned start = 0; - for(i = 0; i < m_sorted_y.size(); i++) - { - unsigned v = m_sorted_y[i].start; - m_sorted_y[i].start = start; - start += v; - } - - // Fill the cell pointer array sorted by Y - block_ptr = m_cells; - nb = m_num_cells >> cell_block_shift; - while(nb--) - { - cell_ptr = *block_ptr++; - i = cell_block_size; - while(i--) - { - sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y]; - m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr; - ++curr_y.num; - ++cell_ptr; - } - } - - cell_ptr = *block_ptr++; - i = m_num_cells & cell_block_mask; - while(i--) - { - sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y]; - m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr; - ++curr_y.num; - ++cell_ptr; - } - - // Finally arrange the X-arrays - for(i = 0; i < m_sorted_y.size(); i++) - { - const sorted_y& curr_y = m_sorted_y[i]; - if(curr_y.num) - { - qsort_cells(m_sorted_cells.data() + curr_y.start, curr_y.num); - } - } - m_sorted = true; - } - - - - //------------------------------------------------------scanline_hit_test - class scanline_hit_test - { - public: - scanline_hit_test(int x) : m_x(x), m_hit(false) {} - - void reset_spans() {} - void finalize(int) {} - void add_cell(int x, int) - { - if(m_x == x) m_hit = true; - } - void add_span(int x, int len, int) - { - if(m_x >= x && m_x < x+len) m_hit = true; - } - unsigned num_spans() const { return 1; } - bool hit() const { return m_hit; } - - private: - int m_x; - bool m_hit; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_rasterizer_compound_aa.h corsix-th-0.62/agg/include/agg_rasterizer_compound_aa.h --- corsix-th-0.30/agg/include/agg_rasterizer_compound_aa.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rasterizer_compound_aa.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,698 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.3 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// -// The author gratefully acknowleges the support of David Turner, -// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType -// libray - in producing this work. See http://www.freetype.org for details. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for 32-bit screen coordinates has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -#ifndef AGG_RASTERIZER_COMPOUND_AA_INCLUDED -#define AGG_RASTERIZER_COMPOUND_AA_INCLUDED - -#include "agg_rasterizer_cells_aa.h" -#include "agg_rasterizer_sl_clip.h" - -namespace agg -{ - - //-----------------------------------------------------------cell_style_aa - // A pixel cell. There're no constructors defined and it was done - // intentionally in order to avoid extra overhead when allocating an - // array of cells. - struct cell_style_aa - { - int x; - int y; - int cover; - int area; - int16 left, right; - - void initial() - { - x = 0x7FFFFFFF; - y = 0x7FFFFFFF; - cover = 0; - area = 0; - left = -1; - right = -1; - } - - void style(const cell_style_aa& c) - { - left = c.left; - right = c.right; - } - - int not_equal(int ex, int ey, const cell_style_aa& c) const - { - return (ex - x) | (ey - y) | (left - c.left) | (right - c.right); - } - }; - - - //===========================================================layer_order_e - enum layer_order_e - { - layer_unsorted, //------layer_unsorted - layer_direct, //------layer_direct - layer_inverse //------layer_inverse - }; - - - //==================================================rasterizer_compound_aa - template class rasterizer_compound_aa - { - struct style_info - { - unsigned start_cell; - unsigned num_cells; - int last_x; - }; - - struct cell_info - { - int x, area, cover; - }; - - public: - typedef Clip clip_type; - typedef typename Clip::conv_type conv_type; - typedef typename Clip::coord_type coord_type; - - enum aa_scale_e - { - aa_shift = 8, - aa_scale = 1 << aa_shift, - aa_mask = aa_scale - 1, - aa_scale2 = aa_scale * 2, - aa_mask2 = aa_scale2 - 1 - }; - - //-------------------------------------------------------------------- - rasterizer_compound_aa() : - m_outline(), - m_clipper(), - m_filling_rule(fill_non_zero), - m_layer_order(layer_direct), - m_styles(), // Active Styles - m_ast(), // Active Style Table (unique values) - m_asm(), // Active Style Mask - m_cells(), - m_cover_buf(), - m_master_alpha(), - m_min_style(0x7FFFFFFF), - m_max_style(-0x7FFFFFFF), - m_start_x(0), - m_start_y(0), - m_scan_y(0x7FFFFFFF), - m_sl_start(0), - m_sl_len(0) - {} - - //-------------------------------------------------------------------- - void reset(); - void reset_clipping(); - void clip_box(double x1, double y1, double x2, double y2); - void filling_rule(filling_rule_e filling_rule); - void layer_order(layer_order_e order); - void master_alpha(int style, double alpha); - - //-------------------------------------------------------------------- - void styles(int left, int right); - void move_to(int x, int y); - void line_to(int x, int y); - void move_to_d(double x, double y); - void line_to_d(double x, double y); - void add_vertex(double x, double y, unsigned cmd); - - void edge(int x1, int y1, int x2, int y2); - void edge_d(double x1, double y1, double x2, double y2); - - //------------------------------------------------------------------- - template - void add_path(VertexSource& vs, unsigned path_id=0) - { - double x; - double y; - - unsigned cmd; - vs.rewind(path_id); - if(m_outline.sorted()) reset(); - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - add_vertex(x, y, cmd); - } - } - - - //-------------------------------------------------------------------- - int min_x() const { return m_outline.min_x(); } - int min_y() const { return m_outline.min_y(); } - int max_x() const { return m_outline.max_x(); } - int max_y() const { return m_outline.max_y(); } - int min_style() const { return m_min_style; } - int max_style() const { return m_max_style; } - - //-------------------------------------------------------------------- - void sort(); - bool rewind_scanlines(); - unsigned sweep_styles(); - int scanline_start() const { return m_sl_start; } - unsigned scanline_length() const { return m_sl_len; } - unsigned style(unsigned style_idx) const; - - cover_type* allocate_cover_buffer(unsigned len); - - //-------------------------------------------------------------------- - bool navigate_scanline(int y); - bool hit_test(int tx, int ty); - - //-------------------------------------------------------------------- - AGG_INLINE unsigned calculate_alpha(int area, unsigned master_alpha) const - { - int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift); - if(cover < 0) cover = -cover; - if(m_filling_rule == fill_even_odd) - { - cover &= aa_mask2; - if(cover > aa_scale) - { - cover = aa_scale2 - cover; - } - } - if(cover > aa_mask) cover = aa_mask; - return (cover * master_alpha + aa_mask) >> aa_shift; - } - - //-------------------------------------------------------------------- - // Sweeps one scanline with one style index. The style ID can be - // determined by calling style(). - template bool sweep_scanline(Scanline& sl, int style_idx) - { - int scan_y = m_scan_y - 1; - if(scan_y > m_outline.max_y()) return false; - - sl.reset_spans(); - - unsigned master_alpha = aa_mask; - - if(style_idx < 0) - { - style_idx = 0; - } - else - { - style_idx++; - master_alpha = m_master_alpha[m_ast[style_idx] + m_min_style - 1]; - } - - const style_info& st = m_styles[m_ast[style_idx]]; - - unsigned num_cells = st.num_cells; - cell_info* cell = &m_cells[st.start_cell]; - - int cover = 0; - while(num_cells--) - { - unsigned alpha; - int x = cell->x; - int area = cell->area; - - cover += cell->cover; - - ++cell; - - if(area) - { - alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area, - master_alpha); - sl.add_cell(x, alpha); - x++; - } - - if(num_cells && cell->x > x) - { - alpha = calculate_alpha(cover << (poly_subpixel_shift + 1), - master_alpha); - if(alpha) - { - sl.add_span(x, cell->x - x, alpha); - } - } - } - - if(sl.num_spans() == 0) return false; - sl.finalize(scan_y); - return true; - } - - private: - void add_style(int style_id); - void allocate_master_alpha(); - - //-------------------------------------------------------------------- - // Disable copying - rasterizer_compound_aa(const rasterizer_compound_aa&); - const rasterizer_compound_aa& - operator = (const rasterizer_compound_aa&); - - private: - rasterizer_cells_aa m_outline; - clip_type m_clipper; - filling_rule_e m_filling_rule; - layer_order_e m_layer_order; - pod_vector m_styles; // Active Styles - pod_vector m_ast; // Active Style Table (unique values) - pod_vector m_asm; // Active Style Mask - pod_vector m_cells; - pod_vector m_cover_buf; - pod_bvector m_master_alpha; - - int m_min_style; - int m_max_style; - coord_type m_start_x; - coord_type m_start_y; - int m_scan_y; - int m_sl_start; - unsigned m_sl_len; - }; - - - - - - - - - - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::reset() - { - m_outline.reset(); - m_min_style = 0x7FFFFFFF; - m_max_style = -0x7FFFFFFF; - m_scan_y = 0x7FFFFFFF; - m_sl_start = 0; - m_sl_len = 0; - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::filling_rule(filling_rule_e filling_rule) - { - m_filling_rule = filling_rule; - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::layer_order(layer_order_e order) - { - m_layer_order = order; - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::clip_box(double x1, double y1, - double x2, double y2) - { - reset(); - m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), - conv_type::upscale(x2), conv_type::upscale(y2)); - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::reset_clipping() - { - reset(); - m_clipper.reset_clipping(); - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::styles(int left, int right) - { - cell_style_aa cell; - cell.initial(); - cell.left = (int16)left; - cell.right = (int16)right; - m_outline.style(cell); - if(left >= 0 && left < m_min_style) m_min_style = left; - if(left >= 0 && left > m_max_style) m_max_style = left; - if(right >= 0 && right < m_min_style) m_min_style = right; - if(right >= 0 && right > m_max_style) m_max_style = right; - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::move_to(int x, int y) - { - if(m_outline.sorted()) reset(); - m_clipper.move_to(m_start_x = conv_type::downscale(x), - m_start_y = conv_type::downscale(y)); - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::line_to(int x, int y) - { - m_clipper.line_to(m_outline, - conv_type::downscale(x), - conv_type::downscale(y)); - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::move_to_d(double x, double y) - { - if(m_outline.sorted()) reset(); - m_clipper.move_to(m_start_x = conv_type::upscale(x), - m_start_y = conv_type::upscale(y)); - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::line_to_d(double x, double y) - { - m_clipper.line_to(m_outline, - conv_type::upscale(x), - conv_type::upscale(y)); - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::add_vertex(double x, double y, unsigned cmd) - { - if(is_move_to(cmd)) - { - move_to_d(x, y); - } - else - if(is_vertex(cmd)) - { - line_to_d(x, y); - } - else - if(is_close(cmd)) - { - m_clipper.line_to(m_outline, m_start_x, m_start_y); - } - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::edge(int x1, int y1, int x2, int y2) - { - if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); - m_clipper.line_to(m_outline, - conv_type::downscale(x2), - conv_type::downscale(y2)); - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::edge_d(double x1, double y1, - double x2, double y2) - { - if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); - m_clipper.line_to(m_outline, - conv_type::upscale(x2), - conv_type::upscale(y2)); - } - - //------------------------------------------------------------------------ - template - AGG_INLINE void rasterizer_compound_aa::sort() - { - m_outline.sort_cells(); - } - - //------------------------------------------------------------------------ - template - AGG_INLINE bool rasterizer_compound_aa::rewind_scanlines() - { - m_outline.sort_cells(); - if(m_outline.total_cells() == 0) - { - return false; - } - if(m_max_style < m_min_style) - { - return false; - } - m_scan_y = m_outline.min_y(); - m_styles.allocate(m_max_style - m_min_style + 2, 128); - allocate_master_alpha(); - return true; - } - - //------------------------------------------------------------------------ - template - AGG_INLINE void rasterizer_compound_aa::add_style(int style_id) - { - if(style_id < 0) style_id = 0; - else style_id -= m_min_style - 1; - - unsigned nbyte = style_id >> 3; - unsigned mask = 1 << (style_id & 7); - - style_info* style = &m_styles[style_id]; - if((m_asm[nbyte] & mask) == 0) - { - m_ast.add(style_id); - m_asm[nbyte] |= mask; - style->start_cell = 0; - style->num_cells = 0; - style->last_x = -0x7FFFFFFF; - } - ++style->start_cell; - } - - //------------------------------------------------------------------------ - // Returns the number of styles - template - unsigned rasterizer_compound_aa::sweep_styles() - { - for(;;) - { - if(m_scan_y > m_outline.max_y()) return 0; - unsigned num_cells = m_outline.scanline_num_cells(m_scan_y); - const cell_style_aa* const* cells = m_outline.scanline_cells(m_scan_y); - unsigned num_styles = m_max_style - m_min_style + 2; - const cell_style_aa* curr_cell; - unsigned style_id; - style_info* style; - cell_info* cell; - - m_cells.allocate(num_cells * 2, 256); // Each cell can have two styles - m_ast.capacity(num_styles, 64); - m_asm.allocate((num_styles + 7) >> 3, 8); - m_asm.zero(); - - if(num_cells) - { - // Pre-add zero (for no-fill style, that is, -1). - // We need that to ensure that the "-1 style" would go first. - m_asm[0] |= 1; - m_ast.add(0); - style = &m_styles[0]; - style->start_cell = 0; - style->num_cells = 0; - style->last_x = -0x7FFFFFFF; - - m_sl_start = cells[0]->x; - m_sl_len = cells[num_cells-1]->x - m_sl_start + 1; - while(num_cells--) - { - curr_cell = *cells++; - add_style(curr_cell->left); - add_style(curr_cell->right); - } - - // Convert the Y-histogram into the array of starting indexes - unsigned i; - unsigned start_cell = 0; - for(i = 0; i < m_ast.size(); i++) - { - style_info& st = m_styles[m_ast[i]]; - unsigned v = st.start_cell; - st.start_cell = start_cell; - start_cell += v; - } - - cells = m_outline.scanline_cells(m_scan_y); - num_cells = m_outline.scanline_num_cells(m_scan_y); - - while(num_cells--) - { - curr_cell = *cells++; - style_id = (curr_cell->left < 0) ? 0 : - curr_cell->left - m_min_style + 1; - - style = &m_styles[style_id]; - if(curr_cell->x == style->last_x) - { - cell = &m_cells[style->start_cell + style->num_cells - 1]; - cell->area += curr_cell->area; - cell->cover += curr_cell->cover; - } - else - { - cell = &m_cells[style->start_cell + style->num_cells]; - cell->x = curr_cell->x; - cell->area = curr_cell->area; - cell->cover = curr_cell->cover; - style->last_x = curr_cell->x; - style->num_cells++; - } - - style_id = (curr_cell->right < 0) ? 0 : - curr_cell->right - m_min_style + 1; - - style = &m_styles[style_id]; - if(curr_cell->x == style->last_x) - { - cell = &m_cells[style->start_cell + style->num_cells - 1]; - cell->area -= curr_cell->area; - cell->cover -= curr_cell->cover; - } - else - { - cell = &m_cells[style->start_cell + style->num_cells]; - cell->x = curr_cell->x; - cell->area = -curr_cell->area; - cell->cover = -curr_cell->cover; - style->last_x = curr_cell->x; - style->num_cells++; - } - } - } - if(m_ast.size() > 1) break; - ++m_scan_y; - } - ++m_scan_y; - - if(m_layer_order != layer_unsorted) - { - range_adaptor > ra(m_ast, 1, m_ast.size() - 1); - if(m_layer_order == layer_direct) quick_sort(ra, unsigned_greater); - else quick_sort(ra, unsigned_less); - } - - return m_ast.size() - 1; - } - - //------------------------------------------------------------------------ - // Returns style ID depending of the existing style index - template - AGG_INLINE - unsigned rasterizer_compound_aa::style(unsigned style_idx) const - { - return m_ast[style_idx + 1] + m_min_style - 1; - } - - //------------------------------------------------------------------------ - template - AGG_INLINE bool rasterizer_compound_aa::navigate_scanline(int y) - { - m_outline.sort_cells(); - if(m_outline.total_cells() == 0) - { - return false; - } - if(m_max_style < m_min_style) - { - return false; - } - if(y < m_outline.min_y() || y > m_outline.max_y()) - { - return false; - } - m_scan_y = y; - m_styles.allocate(m_max_style - m_min_style + 2, 128); - allocate_master_alpha(); - return true; - } - - //------------------------------------------------------------------------ - template - bool rasterizer_compound_aa::hit_test(int tx, int ty) - { - if(!navigate_scanline(ty)) - { - return false; - } - - unsigned num_styles = sweep_styles(); - if(num_styles <= 0) - { - return false; - } - - scanline_hit_test sl(tx); - sweep_scanline(sl, -1); - return sl.hit(); - } - - //------------------------------------------------------------------------ - template - cover_type* rasterizer_compound_aa::allocate_cover_buffer(unsigned len) - { - m_cover_buf.allocate(len, 256); - return &m_cover_buf[0]; - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::allocate_master_alpha() - { - while((int)m_master_alpha.size() <= m_max_style) - { - m_master_alpha.add(aa_mask); - } - } - - //------------------------------------------------------------------------ - template - void rasterizer_compound_aa::master_alpha(int style, double alpha) - { - if(style >= 0) - { - while((int)m_master_alpha.size() <= style) - { - m_master_alpha.add(aa_mask); - } - m_master_alpha[style] = uround(alpha * aa_mask); - } - } - -} - - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_rasterizer_outline_aa.h corsix-th-0.62/agg/include/agg_rasterizer_outline_aa.h --- corsix-th-0.30/agg/include/agg_rasterizer_outline_aa.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rasterizer_outline_aa.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,599 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_RASTERIZER_OUTLINE_AA_INCLUDED -#define AGG_RASTERIZER_OUTLINE_AA_INCLUDED - -#include "agg_basics.h" -#include "agg_line_aa_basics.h" -#include "agg_vertex_sequence.h" - -namespace agg -{ - - //------------------------------------------------------------------------- - inline bool cmp_dist_start(int d) { return d > 0; } - inline bool cmp_dist_end(int d) { return d <= 0; } - - - - //-----------------------------------------------------------line_aa_vertex - // Vertex (x, y) with the distance to the next one. The last vertex has - // the distance between the last and the first points - struct line_aa_vertex - { - int x; - int y; - int len; - - line_aa_vertex() {} - line_aa_vertex(int x_, int y_) : - x(x_), - y(y_), - len(0) - { - } - - bool operator () (const line_aa_vertex& val) - { - double dx = val.x - x; - double dy = val.y - y; - return (len = uround(sqrt(dx * dx + dy * dy))) > - (line_subpixel_scale + line_subpixel_scale / 2); - } - }; - - - //----------------------------------------------------------outline_aa_join_e - enum outline_aa_join_e - { - outline_no_join, //-----outline_no_join - outline_miter_join, //-----outline_miter_join - outline_round_join, //-----outline_round_join - outline_miter_accurate_join //-----outline_accurate_join - }; - - //=======================================================rasterizer_outline_aa - template class rasterizer_outline_aa - { - private: - //------------------------------------------------------------------------ - struct draw_vars - { - unsigned idx; - int x1, y1, x2, y2; - line_parameters curr, next; - int lcurr, lnext; - int xb1, yb1, xb2, yb2; - unsigned flags; - }; - - void draw(draw_vars& dv, unsigned start, unsigned end); - - public: - typedef line_aa_vertex vertex_type; - typedef vertex_sequence vertex_storage_type; - - explicit rasterizer_outline_aa(Renderer& ren) : - m_ren(&ren), - m_line_join(ren.accurate_join_only() ? - outline_miter_accurate_join : - outline_round_join), - m_round_cap(false), - m_start_x(0), - m_start_y(0) - {} - void attach(Renderer& ren) { m_ren = &ren; } - - //------------------------------------------------------------------------ - void line_join(outline_aa_join_e join) - { - m_line_join = m_ren->accurate_join_only() ? - outline_miter_accurate_join : - join; - } - bool line_join() const { return m_line_join; } - - //------------------------------------------------------------------------ - void round_cap(bool v) { m_round_cap = v; } - bool round_cap() const { return m_round_cap; } - - //------------------------------------------------------------------------ - void move_to(int x, int y) - { - m_src_vertices.modify_last(vertex_type(m_start_x = x, m_start_y = y)); - } - - //------------------------------------------------------------------------ - void line_to(int x, int y) - { - m_src_vertices.add(vertex_type(x, y)); - } - - //------------------------------------------------------------------------ - void move_to_d(double x, double y) - { - move_to(Coord::conv(x), Coord::conv(y)); - } - - //------------------------------------------------------------------------ - void line_to_d(double x, double y) - { - line_to(Coord::conv(x), Coord::conv(y)); - } - - //------------------------------------------------------------------------ - void render(bool close_polygon); - - //------------------------------------------------------------------------ - void add_vertex(double x, double y, unsigned cmd) - { - if(is_move_to(cmd)) - { - render(false); - move_to_d(x, y); - } - else - { - if(is_end_poly(cmd)) - { - render(is_closed(cmd)); - if(is_closed(cmd)) - { - move_to(m_start_x, m_start_y); - } - } - else - { - line_to_d(x, y); - } - } - } - - //------------------------------------------------------------------------ - template - void add_path(VertexSource& vs, unsigned path_id=0) - { - double x; - double y; - - unsigned cmd; - vs.rewind(path_id); - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - add_vertex(x, y, cmd); - } - render(false); - } - - - //------------------------------------------------------------------------ - template - void render_all_paths(VertexSource& vs, - const ColorStorage& colors, - const PathId& path_id, - unsigned num_paths) - { - for(unsigned i = 0; i < num_paths; i++) - { - m_ren->color(colors[i]); - add_path(vs, path_id[i]); - } - } - - - //------------------------------------------------------------------------ - template void render_ctrl(Ctrl& c) - { - unsigned i; - for(i = 0; i < c.num_paths(); i++) - { - m_ren->color(c.color(i)); - add_path(c, i); - } - } - - private: - rasterizer_outline_aa(const rasterizer_outline_aa&); - const rasterizer_outline_aa& operator = - (const rasterizer_outline_aa&); - - Renderer* m_ren; - vertex_storage_type m_src_vertices; - outline_aa_join_e m_line_join; - bool m_round_cap; - int m_start_x; - int m_start_y; - }; - - - - - - - - - //---------------------------------------------------------------------------- - template - void rasterizer_outline_aa::draw(draw_vars& dv, - unsigned start, - unsigned end) - { - unsigned i; - const vertex_storage_type::value_type* v; - - for(i = start; i < end; i++) - { - if(m_line_join == outline_round_join) - { - dv.xb1 = dv.curr.x1 + (dv.curr.y2 - dv.curr.y1); - dv.yb1 = dv.curr.y1 - (dv.curr.x2 - dv.curr.x1); - dv.xb2 = dv.curr.x2 + (dv.curr.y2 - dv.curr.y1); - dv.yb2 = dv.curr.y2 - (dv.curr.x2 - dv.curr.x1); - } - - switch(dv.flags) - { - case 0: m_ren->line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break; - case 1: m_ren->line2(dv.curr, dv.xb2, dv.yb2); break; - case 2: m_ren->line1(dv.curr, dv.xb1, dv.yb1); break; - case 3: m_ren->line0(dv.curr); break; - } - - if(m_line_join == outline_round_join && (dv.flags & 2) == 0) - { - m_ren->pie(dv.curr.x2, dv.curr.y2, - dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), - dv.curr.y2 - (dv.curr.x2 - dv.curr.x1), - dv.curr.x2 + (dv.next.y2 - dv.next.y1), - dv.curr.y2 - (dv.next.x2 - dv.next.x1)); - } - - dv.x1 = dv.x2; - dv.y1 = dv.y2; - dv.lcurr = dv.lnext; - dv.lnext = m_src_vertices[dv.idx].len; - - ++dv.idx; - if(dv.idx >= m_src_vertices.size()) dv.idx = 0; - - v = &m_src_vertices[dv.idx]; - dv.x2 = v->x; - dv.y2 = v->y; - - dv.curr = dv.next; - dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); - dv.xb1 = dv.xb2; - dv.yb1 = dv.yb2; - - switch(m_line_join) - { - case outline_no_join: - dv.flags = 3; - break; - - case outline_miter_join: - dv.flags >>= 1; - dv.flags |= ((dv.curr.diagonal_quadrant() == - dv.next.diagonal_quadrant()) << 1); - if((dv.flags & 2) == 0) - { - bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); - } - break; - - case outline_round_join: - dv.flags >>= 1; - dv.flags |= ((dv.curr.diagonal_quadrant() == - dv.next.diagonal_quadrant()) << 1); - break; - - case outline_miter_accurate_join: - dv.flags = 0; - bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); - break; - } - } - } - - - - - //---------------------------------------------------------------------------- - template - void rasterizer_outline_aa::render(bool close_polygon) - { - m_src_vertices.close(close_polygon); - draw_vars dv; - const vertex_storage_type::value_type* v; - int x1; - int y1; - int x2; - int y2; - int lprev; - - if(close_polygon) - { - if(m_src_vertices.size() >= 3) - { - dv.idx = 2; - - v = &m_src_vertices[m_src_vertices.size() - 1]; - x1 = v->x; - y1 = v->y; - lprev = v->len; - - v = &m_src_vertices[0]; - x2 = v->x; - y2 = v->y; - dv.lcurr = v->len; - line_parameters prev(x1, y1, x2, y2, lprev); - - v = &m_src_vertices[1]; - dv.x1 = v->x; - dv.y1 = v->y; - dv.lnext = v->len; - dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr); - - v = &m_src_vertices[dv.idx]; - dv.x2 = v->x; - dv.y2 = v->y; - dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); - - dv.xb1 = 0; - dv.yb1 = 0; - dv.xb2 = 0; - dv.yb2 = 0; - - switch(m_line_join) - { - case outline_no_join: - dv.flags = 3; - break; - - case outline_miter_join: - case outline_round_join: - dv.flags = - (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) | - ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); - break; - - case outline_miter_accurate_join: - dv.flags = 0; - break; - } - - if((dv.flags & 1) == 0 && m_line_join != outline_round_join) - { - bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1); - } - - if((dv.flags & 2) == 0 && m_line_join != outline_round_join) - { - bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); - } - draw(dv, 0, m_src_vertices.size()); - } - } - else - { - switch(m_src_vertices.size()) - { - case 0: - case 1: - break; - - case 2: - { - v = &m_src_vertices[0]; - x1 = v->x; - y1 = v->y; - lprev = v->len; - v = &m_src_vertices[1]; - x2 = v->x; - y2 = v->y; - line_parameters lp(x1, y1, x2, y2, lprev); - if(m_round_cap) - { - m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); - } - m_ren->line3(lp, - x1 + (y2 - y1), - y1 - (x2 - x1), - x2 + (y2 - y1), - y2 - (x2 - x1)); - if(m_round_cap) - { - m_ren->semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1)); - } - } - break; - - case 3: - { - int x3, y3; - int lnext; - v = &m_src_vertices[0]; - x1 = v->x; - y1 = v->y; - lprev = v->len; - v = &m_src_vertices[1]; - x2 = v->x; - y2 = v->y; - lnext = v->len; - v = &m_src_vertices[2]; - x3 = v->x; - y3 = v->y; - line_parameters lp1(x1, y1, x2, y2, lprev); - line_parameters lp2(x2, y2, x3, y3, lnext); - - if(m_round_cap) - { - m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); - } - - if(m_line_join == outline_round_join) - { - m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1), - x2 + (y2 - y1), y2 - (x2 - x1)); - - m_ren->pie(x2, y2, x2 + (y2 - y1), y2 - (x2 - x1), - x2 + (y3 - y2), y2 - (x3 - x2)); - - m_ren->line3(lp2, x2 + (y3 - y2), y2 - (x3 - x2), - x3 + (y3 - y2), y3 - (x3 - x2)); - } - else - { - bisectrix(lp1, lp2, &dv.xb1, &dv.yb1); - m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1), - dv.xb1, dv.yb1); - - m_ren->line3(lp2, dv.xb1, dv.yb1, - x3 + (y3 - y2), y3 - (x3 - x2)); - } - if(m_round_cap) - { - m_ren->semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2)); - } - } - break; - - default: - { - dv.idx = 3; - - v = &m_src_vertices[0]; - x1 = v->x; - y1 = v->y; - lprev = v->len; - - v = &m_src_vertices[1]; - x2 = v->x; - y2 = v->y; - dv.lcurr = v->len; - line_parameters prev(x1, y1, x2, y2, lprev); - - v = &m_src_vertices[2]; - dv.x1 = v->x; - dv.y1 = v->y; - dv.lnext = v->len; - dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr); - - v = &m_src_vertices[dv.idx]; - dv.x2 = v->x; - dv.y2 = v->y; - dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); - - dv.xb1 = 0; - dv.yb1 = 0; - dv.xb2 = 0; - dv.yb2 = 0; - - switch(m_line_join) - { - case outline_no_join: - dv.flags = 3; - break; - - case outline_miter_join: - case outline_round_join: - dv.flags = - (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) | - ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); - break; - - case outline_miter_accurate_join: - dv.flags = 0; - break; - } - - if(m_round_cap) - { - m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); - } - if((dv.flags & 1) == 0) - { - if(m_line_join == outline_round_join) - { - m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1), - x2 + (y2 - y1), y2 - (x2 - x1)); - m_ren->pie(prev.x2, prev.y2, - x2 + (y2 - y1), y2 - (x2 - x1), - dv.curr.x1 + (dv.curr.y2 - dv.curr.y1), - dv.curr.y1 - (dv.curr.x2 - dv.curr.x1)); - } - else - { - bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1); - m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1), - dv.xb1, dv.yb1); - } - } - else - { - m_ren->line1(prev, - x1 + (y2 - y1), - y1 - (x2 - x1)); - } - if((dv.flags & 2) == 0 && m_line_join != outline_round_join) - { - bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); - } - - draw(dv, 1, m_src_vertices.size() - 2); - - if((dv.flags & 1) == 0) - { - if(m_line_join == outline_round_join) - { - m_ren->line3(dv.curr, - dv.curr.x1 + (dv.curr.y2 - dv.curr.y1), - dv.curr.y1 - (dv.curr.x2 - dv.curr.x1), - dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), - dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); - } - else - { - m_ren->line3(dv.curr, dv.xb1, dv.yb1, - dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), - dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); - } - } - else - { - m_ren->line2(dv.curr, - dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), - dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); - } - if(m_round_cap) - { - m_ren->semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2, - dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), - dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); - } - - } - break; - } - } - m_src_vertices.remove_all(); - } - - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_rasterizer_outline.h corsix-th-0.62/agg/include/agg_rasterizer_outline.h --- corsix-th-0.30/agg/include/agg_rasterizer_outline.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rasterizer_outline.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_RASTERIZER_OUTLINE_INCLUDED -#define AGG_RASTERIZER_OUTLINE_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - //======================================================rasterizer_outline - template class rasterizer_outline - { - public: - explicit rasterizer_outline(Renderer& ren) : - m_ren(&ren), - m_start_x(0), - m_start_y(0), - m_vertices(0) - {} - void attach(Renderer& ren) { m_ren = &ren; } - - - //-------------------------------------------------------------------- - void move_to(int x, int y) - { - m_vertices = 1; - m_ren->move_to(m_start_x = x, m_start_y = y); - } - - //-------------------------------------------------------------------- - void line_to(int x, int y) - { - ++m_vertices; - m_ren->line_to(x, y); - } - - //-------------------------------------------------------------------- - void move_to_d(double x, double y) - { - move_to(m_ren->coord(x), m_ren->coord(y)); - } - - //-------------------------------------------------------------------- - void line_to_d(double x, double y) - { - line_to(m_ren->coord(x), m_ren->coord(y)); - } - - //-------------------------------------------------------------------- - void close() - { - if(m_vertices > 2) - { - line_to(m_start_x, m_start_y); - } - m_vertices = 0; - } - - //-------------------------------------------------------------------- - void add_vertex(double x, double y, unsigned cmd) - { - if(is_move_to(cmd)) - { - move_to_d(x, y); - } - else - { - if(is_end_poly(cmd)) - { - if(is_closed(cmd)) close(); - } - else - { - line_to_d(x, y); - } - } - } - - - //-------------------------------------------------------------------- - template - void add_path(VertexSource& vs, unsigned path_id=0) - { - double x; - double y; - - unsigned cmd; - vs.rewind(path_id); - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - add_vertex(x, y, cmd); - } - } - - - //-------------------------------------------------------------------- - template - void render_all_paths(VertexSource& vs, - const ColorStorage& colors, - const PathId& path_id, - unsigned num_paths) - { - for(unsigned i = 0; i < num_paths; i++) - { - m_ren->line_color(colors[i]); - add_path(vs, path_id[i]); - } - } - - - //-------------------------------------------------------------------- - template void render_ctrl(Ctrl& c) - { - unsigned i; - for(i = 0; i < c.num_paths(); i++) - { - m_ren->line_color(c.color(i)); - add_path(c, i); - } - } - - - private: - Renderer* m_ren; - int m_start_x; - int m_start_y; - unsigned m_vertices; - }; - - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_rasterizer_scanline_aa.h corsix-th-0.62/agg/include/agg_rasterizer_scanline_aa.h --- corsix-th-0.30/agg/include/agg_rasterizer_scanline_aa.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rasterizer_scanline_aa.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,510 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// -// The author gratefully acknowleges the support of David Turner, -// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType -// libray - in producing this work. See http://www.freetype.org for details. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for 32-bit screen coordinates has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -#ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED -#define AGG_RASTERIZER_SCANLINE_AA_INCLUDED - -#include "agg_rasterizer_cells_aa.h" -#include "agg_rasterizer_sl_clip.h" -#include "agg_gamma_functions.h" - - -namespace agg -{ - - - //-----------------------------------------------------------------cell_aa - // A pixel cell. There're no constructors defined and it was done - // intentionally in order to avoid extra overhead when allocating an - // array of cells. - struct cell_aa - { - int x; - int y; - int cover; - int area; - - void initial() - { - x = 0x7FFFFFFF; - y = 0x7FFFFFFF; - cover = 0; - area = 0; - } - - void style(const cell_aa&) {} - - int not_equal(int ex, int ey, const cell_aa&) const - { - return (ex - x) | (ey - y); - } - }; - - - //==================================================rasterizer_scanline_aa - // Polygon rasterizer that is used to render filled polygons with - // high-quality Anti-Aliasing. Internally, by default, the class uses - // integer coordinates in format 24.8, i.e. 24 bits for integer part - // and 8 bits for fractional - see poly_subpixel_shift. This class can be - // used in the following way: - // - // 1. filling_rule(filling_rule_e ft) - optional. - // - // 2. gamma() - optional. - // - // 3. reset() - // - // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create - // more than one contour, but each contour must consist of at least 3 - // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3); - // is the absolute minimum of vertices that define a triangle. - // The algorithm does not check either the number of vertices nor - // coincidence of their coordinates, but in the worst case it just - // won't draw anything. - // The orger of the vertices (clockwise or counterclockwise) - // is important when using the non-zero filling rule (fill_non_zero). - // In this case the vertex order of all the contours must be the same - // if you want your intersecting polygons to be without "holes". - // You actually can use different vertices order. If the contours do not - // intersect each other the order is not important anyway. If they do, - // contours with the same vertex order will be rendered without "holes" - // while the intersecting contours with different orders will have "holes". - // - // filling_rule() and gamma() can be called anytime before "sweeping". - //------------------------------------------------------------------------ - template class rasterizer_scanline_aa - { - enum status - { - status_initial, - status_move_to, - status_line_to, - status_closed - }; - - public: - typedef Clip clip_type; - typedef typename Clip::conv_type conv_type; - typedef typename Clip::coord_type coord_type; - - enum aa_scale_e - { - aa_shift = 8, - aa_scale = 1 << aa_shift, - aa_mask = aa_scale - 1, - aa_scale2 = aa_scale * 2, - aa_mask2 = aa_scale2 - 1 - }; - - //-------------------------------------------------------------------- - rasterizer_scanline_aa() : - m_outline(), - m_clipper(), - m_filling_rule(fill_non_zero), - m_auto_close(true), - m_start_x(0), - m_start_y(0), - m_status(status_initial) - { - int i; - for(i = 0; i < aa_scale; i++) m_gamma[i] = i; - } - - //-------------------------------------------------------------------- - template - rasterizer_scanline_aa(const GammaF& gamma_function) : - m_outline(), - m_clipper(m_outline), - m_filling_rule(fill_non_zero), - m_auto_close(true), - m_start_x(0), - m_start_y(0), - m_status(status_initial) - { - gamma(gamma_function); - } - - //-------------------------------------------------------------------- - void reset(); - void reset_clipping(); - void clip_box(double x1, double y1, double x2, double y2); - void filling_rule(filling_rule_e filling_rule); - void auto_close(bool flag) { m_auto_close = flag; } - - //-------------------------------------------------------------------- - template void gamma(const GammaF& gamma_function) - { - int i; - for(i = 0; i < aa_scale; i++) - { - m_gamma[i] = uround(gamma_function(double(i) / aa_mask) * aa_mask); - } - } - - //-------------------------------------------------------------------- - unsigned apply_gamma(unsigned cover) const - { - return m_gamma[cover]; - } - - //-------------------------------------------------------------------- - void move_to(int x, int y); - void line_to(int x, int y); - void move_to_d(double x, double y); - void line_to_d(double x, double y); - void close_polygon(); - void add_vertex(double x, double y, unsigned cmd); - - void edge(int x1, int y1, int x2, int y2); - void edge_d(double x1, double y1, double x2, double y2); - - //------------------------------------------------------------------- - template - void add_path(VertexSource& vs, unsigned path_id=0) - { - double x; - double y; - - unsigned cmd; - vs.rewind(path_id); - if(m_outline.sorted()) reset(); - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - add_vertex(x, y, cmd); - } - } - - //-------------------------------------------------------------------- - int min_x() const { return m_outline.min_x(); } - int min_y() const { return m_outline.min_y(); } - int max_x() const { return m_outline.max_x(); } - int max_y() const { return m_outline.max_y(); } - - //-------------------------------------------------------------------- - void sort(); - bool rewind_scanlines(); - bool navigate_scanline(int y); - - //-------------------------------------------------------------------- - AGG_INLINE unsigned calculate_alpha(int area) const - { - int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift); - - if(cover < 0) cover = -cover; - if(m_filling_rule == fill_even_odd) - { - cover &= aa_mask2; - if(cover > aa_scale) - { - cover = aa_scale2 - cover; - } - } - if(cover > aa_mask) cover = aa_mask; - return m_gamma[cover]; - } - - //-------------------------------------------------------------------- - template bool sweep_scanline(Scanline& sl) - { - for(;;) - { - if(m_scan_y > m_outline.max_y()) return false; - sl.reset_spans(); - unsigned num_cells = m_outline.scanline_num_cells(m_scan_y); - const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y); - int cover = 0; - - while(num_cells) - { - const cell_aa* cur_cell = *cells; - int x = cur_cell->x; - int area = cur_cell->area; - unsigned alpha; - - cover += cur_cell->cover; - - //accumulate all cells with the same X - while(--num_cells) - { - cur_cell = *++cells; - if(cur_cell->x != x) break; - area += cur_cell->area; - cover += cur_cell->cover; - } - - if(area) - { - alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area); - if(alpha) - { - sl.add_cell(x, alpha); - } - x++; - } - - if(num_cells && cur_cell->x > x) - { - alpha = calculate_alpha(cover << (poly_subpixel_shift + 1)); - if(alpha) - { - sl.add_span(x, cur_cell->x - x, alpha); - } - } - } - - if(sl.num_spans()) break; - ++m_scan_y; - } - - sl.finalize(m_scan_y); - ++m_scan_y; - return true; - } - - //-------------------------------------------------------------------- - bool hit_test(int tx, int ty); - - - private: - //-------------------------------------------------------------------- - // Disable copying - rasterizer_scanline_aa(const rasterizer_scanline_aa&); - const rasterizer_scanline_aa& - operator = (const rasterizer_scanline_aa&); - - private: - rasterizer_cells_aa m_outline; - clip_type m_clipper; - int m_gamma[aa_scale]; - filling_rule_e m_filling_rule; - bool m_auto_close; - coord_type m_start_x; - coord_type m_start_y; - unsigned m_status; - int m_scan_y; - }; - - - - - - - - - - - - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::reset() - { - m_outline.reset(); - m_status = status_initial; - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::filling_rule(filling_rule_e filling_rule) - { - m_filling_rule = filling_rule; - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::clip_box(double x1, double y1, - double x2, double y2) - { - reset(); - m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), - conv_type::upscale(x2), conv_type::upscale(y2)); - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::reset_clipping() - { - reset(); - m_clipper.reset_clipping(); - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::close_polygon() - { - if(m_status == status_line_to) - { - m_clipper.line_to(m_outline, m_start_x, m_start_y); - m_status = status_closed; - } - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::move_to(int x, int y) - { - if(m_outline.sorted()) reset(); - if(m_auto_close) close_polygon(); - m_clipper.move_to(m_start_x = conv_type::downscale(x), - m_start_y = conv_type::downscale(y)); - m_status = status_move_to; - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::line_to(int x, int y) - { - m_clipper.line_to(m_outline, - conv_type::downscale(x), - conv_type::downscale(y)); - m_status = status_line_to; - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::move_to_d(double x, double y) - { - if(m_outline.sorted()) reset(); - if(m_auto_close) close_polygon(); - m_clipper.move_to(m_start_x = conv_type::upscale(x), - m_start_y = conv_type::upscale(y)); - m_status = status_move_to; - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::line_to_d(double x, double y) - { - m_clipper.line_to(m_outline, - conv_type::upscale(x), - conv_type::upscale(y)); - m_status = status_line_to; - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::add_vertex(double x, double y, unsigned cmd) - { - if(is_move_to(cmd)) - { - move_to_d(x, y); - } - else - if(is_vertex(cmd)) - { - line_to_d(x, y); - } - else - if(is_close(cmd)) - { - close_polygon(); - } - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::edge(int x1, int y1, int x2, int y2) - { - if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); - m_clipper.line_to(m_outline, - conv_type::downscale(x2), - conv_type::downscale(y2)); - m_status = status_move_to; - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::edge_d(double x1, double y1, - double x2, double y2) - { - if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); - m_clipper.line_to(m_outline, - conv_type::upscale(x2), - conv_type::upscale(y2)); - m_status = status_move_to; - } - - //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::sort() - { - if(m_auto_close) close_polygon(); - m_outline.sort_cells(); - } - - //------------------------------------------------------------------------ - template - AGG_INLINE bool rasterizer_scanline_aa::rewind_scanlines() - { - if(m_auto_close) close_polygon(); - m_outline.sort_cells(); - if(m_outline.total_cells() == 0) - { - return false; - } - m_scan_y = m_outline.min_y(); - return true; - } - - - //------------------------------------------------------------------------ - template - AGG_INLINE bool rasterizer_scanline_aa::navigate_scanline(int y) - { - if(m_auto_close) close_polygon(); - m_outline.sort_cells(); - if(m_outline.total_cells() == 0 || - y < m_outline.min_y() || - y > m_outline.max_y()) - { - return false; - } - m_scan_y = y; - return true; - } - - //------------------------------------------------------------------------ - template - bool rasterizer_scanline_aa::hit_test(int tx, int ty) - { - if(!navigate_scanline(ty)) return false; - scanline_hit_test sl(tx); - sweep_scanline(sl); - return sl.hit(); - } - - - -} - - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_rasterizer_sl_clip.h corsix-th-0.62/agg/include/agg_rasterizer_sl_clip.h --- corsix-th-0.30/agg/include/agg_rasterizer_sl_clip.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rasterizer_sl_clip.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,351 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_RASTERIZER_SL_CLIP_INCLUDED -#define AGG_RASTERIZER_SL_CLIP_INCLUDED - -#include "agg_clip_liang_barsky.h" - -namespace agg -{ - //--------------------------------------------------------poly_max_coord_e - enum poly_max_coord_e - { - poly_max_coord = (1 << 30) - 1 //----poly_max_coord - }; - - //------------------------------------------------------------ras_conv_int - struct ras_conv_int - { - typedef int coord_type; - static AGG_INLINE int mul_div(double a, double b, double c) - { - return iround(a * b / c); - } - static int xi(int v) { return v; } - static int yi(int v) { return v; } - static int upscale(double v) { return iround(v * poly_subpixel_scale); } - static int downscale(int v) { return v; } - }; - - //--------------------------------------------------------ras_conv_int_sat - struct ras_conv_int_sat - { - typedef int coord_type; - static AGG_INLINE int mul_div(double a, double b, double c) - { - return saturation::iround(a * b / c); - } - static int xi(int v) { return v; } - static int yi(int v) { return v; } - static int upscale(double v) - { - return saturation::iround(v * poly_subpixel_scale); - } - static int downscale(int v) { return v; } - }; - - //---------------------------------------------------------ras_conv_int_3x - struct ras_conv_int_3x - { - typedef int coord_type; - static AGG_INLINE int mul_div(double a, double b, double c) - { - return iround(a * b / c); - } - static int xi(int v) { return v * 3; } - static int yi(int v) { return v; } - static int upscale(double v) { return iround(v * poly_subpixel_scale); } - static int downscale(int v) { return v; } - }; - - //-----------------------------------------------------------ras_conv_dbl - struct ras_conv_dbl - { - typedef double coord_type; - static AGG_INLINE double mul_div(double a, double b, double c) - { - return a * b / c; - } - static int xi(double v) { return iround(v * poly_subpixel_scale); } - static int yi(double v) { return iround(v * poly_subpixel_scale); } - static double upscale(double v) { return v; } - static double downscale(int v) { return v / double(poly_subpixel_scale); } - }; - - //--------------------------------------------------------ras_conv_dbl_3x - struct ras_conv_dbl_3x - { - typedef double coord_type; - static AGG_INLINE double mul_div(double a, double b, double c) - { - return a * b / c; - } - static int xi(double v) { return iround(v * poly_subpixel_scale * 3); } - static int yi(double v) { return iround(v * poly_subpixel_scale); } - static double upscale(double v) { return v; } - static double downscale(int v) { return v / double(poly_subpixel_scale); } - }; - - - - - - //------------------------------------------------------rasterizer_sl_clip - template class rasterizer_sl_clip - { - public: - typedef Conv conv_type; - typedef typename Conv::coord_type coord_type; - typedef rect_base rect_type; - - //-------------------------------------------------------------------- - rasterizer_sl_clip() : - m_clip_box(0,0,0,0), - m_x1(0), - m_y1(0), - m_f1(0), - m_clipping(false) - {} - - //-------------------------------------------------------------------- - void reset_clipping() - { - m_clipping = false; - } - - //-------------------------------------------------------------------- - void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) - { - m_clip_box = rect_type(x1, y1, x2, y2); - m_clip_box.normalize(); - m_clipping = true; - } - - //-------------------------------------------------------------------- - void move_to(coord_type x1, coord_type y1) - { - m_x1 = x1; - m_y1 = y1; - if(m_clipping) m_f1 = clipping_flags(x1, y1, m_clip_box); - } - - private: - //------------------------------------------------------------------------ - template - AGG_INLINE void line_clip_y(Rasterizer& ras, - coord_type x1, coord_type y1, - coord_type x2, coord_type y2, - unsigned f1, unsigned f2) const - { - f1 &= 10; - f2 &= 10; - if((f1 | f2) == 0) - { - // Fully visible - ras.line(Conv::xi(x1), Conv::yi(y1), Conv::xi(x2), Conv::yi(y2)); - } - else - { - if(f1 == f2) - { - // Invisible by Y - return; - } - - coord_type tx1 = x1; - coord_type ty1 = y1; - coord_type tx2 = x2; - coord_type ty2 = y2; - - if(f1 & 8) // y1 < clip.y1 - { - tx1 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1); - ty1 = m_clip_box.y1; - } - - if(f1 & 2) // y1 > clip.y2 - { - tx1 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1); - ty1 = m_clip_box.y2; - } - - if(f2 & 8) // y2 < clip.y1 - { - tx2 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1); - ty2 = m_clip_box.y1; - } - - if(f2 & 2) // y2 > clip.y2 - { - tx2 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1); - ty2 = m_clip_box.y2; - } - ras.line(Conv::xi(tx1), Conv::yi(ty1), - Conv::xi(tx2), Conv::yi(ty2)); - } - } - - - public: - //-------------------------------------------------------------------- - template - void line_to(Rasterizer& ras, coord_type x2, coord_type y2) - { - if(m_clipping) - { - unsigned f2 = clipping_flags(x2, y2, m_clip_box); - - if((m_f1 & 10) == (f2 & 10) && (m_f1 & 10) != 0) - { - // Invisible by Y - m_x1 = x2; - m_y1 = y2; - m_f1 = f2; - return; - } - - coord_type x1 = m_x1; - coord_type y1 = m_y1; - unsigned f1 = m_f1; - coord_type y3, y4; - unsigned f3, f4; - - switch(((f1 & 5) << 1) | (f2 & 5)) - { - case 0: // Visible by X - line_clip_y(ras, x1, y1, x2, y2, f1, f2); - break; - - case 1: // x2 > clip.x2 - y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); - f3 = clipping_flags_y(y3, m_clip_box); - line_clip_y(ras, x1, y1, m_clip_box.x2, y3, f1, f3); - line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x2, y2, f3, f2); - break; - - case 2: // x1 > clip.x2 - y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); - f3 = clipping_flags_y(y3, m_clip_box); - line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3); - line_clip_y(ras, m_clip_box.x2, y3, x2, y2, f3, f2); - break; - - case 3: // x1 > clip.x2 && x2 > clip.x2 - line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y2, f1, f2); - break; - - case 4: // x2 < clip.x1 - y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); - f3 = clipping_flags_y(y3, m_clip_box); - line_clip_y(ras, x1, y1, m_clip_box.x1, y3, f1, f3); - line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x1, y2, f3, f2); - break; - - case 6: // x1 > clip.x2 && x2 < clip.x1 - y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); - y4 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); - f3 = clipping_flags_y(y3, m_clip_box); - f4 = clipping_flags_y(y4, m_clip_box); - line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3); - line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x1, y4, f3, f4); - line_clip_y(ras, m_clip_box.x1, y4, m_clip_box.x1, y2, f4, f2); - break; - - case 8: // x1 < clip.x1 - y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); - f3 = clipping_flags_y(y3, m_clip_box); - line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3); - line_clip_y(ras, m_clip_box.x1, y3, x2, y2, f3, f2); - break; - - case 9: // x1 < clip.x1 && x2 > clip.x2 - y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); - y4 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); - f3 = clipping_flags_y(y3, m_clip_box); - f4 = clipping_flags_y(y4, m_clip_box); - line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3); - line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x2, y4, f3, f4); - line_clip_y(ras, m_clip_box.x2, y4, m_clip_box.x2, y2, f4, f2); - break; - - case 12: // x1 < clip.x1 && x2 < clip.x1 - line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y2, f1, f2); - break; - } - m_f1 = f2; - } - else - { - ras.line(Conv::xi(m_x1), Conv::yi(m_y1), - Conv::xi(x2), Conv::yi(y2)); - } - m_x1 = x2; - m_y1 = y2; - } - - - private: - rect_type m_clip_box; - coord_type m_x1; - coord_type m_y1; - unsigned m_f1; - bool m_clipping; - }; - - - - - //---------------------------------------------------rasterizer_sl_no_clip - class rasterizer_sl_no_clip - { - public: - typedef ras_conv_int conv_type; - typedef int coord_type; - - rasterizer_sl_no_clip() : m_x1(0), m_y1(0) {} - - void reset_clipping() {} - void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) {} - void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; } - - template - void line_to(Rasterizer& ras, coord_type x2, coord_type y2) - { - ras.line(m_x1, m_y1, x2, y2); - m_x1 = x2; - m_y1 = y2; - } - - private: - int m_x1, m_y1; - }; - - - // -----rasterizer_sl_clip_int - // -----rasterizer_sl_clip_int_sat - // -----rasterizer_sl_clip_int_3x - // -----rasterizer_sl_clip_dbl - // -----rasterizer_sl_clip_dbl_3x - //------------------------------------------------------------------------ - typedef rasterizer_sl_clip rasterizer_sl_clip_int; - typedef rasterizer_sl_clip rasterizer_sl_clip_int_sat; - typedef rasterizer_sl_clip rasterizer_sl_clip_int_3x; - typedef rasterizer_sl_clip rasterizer_sl_clip_dbl; - typedef rasterizer_sl_clip rasterizer_sl_clip_dbl_3x; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_renderer_base.h corsix-th-0.62/agg/include/agg_renderer_base.h --- corsix-th-0.30/agg/include/agg_renderer_base.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_renderer_base.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,718 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class renderer_base -// -//---------------------------------------------------------------------------- - -#ifndef AGG_RENDERER_BASE_INCLUDED -#define AGG_RENDERER_BASE_INCLUDED - -#include "agg_basics.h" -#include "agg_rendering_buffer.h" - -namespace agg -{ - - //-----------------------------------------------------------renderer_base - template class renderer_base - { - public: - typedef PixelFormat pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::row_data row_data; - - //-------------------------------------------------------------------- - renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {} - explicit renderer_base(pixfmt_type& ren) : - m_ren(&ren), - m_clip_box(0, 0, ren.width() - 1, ren.height() - 1) - {} - void attach(pixfmt_type& ren) - { - m_ren = &ren; - m_clip_box = rect_i(0, 0, ren.width() - 1, ren.height() - 1); - } - - //-------------------------------------------------------------------- - const pixfmt_type& ren() const { return *m_ren; } - pixfmt_type& ren() { return *m_ren; } - - //-------------------------------------------------------------------- - unsigned width() const { return m_ren->width(); } - unsigned height() const { return m_ren->height(); } - - //-------------------------------------------------------------------- - bool clip_box(int x1, int y1, int x2, int y2) - { - rect_i cb(x1, y1, x2, y2); - cb.normalize(); - if(cb.clip(rect_i(0, 0, width() - 1, height() - 1))) - { - m_clip_box = cb; - return true; - } - m_clip_box.x1 = 1; - m_clip_box.y1 = 1; - m_clip_box.x2 = 0; - m_clip_box.y2 = 0; - return false; - } - - //-------------------------------------------------------------------- - void reset_clipping(bool visibility) - { - if(visibility) - { - m_clip_box.x1 = 0; - m_clip_box.y1 = 0; - m_clip_box.x2 = width() - 1; - m_clip_box.y2 = height() - 1; - } - else - { - m_clip_box.x1 = 1; - m_clip_box.y1 = 1; - m_clip_box.x2 = 0; - m_clip_box.y2 = 0; - } - } - - //-------------------------------------------------------------------- - void clip_box_naked(int x1, int y1, int x2, int y2) - { - m_clip_box.x1 = x1; - m_clip_box.y1 = y1; - m_clip_box.x2 = x2; - m_clip_box.y2 = y2; - } - - //-------------------------------------------------------------------- - bool inbox(int x, int y) const - { - return x >= m_clip_box.x1 && y >= m_clip_box.y1 && - x <= m_clip_box.x2 && y <= m_clip_box.y2; - } - - //-------------------------------------------------------------------- - const rect_i& clip_box() const { return m_clip_box; } - int xmin() const { return m_clip_box.x1; } - int ymin() const { return m_clip_box.y1; } - int xmax() const { return m_clip_box.x2; } - int ymax() const { return m_clip_box.y2; } - - //-------------------------------------------------------------------- - const rect_i& bounding_clip_box() const { return m_clip_box; } - int bounding_xmin() const { return m_clip_box.x1; } - int bounding_ymin() const { return m_clip_box.y1; } - int bounding_xmax() const { return m_clip_box.x2; } - int bounding_ymax() const { return m_clip_box.y2; } - - //-------------------------------------------------------------------- - void clear(const color_type& c) - { - unsigned y; - if(width()) - { - for(y = 0; y < height(); y++) - { - m_ren->copy_hline(0, y, width(), c); - } - } - } - - - //-------------------------------------------------------------------- - void copy_pixel(int x, int y, const color_type& c) - { - if(inbox(x, y)) - { - m_ren->copy_pixel(x, y, c); - } - } - - //-------------------------------------------------------------------- - void blend_pixel(int x, int y, const color_type& c, cover_type cover) - { - if(inbox(x, y)) - { - m_ren->blend_pixel(x, y, c, cover); - } - } - - //-------------------------------------------------------------------- - color_type pixel(int x, int y) const - { - return inbox(x, y) ? - m_ren->pixel(x, y) : - color_type::no_color(); - } - - //-------------------------------------------------------------------- - void copy_hline(int x1, int y, int x2, const color_type& c) - { - if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } - if(y > ymax()) return; - if(y < ymin()) return; - if(x1 > xmax()) return; - if(x2 < xmin()) return; - - if(x1 < xmin()) x1 = xmin(); - if(x2 > xmax()) x2 = xmax(); - - m_ren->copy_hline(x1, y, x2 - x1 + 1, c); - } - - //-------------------------------------------------------------------- - void copy_vline(int x, int y1, int y2, const color_type& c) - { - if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } - if(x > xmax()) return; - if(x < xmin()) return; - if(y1 > ymax()) return; - if(y2 < ymin()) return; - - if(y1 < ymin()) y1 = ymin(); - if(y2 > ymax()) y2 = ymax(); - - m_ren->copy_vline(x, y1, y2 - y1 + 1, c); - } - - //-------------------------------------------------------------------- - void blend_hline(int x1, int y, int x2, - const color_type& c, cover_type cover) - { - if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } - if(y > ymax()) return; - if(y < ymin()) return; - if(x1 > xmax()) return; - if(x2 < xmin()) return; - - if(x1 < xmin()) x1 = xmin(); - if(x2 > xmax()) x2 = xmax(); - - m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover); - } - - //-------------------------------------------------------------------- - void blend_vline(int x, int y1, int y2, - const color_type& c, cover_type cover) - { - if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } - if(x > xmax()) return; - if(x < xmin()) return; - if(y1 > ymax()) return; - if(y2 < ymin()) return; - - if(y1 < ymin()) y1 = ymin(); - if(y2 > ymax()) y2 = ymax(); - - m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover); - } - - - //-------------------------------------------------------------------- - void copy_bar(int x1, int y1, int x2, int y2, const color_type& c) - { - rect_i rc(x1, y1, x2, y2); - rc.normalize(); - if(rc.clip(clip_box())) - { - int y; - for(y = rc.y1; y <= rc.y2; y++) - { - m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c); - } - } - } - - //-------------------------------------------------------------------- - void blend_bar(int x1, int y1, int x2, int y2, - const color_type& c, cover_type cover) - { - rect_i rc(x1, y1, x2, y2); - rc.normalize(); - if(rc.clip(clip_box())) - { - int y; - for(y = rc.y1; y <= rc.y2; y++) - { - m_ren->blend_hline(rc.x1, - y, - unsigned(rc.x2 - rc.x1 + 1), - c, - cover); - } - } - } - - //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, int len, - const color_type& c, - const cover_type* covers) - { - if(y > ymax()) return; - if(y < ymin()) return; - - if(x < xmin()) - { - len -= xmin() - x; - if(len <= 0) return; - covers += xmin() - x; - x = xmin(); - } - if(x + len > xmax()) - { - len = xmax() - x + 1; - if(len <= 0) return; - } - m_ren->blend_solid_hspan(x, y, len, c, covers); - } - - //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, int len, - const color_type& c, - const cover_type* covers) - { - if(x > xmax()) return; - if(x < xmin()) return; - - if(y < ymin()) - { - len -= ymin() - y; - if(len <= 0) return; - covers += ymin() - y; - y = ymin(); - } - if(y + len > ymax()) - { - len = ymax() - y + 1; - if(len <= 0) return; - } - m_ren->blend_solid_vspan(x, y, len, c, covers); - } - - - //-------------------------------------------------------------------- - void copy_color_hspan(int x, int y, int len, const color_type* colors) - { - if(y > ymax()) return; - if(y < ymin()) return; - - if(x < xmin()) - { - int d = xmin() - x; - len -= d; - if(len <= 0) return; - colors += d; - x = xmin(); - } - if(x + len > xmax()) - { - len = xmax() - x + 1; - if(len <= 0) return; - } - m_ren->copy_color_hspan(x, y, len, colors); - } - - - //-------------------------------------------------------------------- - void copy_color_vspan(int x, int y, int len, const color_type* colors) - { - if(x > xmax()) return; - if(x < xmin()) return; - - if(y < ymin()) - { - int d = ymin() - y; - len -= d; - if(len <= 0) return; - colors += d; - y = ymin(); - } - if(y + len > ymax()) - { - len = ymax() - y + 1; - if(len <= 0) return; - } - m_ren->copy_color_vspan(x, y, len, colors); - } - - - //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, int len, - const color_type* colors, - const cover_type* covers, - cover_type cover = agg::cover_full) - { - if(y > ymax()) return; - if(y < ymin()) return; - - if(x < xmin()) - { - int d = xmin() - x; - len -= d; - if(len <= 0) return; - if(covers) covers += d; - colors += d; - x = xmin(); - } - if(x + len > xmax()) - { - len = xmax() - x + 1; - if(len <= 0) return; - } - m_ren->blend_color_hspan(x, y, len, colors, covers, cover); - } - - //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, int len, - const color_type* colors, - const cover_type* covers, - cover_type cover = agg::cover_full) - { - if(x > xmax()) return; - if(x < xmin()) return; - - if(y < ymin()) - { - int d = ymin() - y; - len -= d; - if(len <= 0) return; - if(covers) covers += d; - colors += d; - y = ymin(); - } - if(y + len > ymax()) - { - len = ymax() - y + 1; - if(len <= 0) return; - } - m_ren->blend_color_vspan(x, y, len, colors, covers, cover); - } - - //-------------------------------------------------------------------- - rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const - { - rect_i rc(0,0,0,0); - rect_i cb = clip_box(); - ++cb.x2; - ++cb.y2; - - if(src.x1 < 0) - { - dst.x1 -= src.x1; - src.x1 = 0; - } - if(src.y1 < 0) - { - dst.y1 -= src.y1; - src.y1 = 0; - } - - if(src.x2 > wsrc) src.x2 = wsrc; - if(src.y2 > hsrc) src.y2 = hsrc; - - if(dst.x1 < cb.x1) - { - src.x1 += cb.x1 - dst.x1; - dst.x1 = cb.x1; - } - if(dst.y1 < cb.y1) - { - src.y1 += cb.y1 - dst.y1; - dst.y1 = cb.y1; - } - - if(dst.x2 > cb.x2) dst.x2 = cb.x2; - if(dst.y2 > cb.y2) dst.y2 = cb.y2; - - rc.x2 = dst.x2 - dst.x1; - rc.y2 = dst.y2 - dst.y1; - - if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1; - if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1; - return rc; - } - - //-------------------------------------------------------------------- - template - void copy_from(const RenBuf& src, - const rect_i* rect_src_ptr = 0, - int dx = 0, - int dy = 0) - { - rect_i rsrc(0, 0, src.width(), src.height()); - if(rect_src_ptr) - { - rsrc.x1 = rect_src_ptr->x1; - rsrc.y1 = rect_src_ptr->y1; - rsrc.x2 = rect_src_ptr->x2 + 1; - rsrc.y2 = rect_src_ptr->y2 + 1; - } - - // Version with xdst, ydst (absolute positioning) - //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); - - // Version with dx, dy (relative positioning) - rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); - - rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); - - if(rc.x2 > 0) - { - int incy = 1; - if(rdst.y1 > rsrc.y1) - { - rsrc.y1 += rc.y2 - 1; - rdst.y1 += rc.y2 - 1; - incy = -1; - } - while(rc.y2 > 0) - { - m_ren->copy_from(src, - rdst.x1, rdst.y1, - rsrc.x1, rsrc.y1, - rc.x2); - rdst.y1 += incy; - rsrc.y1 += incy; - --rc.y2; - } - } - } - - //-------------------------------------------------------------------- - template - void blend_from(const SrcPixelFormatRenderer& src, - const rect_i* rect_src_ptr = 0, - int dx = 0, - int dy = 0, - cover_type cover = agg::cover_full) - { - rect_i rsrc(0, 0, src.width(), src.height()); - if(rect_src_ptr) - { - rsrc.x1 = rect_src_ptr->x1; - rsrc.y1 = rect_src_ptr->y1; - rsrc.x2 = rect_src_ptr->x2 + 1; - rsrc.y2 = rect_src_ptr->y2 + 1; - } - - // Version with xdst, ydst (absolute positioning) - //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); - - // Version with dx, dy (relative positioning) - rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); - rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); - - if(rc.x2 > 0) - { - int incy = 1; - if(rdst.y1 > rsrc.y1) - { - rsrc.y1 += rc.y2 - 1; - rdst.y1 += rc.y2 - 1; - incy = -1; - } - while(rc.y2 > 0) - { - typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); - if(rw.ptr) - { - int x1src = rsrc.x1; - int x1dst = rdst.x1; - int len = rc.x2; - if(rw.x1 > x1src) - { - x1dst += rw.x1 - x1src; - len -= rw.x1 - x1src; - x1src = rw.x1; - } - if(len > 0) - { - if(x1src + len-1 > rw.x2) - { - len -= x1src + len - rw.x2 - 1; - } - if(len > 0) - { - m_ren->blend_from(src, - x1dst, rdst.y1, - x1src, rsrc.y1, - len, - cover); - } - } - } - rdst.y1 += incy; - rsrc.y1 += incy; - --rc.y2; - } - } - } - - //-------------------------------------------------------------------- - template - void blend_from_color(const SrcPixelFormatRenderer& src, - const color_type& color, - const rect_i* rect_src_ptr = 0, - int dx = 0, - int dy = 0, - cover_type cover = agg::cover_full) - { - rect_i rsrc(0, 0, src.width(), src.height()); - if(rect_src_ptr) - { - rsrc.x1 = rect_src_ptr->x1; - rsrc.y1 = rect_src_ptr->y1; - rsrc.x2 = rect_src_ptr->x2 + 1; - rsrc.y2 = rect_src_ptr->y2 + 1; - } - - // Version with xdst, ydst (absolute positioning) - //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); - - // Version with dx, dy (relative positioning) - rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); - rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); - - if(rc.x2 > 0) - { - int incy = 1; - if(rdst.y1 > rsrc.y1) - { - rsrc.y1 += rc.y2 - 1; - rdst.y1 += rc.y2 - 1; - incy = -1; - } - while(rc.y2 > 0) - { - typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); - if(rw.ptr) - { - int x1src = rsrc.x1; - int x1dst = rdst.x1; - int len = rc.x2; - if(rw.x1 > x1src) - { - x1dst += rw.x1 - x1src; - len -= rw.x1 - x1src; - x1src = rw.x1; - } - if(len > 0) - { - if(x1src + len-1 > rw.x2) - { - len -= x1src + len - rw.x2 - 1; - } - if(len > 0) - { - m_ren->blend_from_color(src, - color, - x1dst, rdst.y1, - x1src, rsrc.y1, - len, - cover); - } - } - } - rdst.y1 += incy; - rsrc.y1 += incy; - --rc.y2; - } - } - } - - //-------------------------------------------------------------------- - template - void blend_from_lut(const SrcPixelFormatRenderer& src, - const color_type* color_lut, - const rect_i* rect_src_ptr = 0, - int dx = 0, - int dy = 0, - cover_type cover = agg::cover_full) - { - rect_i rsrc(0, 0, src.width(), src.height()); - if(rect_src_ptr) - { - rsrc.x1 = rect_src_ptr->x1; - rsrc.y1 = rect_src_ptr->y1; - rsrc.x2 = rect_src_ptr->x2 + 1; - rsrc.y2 = rect_src_ptr->y2 + 1; - } - - // Version with xdst, ydst (absolute positioning) - //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); - - // Version with dx, dy (relative positioning) - rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); - rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); - - if(rc.x2 > 0) - { - int incy = 1; - if(rdst.y1 > rsrc.y1) - { - rsrc.y1 += rc.y2 - 1; - rdst.y1 += rc.y2 - 1; - incy = -1; - } - while(rc.y2 > 0) - { - typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); - if(rw.ptr) - { - int x1src = rsrc.x1; - int x1dst = rdst.x1; - int len = rc.x2; - if(rw.x1 > x1src) - { - x1dst += rw.x1 - x1src; - len -= rw.x1 - x1src; - x1src = rw.x1; - } - if(len > 0) - { - if(x1src + len-1 > rw.x2) - { - len -= x1src + len - rw.x2 - 1; - } - if(len > 0) - { - m_ren->blend_from_lut(src, - color_lut, - x1dst, rdst.y1, - x1src, rsrc.y1, - len, - cover); - } - } - } - rdst.y1 += incy; - rsrc.y1 += incy; - --rc.y2; - } - } - } - - private: - pixfmt_type* m_ren; - rect_i m_clip_box; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_renderer_markers.h corsix-th-0.62/agg/include/agg_renderer_markers.h --- corsix-th-0.30/agg/include/agg_renderer_markers.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_renderer_markers.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,706 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class renderer_markers -// -//---------------------------------------------------------------------------- - -#ifndef AGG_RENDERER_MARKERS_INCLUDED -#define AGG_RENDERER_MARKERS_INCLUDED - -#include "agg_basics.h" -#include "agg_renderer_primitives.h" - -namespace agg -{ - - //---------------------------------------------------------------marker_e - enum marker_e - { - marker_square, - marker_diamond, - marker_circle, - marker_crossed_circle, - marker_semiellipse_left, - marker_semiellipse_right, - marker_semiellipse_up, - marker_semiellipse_down, - marker_triangle_left, - marker_triangle_right, - marker_triangle_up, - marker_triangle_down, - marker_four_rays, - marker_cross, - marker_x, - marker_dash, - marker_dot, - marker_pixel, - - end_of_markers - }; - - - - //--------------------------------------------------------renderer_markers - template class renderer_markers : - public renderer_primitives - { - public: - typedef renderer_primitives base_type; - typedef BaseRenderer base_ren_type; - typedef typename base_ren_type::color_type color_type; - - //-------------------------------------------------------------------- - renderer_markers(base_ren_type& rbuf) : - base_type(rbuf) - {} - - //-------------------------------------------------------------------- - bool visible(int x, int y, int r) const - { - rect_i rc(x-r, y-r, x+y, y+r); - return rc.clip(base_type::ren().bounding_clip_box()); - } - - //-------------------------------------------------------------------- - void square(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) base_type::outlined_rectangle(x-r, y-r, x+r, y+r); - else base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - - //-------------------------------------------------------------------- - void diamond(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int dy = -r; - int dx = 0; - do - { - base_type::ren().blend_pixel(x - dx, y + dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dx, y + dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dx, y - dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dx, y - dy, base_type::line_color(), cover_full); - - if(dx) - { - base_type::ren().blend_hline(x-dx+1, y+dy, x+dx-1, base_type::fill_color(), cover_full); - base_type::ren().blend_hline(x-dx+1, y-dy, x+dx-1, base_type::fill_color(), cover_full); - } - ++dy; - ++dx; - } - while(dy <= 0); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - //-------------------------------------------------------------------- - void circle(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) base_type::outlined_ellipse(x, y, r, r); - else base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - - - - //-------------------------------------------------------------------- - void crossed_circle(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - base_type::outlined_ellipse(x, y, r, r); - int r6 = r + (r >> 1); - if(r <= 2) r6++; - r >>= 1; - base_type::ren().blend_hline(x-r6, y, x-r, base_type::line_color(), cover_full); - base_type::ren().blend_hline(x+r, y, x+r6, base_type::line_color(), cover_full); - base_type::ren().blend_vline(x, y-r6, y-r, base_type::line_color(), cover_full); - base_type::ren().blend_vline(x, y+r, y+r6, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //------------------------------------------------------------------------ - void semiellipse_left(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int r8 = r * 4 / 5; - int dy = -r; - int dx = 0; - ellipse_bresenham_interpolator ei(r * 3 / 5, r+r8); - do - { - dx += ei.dx(); - dy += ei.dy(); - - base_type::ren().blend_pixel(x + dy, y + dx, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dy, y - dx, base_type::line_color(), cover_full); - - if(ei.dy() && dx) - { - base_type::ren().blend_vline(x+dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); - } - ++ei; - } - while(dy < r8); - base_type::ren().blend_vline(x+dy, y-dx, y+dx, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void semiellipse_right(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int r8 = r * 4 / 5; - int dy = -r; - int dx = 0; - ellipse_bresenham_interpolator ei(r * 3 / 5, r+r8); - do - { - dx += ei.dx(); - dy += ei.dy(); - - base_type::ren().blend_pixel(x - dy, y + dx, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dy, y - dx, base_type::line_color(), cover_full); - - if(ei.dy() && dx) - { - base_type::ren().blend_vline(x-dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); - } - ++ei; - } - while(dy < r8); - base_type::ren().blend_vline(x-dy, y-dx, y+dx, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void semiellipse_up(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int r8 = r * 4 / 5; - int dy = -r; - int dx = 0; - ellipse_bresenham_interpolator ei(r * 3 / 5, r+r8); - do - { - dx += ei.dx(); - dy += ei.dy(); - - base_type::ren().blend_pixel(x + dx, y - dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dx, y - dy, base_type::line_color(), cover_full); - - if(ei.dy() && dx) - { - base_type::ren().blend_hline(x-dx+1, y-dy, x+dx-1, base_type::fill_color(), cover_full); - } - ++ei; - } - while(dy < r8); - base_type::ren().blend_hline(x-dx, y-dy-1, x+dx, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void semiellipse_down(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int r8 = r * 4 / 5; - int dy = -r; - int dx = 0; - ellipse_bresenham_interpolator ei(r * 3 / 5, r+r8); - do - { - dx += ei.dx(); - dy += ei.dy(); - - base_type::ren().blend_pixel(x + dx, y + dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dx, y + dy, base_type::line_color(), cover_full); - - if(ei.dy() && dx) - { - base_type::ren().blend_hline(x-dx+1, y+dy, x+dx-1, base_type::fill_color(), cover_full); - } - ++ei; - } - while(dy < r8); - base_type::ren().blend_hline(x-dx, y+dy+1, x+dx, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void triangle_left(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int dy = -r; - int dx = 0; - int flip = 0; - int r6 = r * 3 / 5; - do - { - base_type::ren().blend_pixel(x + dy, y - dx, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dy, y + dx, base_type::line_color(), cover_full); - - if(dx) - { - base_type::ren().blend_vline(x+dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); - } - ++dy; - dx += flip; - flip ^= 1; - } - while(dy < r6); - base_type::ren().blend_vline(x+dy, y-dx, y+dx, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void triangle_right(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int dy = -r; - int dx = 0; - int flip = 0; - int r6 = r * 3 / 5; - do - { - base_type::ren().blend_pixel(x - dy, y - dx, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dy, y + dx, base_type::line_color(), cover_full); - - if(dx) - { - base_type::ren().blend_vline(x-dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); - } - ++dy; - dx += flip; - flip ^= 1; - } - while(dy < r6); - base_type::ren().blend_vline(x-dy, y-dx, y+dx, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void triangle_up(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int dy = -r; - int dx = 0; - int flip = 0; - int r6 = r * 3 / 5; - do - { - base_type::ren().blend_pixel(x - dx, y - dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dx, y - dy, base_type::line_color(), cover_full); - - if(dx) - { - base_type::ren().blend_hline(x-dx+1, y-dy, x+dx-1, base_type::fill_color(), cover_full); - } - ++dy; - dx += flip; - flip ^= 1; - } - while(dy < r6); - base_type::ren().blend_hline(x-dx, y-dy, x+dx, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void triangle_down(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int dy = -r; - int dx = 0; - int flip = 0; - int r6 = r * 3 / 5; - do - { - base_type::ren().blend_pixel(x - dx, y + dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dx, y + dy, base_type::line_color(), cover_full); - - if(dx) - { - base_type::ren().blend_hline(x-dx+1, y+dy, x+dx-1, base_type::fill_color(), cover_full); - } - ++dy; - dx += flip; - flip ^= 1; - } - while(dy < r6); - base_type::ren().blend_hline(x-dx, y+dy, x+dx, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void four_rays(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int dy = -r; - int dx = 0; - int flip = 0; - int r3 = -(r / 3); - do - { - base_type::ren().blend_pixel(x - dx, y + dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dx, y + dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dx, y - dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dx, y - dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dy, y - dx, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dy, y + dx, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dy, y - dx, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dy, y + dx, base_type::line_color(), cover_full); - - if(dx) - { - base_type::ren().blend_hline(x-dx+1, y+dy, x+dx-1, base_type::fill_color(), cover_full); - base_type::ren().blend_hline(x-dx+1, y-dy, x+dx-1, base_type::fill_color(), cover_full); - base_type::ren().blend_vline(x+dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); - base_type::ren().blend_vline(x-dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); - } - ++dy; - dx += flip; - flip ^= 1; - } - while(dy <= r3); - base_type::solid_rectangle(x+r3+1, y+r3+1, x-r3-1, y-r3-1); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void cross(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - base_type::ren().blend_vline(x, y-r, y+r, base_type::line_color(), cover_full); - base_type::ren().blend_hline(x-r, y, x+r, base_type::line_color(), cover_full); - } - else - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - } - - - //-------------------------------------------------------------------- - void xing(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) - { - int dy = -r * 7 / 10; - do - { - base_type::ren().blend_pixel(x + dy, y + dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dy, y + dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x + dy, y - dy, base_type::line_color(), cover_full); - base_type::ren().blend_pixel(x - dy, y - dy, base_type::line_color(), cover_full); - ++dy; - } - while(dy < 0); - } - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - - - //-------------------------------------------------------------------- - void dash(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) base_type::ren().blend_hline(x-r, y, x+r, base_type::line_color(), cover_full); - else base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - - - //-------------------------------------------------------------------- - void dot(int x, int y, int r) - { - if(visible(x, y, r)) - { - if(r) base_type::solid_ellipse(x, y, r, r); - else base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - } - - //-------------------------------------------------------------------- - void pixel(int x, int y, int) - { - base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); - } - - //-------------------------------------------------------------------- - void marker(int x, int y, int r, marker_e type) - { - switch(type) - { - case marker_square: square(x, y, r); break; - case marker_diamond: diamond(x, y, r); break; - case marker_circle: circle(x, y, r); break; - case marker_crossed_circle: crossed_circle(x, y, r); break; - case marker_semiellipse_left: semiellipse_left(x, y, r); break; - case marker_semiellipse_right: semiellipse_right(x, y, r); break; - case marker_semiellipse_up: semiellipse_up(x, y, r); break; - case marker_semiellipse_down: semiellipse_down(x, y, r); break; - case marker_triangle_left: triangle_left(x, y, r); break; - case marker_triangle_right: triangle_right(x, y, r); break; - case marker_triangle_up: triangle_up(x, y, r); break; - case marker_triangle_down: triangle_down(x, y, r); break; - case marker_four_rays: four_rays(x, y, r); break; - case marker_cross: cross(x, y, r); break; - case marker_x: xing(x, y, r); break; - case marker_dash: dash(x, y, r); break; - case marker_dot: dot(x, y, r); break; - case marker_pixel: pixel(x, y, r); break; - } - } - - - //-------------------------------------------------------------------- - template - void markers(int n, const T* x, const T* y, T r, marker_e type) - { - if(n <= 0) return; - if(r == 0) - { - do - { - base_type::ren().blend_pixel(int(*x), int(*y), base_type::fill_color(), cover_full); - ++x; - ++y; - } - while(--n); - return; - } - - switch(type) - { - case marker_square: do { square (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_diamond: do { diamond (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_circle: do { circle (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_crossed_circle: do { crossed_circle (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_semiellipse_left: do { semiellipse_left (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_semiellipse_right: do { semiellipse_right(int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_semiellipse_up: do { semiellipse_up (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_semiellipse_down: do { semiellipse_down (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_triangle_left: do { triangle_left (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_triangle_right: do { triangle_right (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_triangle_up: do { triangle_up (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_triangle_down: do { triangle_down (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_four_rays: do { four_rays (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_cross: do { cross (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_x: do { xing (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_dash: do { dash (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_dot: do { dot (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - case marker_pixel: do { pixel (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; - } - } - - //-------------------------------------------------------------------- - template - void markers(int n, const T* x, const T* y, const T* r, marker_e type) - { - if(n <= 0) return; - switch(type) - { - case marker_square: do { square (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_diamond: do { diamond (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_circle: do { circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_crossed_circle: do { crossed_circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_semiellipse_left: do { semiellipse_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_semiellipse_right: do { semiellipse_right(int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_semiellipse_up: do { semiellipse_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_semiellipse_down: do { semiellipse_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_triangle_left: do { triangle_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_triangle_right: do { triangle_right (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_triangle_up: do { triangle_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_triangle_down: do { triangle_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_four_rays: do { four_rays (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_cross: do { cross (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_x: do { xing (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_dash: do { dash (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_dot: do { dot (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - case marker_pixel: do { pixel (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; - } - } - - //-------------------------------------------------------------------- - template - void markers(int n, const T* x, const T* y, const T* r, const color_type* fc, marker_e type) - { - if(n <= 0) return; - switch(type) - { - case marker_square: do { base_type::fill_color(*fc); square (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_diamond: do { base_type::fill_color(*fc); diamond (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_circle: do { base_type::fill_color(*fc); circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_crossed_circle: do { base_type::fill_color(*fc); crossed_circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_semiellipse_left: do { base_type::fill_color(*fc); semiellipse_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_semiellipse_right: do { base_type::fill_color(*fc); semiellipse_right(int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_semiellipse_up: do { base_type::fill_color(*fc); semiellipse_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_semiellipse_down: do { base_type::fill_color(*fc); semiellipse_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_triangle_left: do { base_type::fill_color(*fc); triangle_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_triangle_right: do { base_type::fill_color(*fc); triangle_right (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_triangle_up: do { base_type::fill_color(*fc); triangle_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_triangle_down: do { base_type::fill_color(*fc); triangle_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_four_rays: do { base_type::fill_color(*fc); four_rays (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_cross: do { base_type::fill_color(*fc); cross (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_x: do { base_type::fill_color(*fc); xing (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_dash: do { base_type::fill_color(*fc); dash (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_dot: do { base_type::fill_color(*fc); dot (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - case marker_pixel: do { base_type::fill_color(*fc); pixel (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; - } - } - - //-------------------------------------------------------------------- - template - void markers(int n, const T* x, const T* y, const T* r, const color_type* fc, const color_type* lc, marker_e type) - { - if(n <= 0) return; - switch(type) - { - case marker_square: do { base_type::fill_color(*fc); base_type::line_color(*lc); square (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_diamond: do { base_type::fill_color(*fc); base_type::line_color(*lc); diamond (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_circle: do { base_type::fill_color(*fc); base_type::line_color(*lc); circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_crossed_circle: do { base_type::fill_color(*fc); base_type::line_color(*lc); crossed_circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_semiellipse_left: do { base_type::fill_color(*fc); base_type::line_color(*lc); semiellipse_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_semiellipse_right: do { base_type::fill_color(*fc); base_type::line_color(*lc); semiellipse_right(int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_semiellipse_up: do { base_type::fill_color(*fc); base_type::line_color(*lc); semiellipse_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_semiellipse_down: do { base_type::fill_color(*fc); base_type::line_color(*lc); semiellipse_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_triangle_left: do { base_type::fill_color(*fc); base_type::line_color(*lc); triangle_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_triangle_right: do { base_type::fill_color(*fc); base_type::line_color(*lc); triangle_right (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_triangle_up: do { base_type::fill_color(*fc); base_type::line_color(*lc); triangle_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_triangle_down: do { base_type::fill_color(*fc); base_type::line_color(*lc); triangle_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_four_rays: do { base_type::fill_color(*fc); base_type::line_color(*lc); four_rays (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_cross: do { base_type::fill_color(*fc); base_type::line_color(*lc); cross (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_x: do { base_type::fill_color(*fc); base_type::line_color(*lc); xing (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_dash: do { base_type::fill_color(*fc); base_type::line_color(*lc); dash (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_dot: do { base_type::fill_color(*fc); base_type::line_color(*lc); dot (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - case marker_pixel: do { base_type::fill_color(*fc); base_type::line_color(*lc); pixel (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; - } - } - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_renderer_mclip.h corsix-th-0.62/agg/include/agg_renderer_mclip.h --- corsix-th-0.30/agg/include/agg_renderer_mclip.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_renderer_mclip.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,349 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class renderer_mclip -// -//---------------------------------------------------------------------------- - -#ifndef AGG_RENDERER_MCLIP_INCLUDED -#define AGG_RENDERER_MCLIP_INCLUDED - -#include "agg_basics.h" -#include "agg_array.h" -#include "agg_renderer_base.h" - -namespace agg -{ - - //----------------------------------------------------------renderer_mclip - template class renderer_mclip - { - public: - typedef PixelFormat pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::row_data row_data; - typedef renderer_base base_ren_type; - - //-------------------------------------------------------------------- - explicit renderer_mclip(pixfmt_type& pixf) : - m_ren(pixf), - m_curr_cb(0), - m_bounds(m_ren.xmin(), m_ren.ymin(), m_ren.xmax(), m_ren.ymax()) - {} - void attach(pixfmt_type& pixf) - { - m_ren.attach(pixf); - reset_clipping(true); - } - - //-------------------------------------------------------------------- - const pixfmt_type& ren() const { return m_ren.ren(); } - pixfmt_type& ren() { return m_ren.ren(); } - - //-------------------------------------------------------------------- - unsigned width() const { return m_ren.width(); } - unsigned height() const { return m_ren.height(); } - - //-------------------------------------------------------------------- - const rect_i& clip_box() const { return m_ren.clip_box(); } - int xmin() const { return m_ren.xmin(); } - int ymin() const { return m_ren.ymin(); } - int xmax() const { return m_ren.xmax(); } - int ymax() const { return m_ren.ymax(); } - - //-------------------------------------------------------------------- - const rect_i& bounding_clip_box() const { return m_bounds; } - int bounding_xmin() const { return m_bounds.x1; } - int bounding_ymin() const { return m_bounds.y1; } - int bounding_xmax() const { return m_bounds.x2; } - int bounding_ymax() const { return m_bounds.y2; } - - //-------------------------------------------------------------------- - void first_clip_box() - { - m_curr_cb = 0; - if(m_clip.size()) - { - const rect_i& cb = m_clip[0]; - m_ren.clip_box_naked(cb.x1, cb.y1, cb.x2, cb.y2); - } - } - - //-------------------------------------------------------------------- - bool next_clip_box() - { - if(++m_curr_cb < m_clip.size()) - { - const rect_i& cb = m_clip[m_curr_cb]; - m_ren.clip_box_naked(cb.x1, cb.y1, cb.x2, cb.y2); - return true; - } - return false; - } - - //-------------------------------------------------------------------- - void reset_clipping(bool visibility) - { - m_ren.reset_clipping(visibility); - m_clip.remove_all(); - m_curr_cb = 0; - m_bounds = m_ren.clip_box(); - } - - //-------------------------------------------------------------------- - void add_clip_box(int x1, int y1, int x2, int y2) - { - rect_i cb(x1, y1, x2, y2); - cb.normalize(); - if(cb.clip(rect_i(0, 0, width() - 1, height() - 1))) - { - m_clip.add(cb); - if(cb.x1 < m_bounds.x1) m_bounds.x1 = cb.x1; - if(cb.y1 < m_bounds.y1) m_bounds.y1 = cb.y1; - if(cb.x2 > m_bounds.x2) m_bounds.x2 = cb.x2; - if(cb.y2 > m_bounds.y2) m_bounds.y2 = cb.y2; - } - } - - //-------------------------------------------------------------------- - void clear(const color_type& c) - { - m_ren.clear(c); - } - - //-------------------------------------------------------------------- - void copy_pixel(int x, int y, const color_type& c) - { - first_clip_box(); - do - { - if(m_ren.inbox(x, y)) - { - m_ren.ren().copy_pixel(x, y, c); - break; - } - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void blend_pixel(int x, int y, const color_type& c, cover_type cover) - { - first_clip_box(); - do - { - if(m_ren.inbox(x, y)) - { - m_ren.ren().blend_pixel(x, y, c, cover); - break; - } - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - color_type pixel(int x, int y) const - { - first_clip_box(); - do - { - if(m_ren.inbox(x, y)) - { - return m_ren.ren().pixel(x, y); - } - } - while(next_clip_box()); - return color_type::no_color(); - } - - //-------------------------------------------------------------------- - void copy_hline(int x1, int y, int x2, const color_type& c) - { - first_clip_box(); - do - { - m_ren.copy_hline(x1, y, x2, c); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void copy_vline(int x, int y1, int y2, const color_type& c) - { - first_clip_box(); - do - { - m_ren.copy_vline(x, y1, y2, c); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void blend_hline(int x1, int y, int x2, - const color_type& c, cover_type cover) - { - first_clip_box(); - do - { - m_ren.blend_hline(x1, y, x2, c, cover); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void blend_vline(int x, int y1, int y2, - const color_type& c, cover_type cover) - { - first_clip_box(); - do - { - m_ren.blend_vline(x, y1, y2, c, cover); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void copy_bar(int x1, int y1, int x2, int y2, const color_type& c) - { - first_clip_box(); - do - { - m_ren.copy_bar(x1, y1, x2, y2, c); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void blend_bar(int x1, int y1, int x2, int y2, - const color_type& c, cover_type cover) - { - first_clip_box(); - do - { - m_ren.blend_bar(x1, y1, x2, y2, c, cover); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, int len, - const color_type& c, const cover_type* covers) - { - first_clip_box(); - do - { - m_ren.blend_solid_hspan(x, y, len, c, covers); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, int len, - const color_type& c, const cover_type* covers) - { - first_clip_box(); - do - { - m_ren.blend_solid_vspan(x, y, len, c, covers); - } - while(next_clip_box()); - } - - - //-------------------------------------------------------------------- - void copy_color_hspan(int x, int y, int len, const color_type* colors) - { - first_clip_box(); - do - { - m_ren.copy_color_hspan(x, y, len, colors); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, int len, - const color_type* colors, - const cover_type* covers, - cover_type cover = cover_full) - { - first_clip_box(); - do - { - m_ren.blend_color_hspan(x, y, len, colors, covers, cover); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, int len, - const color_type* colors, - const cover_type* covers, - cover_type cover = cover_full) - { - first_clip_box(); - do - { - m_ren.blend_color_vspan(x, y, len, colors, covers, cover); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - void copy_from(const rendering_buffer& from, - const rect_i* rc=0, - int x_to=0, - int y_to=0) - { - first_clip_box(); - do - { - m_ren.copy_from(from, rc, x_to, y_to); - } - while(next_clip_box()); - } - - //-------------------------------------------------------------------- - template - void blend_from(const SrcPixelFormatRenderer& src, - const rect_i* rect_src_ptr = 0, - int dx = 0, - int dy = 0, - cover_type cover = cover_full) - { - first_clip_box(); - do - { - m_ren.blend_from(src, rect_src_ptr, dx, dy, cover); - } - while(next_clip_box()); - } - - - private: - renderer_mclip(const renderer_mclip&); - const renderer_mclip& - operator = (const renderer_mclip&); - - base_ren_type m_ren; - pod_bvector m_clip; - unsigned m_curr_cb; - rect_i m_bounds; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_renderer_outline_aa.h corsix-th-0.62/agg/include/agg_renderer_outline_aa.h --- corsix-th-0.30/agg/include/agg_renderer_outline_aa.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_renderer_outline_aa.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1837 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_RENDERER_OUTLINE_AA_INCLUDED -#define AGG_RENDERER_OUTLINE_AA_INCLUDED - -#include "agg_array.h" -#include "agg_math.h" -#include "agg_line_aa_basics.h" -#include "agg_dda_line.h" -#include "agg_ellipse_bresenham.h" -#include "agg_renderer_base.h" -#include "agg_gamma_functions.h" -#include "agg_clip_liang_barsky.h" - -namespace agg -{ - - //===================================================distance_interpolator0 - class distance_interpolator0 - { - public: - //--------------------------------------------------------------------- - distance_interpolator0() {} - distance_interpolator0(int x1, int y1, int x2, int y2, int x, int y) : - m_dx(line_mr(x2) - line_mr(x1)), - m_dy(line_mr(y2) - line_mr(y1)), - m_dist((line_mr(x + line_subpixel_scale/2) - line_mr(x2)) * m_dy - - (line_mr(y + line_subpixel_scale/2) - line_mr(y2)) * m_dx) - { - m_dx <<= line_mr_subpixel_shift; - m_dy <<= line_mr_subpixel_shift; - } - - //--------------------------------------------------------------------- - void inc_x() { m_dist += m_dy; } - int dist() const { return m_dist; } - - private: - //--------------------------------------------------------------------- - int m_dx; - int m_dy; - int m_dist; - }; - - //==================================================distance_interpolator00 - class distance_interpolator00 - { - public: - //--------------------------------------------------------------------- - distance_interpolator00() {} - distance_interpolator00(int xc, int yc, - int x1, int y1, int x2, int y2, - int x, int y) : - m_dx1(line_mr(x1) - line_mr(xc)), - m_dy1(line_mr(y1) - line_mr(yc)), - m_dx2(line_mr(x2) - line_mr(xc)), - m_dy2(line_mr(y2) - line_mr(yc)), - m_dist1((line_mr(x + line_subpixel_scale/2) - line_mr(x1)) * m_dy1 - - (line_mr(y + line_subpixel_scale/2) - line_mr(y1)) * m_dx1), - m_dist2((line_mr(x + line_subpixel_scale/2) - line_mr(x2)) * m_dy2 - - (line_mr(y + line_subpixel_scale/2) - line_mr(y2)) * m_dx2) - { - m_dx1 <<= line_mr_subpixel_shift; - m_dy1 <<= line_mr_subpixel_shift; - m_dx2 <<= line_mr_subpixel_shift; - m_dy2 <<= line_mr_subpixel_shift; - } - - //--------------------------------------------------------------------- - void inc_x() { m_dist1 += m_dy1; m_dist2 += m_dy2; } - int dist1() const { return m_dist1; } - int dist2() const { return m_dist2; } - - private: - //--------------------------------------------------------------------- - int m_dx1; - int m_dy1; - int m_dx2; - int m_dy2; - int m_dist1; - int m_dist2; - }; - - //===================================================distance_interpolator1 - class distance_interpolator1 - { - public: - //--------------------------------------------------------------------- - distance_interpolator1() {} - distance_interpolator1(int x1, int y1, int x2, int y2, int x, int y) : - m_dx(x2 - x1), - m_dy(y2 - y1), - m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - - double(y + line_subpixel_scale/2 - y2) * double(m_dx))) - { - m_dx <<= line_subpixel_shift; - m_dy <<= line_subpixel_shift; - } - - //--------------------------------------------------------------------- - void inc_x() { m_dist += m_dy; } - void dec_x() { m_dist -= m_dy; } - void inc_y() { m_dist -= m_dx; } - void dec_y() { m_dist += m_dx; } - - //--------------------------------------------------------------------- - void inc_x(int dy) - { - m_dist += m_dy; - if(dy > 0) m_dist -= m_dx; - if(dy < 0) m_dist += m_dx; - } - - //--------------------------------------------------------------------- - void dec_x(int dy) - { - m_dist -= m_dy; - if(dy > 0) m_dist -= m_dx; - if(dy < 0) m_dist += m_dx; - } - - //--------------------------------------------------------------------- - void inc_y(int dx) - { - m_dist -= m_dx; - if(dx > 0) m_dist += m_dy; - if(dx < 0) m_dist -= m_dy; - } - - void dec_y(int dx) - //--------------------------------------------------------------------- - { - m_dist += m_dx; - if(dx > 0) m_dist += m_dy; - if(dx < 0) m_dist -= m_dy; - } - - //--------------------------------------------------------------------- - int dist() const { return m_dist; } - int dx() const { return m_dx; } - int dy() const { return m_dy; } - - private: - //--------------------------------------------------------------------- - int m_dx; - int m_dy; - int m_dist; - }; - - - - - - //===================================================distance_interpolator2 - class distance_interpolator2 - { - public: - //--------------------------------------------------------------------- - distance_interpolator2() {} - distance_interpolator2(int x1, int y1, int x2, int y2, - int sx, int sy, int x, int y) : - m_dx(x2 - x1), - m_dy(y2 - y1), - m_dx_start(line_mr(sx) - line_mr(x1)), - m_dy_start(line_mr(sy) - line_mr(y1)), - - m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - - double(y + line_subpixel_scale/2 - y2) * double(m_dx))), - - m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(sx)) * m_dy_start - - (line_mr(y + line_subpixel_scale/2) - line_mr(sy)) * m_dx_start) - { - m_dx <<= line_subpixel_shift; - m_dy <<= line_subpixel_shift; - m_dx_start <<= line_mr_subpixel_shift; - m_dy_start <<= line_mr_subpixel_shift; - } - - distance_interpolator2(int x1, int y1, int x2, int y2, - int ex, int ey, int x, int y, int) : - m_dx(x2 - x1), - m_dy(y2 - y1), - m_dx_start(line_mr(ex) - line_mr(x2)), - m_dy_start(line_mr(ey) - line_mr(y2)), - - m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - - double(y + line_subpixel_scale/2 - y2) * double(m_dx))), - - m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(ex)) * m_dy_start - - (line_mr(y + line_subpixel_scale/2) - line_mr(ey)) * m_dx_start) - { - m_dx <<= line_subpixel_shift; - m_dy <<= line_subpixel_shift; - m_dx_start <<= line_mr_subpixel_shift; - m_dy_start <<= line_mr_subpixel_shift; - } - - - //--------------------------------------------------------------------- - void inc_x() { m_dist += m_dy; m_dist_start += m_dy_start; } - void dec_x() { m_dist -= m_dy; m_dist_start -= m_dy_start; } - void inc_y() { m_dist -= m_dx; m_dist_start -= m_dx_start; } - void dec_y() { m_dist += m_dx; m_dist_start += m_dx_start; } - - //--------------------------------------------------------------------- - void inc_x(int dy) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - if(dy > 0) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - } - if(dy < 0) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - } - } - - //--------------------------------------------------------------------- - void dec_x(int dy) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - if(dy > 0) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - } - if(dy < 0) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - } - } - - //--------------------------------------------------------------------- - void inc_y(int dx) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - if(dx > 0) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - } - if(dx < 0) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - } - } - - //--------------------------------------------------------------------- - void dec_y(int dx) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - if(dx > 0) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - } - if(dx < 0) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - } - } - - //--------------------------------------------------------------------- - int dist() const { return m_dist; } - int dist_start() const { return m_dist_start; } - int dist_end() const { return m_dist_start; } - - //--------------------------------------------------------------------- - int dx() const { return m_dx; } - int dy() const { return m_dy; } - int dx_start() const { return m_dx_start; } - int dy_start() const { return m_dy_start; } - int dx_end() const { return m_dx_start; } - int dy_end() const { return m_dy_start; } - - private: - //--------------------------------------------------------------------- - int m_dx; - int m_dy; - int m_dx_start; - int m_dy_start; - - int m_dist; - int m_dist_start; - }; - - - - - - //===================================================distance_interpolator3 - class distance_interpolator3 - { - public: - //--------------------------------------------------------------------- - distance_interpolator3() {} - distance_interpolator3(int x1, int y1, int x2, int y2, - int sx, int sy, int ex, int ey, - int x, int y) : - m_dx(x2 - x1), - m_dy(y2 - y1), - m_dx_start(line_mr(sx) - line_mr(x1)), - m_dy_start(line_mr(sy) - line_mr(y1)), - m_dx_end(line_mr(ex) - line_mr(x2)), - m_dy_end(line_mr(ey) - line_mr(y2)), - - m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - - double(y + line_subpixel_scale/2 - y2) * double(m_dx))), - - m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(sx)) * m_dy_start - - (line_mr(y + line_subpixel_scale/2) - line_mr(sy)) * m_dx_start), - - m_dist_end((line_mr(x + line_subpixel_scale/2) - line_mr(ex)) * m_dy_end - - (line_mr(y + line_subpixel_scale/2) - line_mr(ey)) * m_dx_end) - { - m_dx <<= line_subpixel_shift; - m_dy <<= line_subpixel_shift; - m_dx_start <<= line_mr_subpixel_shift; - m_dy_start <<= line_mr_subpixel_shift; - m_dx_end <<= line_mr_subpixel_shift; - m_dy_end <<= line_mr_subpixel_shift; - } - - //--------------------------------------------------------------------- - void inc_x() { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_end += m_dy_end; } - void dec_x() { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_end -= m_dy_end; } - void inc_y() { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_end -= m_dx_end; } - void dec_y() { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_end += m_dx_end; } - - //--------------------------------------------------------------------- - void inc_x(int dy) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - m_dist_end += m_dy_end; - if(dy > 0) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - m_dist_end -= m_dx_end; - } - if(dy < 0) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - m_dist_end += m_dx_end; - } - } - - //--------------------------------------------------------------------- - void dec_x(int dy) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - m_dist_end -= m_dy_end; - if(dy > 0) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - m_dist_end -= m_dx_end; - } - if(dy < 0) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - m_dist_end += m_dx_end; - } - } - - //--------------------------------------------------------------------- - void inc_y(int dx) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - m_dist_end -= m_dx_end; - if(dx > 0) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - m_dist_end += m_dy_end; - } - if(dx < 0) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - m_dist_end -= m_dy_end; - } - } - - //--------------------------------------------------------------------- - void dec_y(int dx) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - m_dist_end += m_dx_end; - if(dx > 0) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - m_dist_end += m_dy_end; - } - if(dx < 0) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - m_dist_end -= m_dy_end; - } - } - - //--------------------------------------------------------------------- - int dist() const { return m_dist; } - int dist_start() const { return m_dist_start; } - int dist_end() const { return m_dist_end; } - - //--------------------------------------------------------------------- - int dx() const { return m_dx; } - int dy() const { return m_dy; } - int dx_start() const { return m_dx_start; } - int dy_start() const { return m_dy_start; } - int dx_end() const { return m_dx_end; } - int dy_end() const { return m_dy_end; } - - private: - //--------------------------------------------------------------------- - int m_dx; - int m_dy; - int m_dx_start; - int m_dy_start; - int m_dx_end; - int m_dy_end; - - int m_dist; - int m_dist_start; - int m_dist_end; - }; - - - - - - //================================================line_interpolator_aa_base - template class line_interpolator_aa_base - { - public: - typedef Renderer renderer_type; - typedef typename Renderer::color_type color_type; - - //--------------------------------------------------------------------- - enum max_half_width_e - { - max_half_width = 64 - }; - - //--------------------------------------------------------------------- - line_interpolator_aa_base(renderer_type& ren, const line_parameters& lp) : - m_lp(&lp), - m_li(lp.vertical ? line_dbl_hr(lp.x2 - lp.x1) : - line_dbl_hr(lp.y2 - lp.y1), - lp.vertical ? abs(lp.y2 - lp.y1) : - abs(lp.x2 - lp.x1) + 1), - m_ren(ren), - m_len((lp.vertical == (lp.inc > 0)) ? -lp.len : lp.len), - m_x(lp.x1 >> line_subpixel_shift), - m_y(lp.y1 >> line_subpixel_shift), - m_old_x(m_x), - m_old_y(m_y), - m_count((lp.vertical ? abs((lp.y2 >> line_subpixel_shift) - m_y) : - abs((lp.x2 >> line_subpixel_shift) - m_x))), - m_width(ren.subpixel_width()), - //m_max_extent(m_width >> (line_subpixel_shift - 2)), - m_max_extent((m_width + line_subpixel_mask) >> line_subpixel_shift), - m_step(0) - { - agg::dda2_line_interpolator li(0, lp.vertical ? - (lp.dy << agg::line_subpixel_shift) : - (lp.dx << agg::line_subpixel_shift), - lp.len); - - unsigned i; - int stop = m_width + line_subpixel_scale * 2; - for(i = 0; i < max_half_width; ++i) - { - m_dist[i] = li.y(); - if(m_dist[i] >= stop) break; - ++li; - } - m_dist[i++] = 0x7FFF0000; - } - - //--------------------------------------------------------------------- - template int step_hor_base(DI& di) - { - ++m_li; - m_x += m_lp->inc; - m_y = (m_lp->y1 + m_li.y()) >> line_subpixel_shift; - - if(m_lp->inc > 0) di.inc_x(m_y - m_old_y); - else di.dec_x(m_y - m_old_y); - - m_old_y = m_y; - - return di.dist() / m_len; - } - - //--------------------------------------------------------------------- - template int step_ver_base(DI& di) - { - ++m_li; - m_y += m_lp->inc; - m_x = (m_lp->x1 + m_li.y()) >> line_subpixel_shift; - - if(m_lp->inc > 0) di.inc_y(m_x - m_old_x); - else di.dec_y(m_x - m_old_x); - - m_old_x = m_x; - - return di.dist() / m_len; - } - - //--------------------------------------------------------------------- - bool vertical() const { return m_lp->vertical; } - int width() const { return m_width; } - int count() const { return m_count; } - - private: - line_interpolator_aa_base(const line_interpolator_aa_base&); - const line_interpolator_aa_base& - operator = (const line_interpolator_aa_base&); - - protected: - const line_parameters* m_lp; - dda2_line_interpolator m_li; - renderer_type& m_ren; - int m_len; - int m_x; - int m_y; - int m_old_x; - int m_old_y; - int m_count; - int m_width; - int m_max_extent; - int m_step; - int m_dist[max_half_width + 1]; - cover_type m_covers[max_half_width * 2 + 4]; - }; - - - - - - - - //====================================================line_interpolator_aa0 - template class line_interpolator_aa0 : - public line_interpolator_aa_base - { - public: - typedef Renderer renderer_type; - typedef typename Renderer::color_type color_type; - typedef line_interpolator_aa_base base_type; - - //--------------------------------------------------------------------- - line_interpolator_aa0(renderer_type& ren, const line_parameters& lp) : - line_interpolator_aa_base(ren, lp), - m_di(lp.x1, lp.y1, lp.x2, lp.y2, - lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask) - { - base_type::m_li.adjust_forward(); - } - - //--------------------------------------------------------------------- - bool step_hor() - { - int dist; - int dy; - int s1 = base_type::step_hor_base(m_di); - cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; - cover_type* p1 = p0; - - *p1++ = (cover_type)base_type::m_ren.cover(s1); - - dy = 1; - while((dist = base_type::m_dist[dy] - s1) <= base_type::m_width) - { - *p1++ = (cover_type)base_type::m_ren.cover(dist); - ++dy; - } - - dy = 1; - while((dist = base_type::m_dist[dy] + s1) <= base_type::m_width) - { - *--p0 = (cover_type)base_type::m_ren.cover(dist); - ++dy; - } - base_type::m_ren.blend_solid_vspan(base_type::m_x, - base_type::m_y - dy + 1, - unsigned(p1 - p0), - p0); - return ++base_type::m_step < base_type::m_count; - } - - //--------------------------------------------------------------------- - bool step_ver() - { - int dist; - int dx; - int s1 = base_type::step_ver_base(m_di); - cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; - cover_type* p1 = p0; - - *p1++ = (cover_type)base_type::m_ren.cover(s1); - - dx = 1; - while((dist = base_type::m_dist[dx] - s1) <= base_type::m_width) - { - *p1++ = (cover_type)base_type::m_ren.cover(dist); - ++dx; - } - - dx = 1; - while((dist = base_type::m_dist[dx] + s1) <= base_type::m_width) - { - *--p0 = (cover_type)base_type::m_ren.cover(dist); - ++dx; - } - base_type::m_ren.blend_solid_hspan(base_type::m_x - dx + 1, - base_type::m_y, - unsigned(p1 - p0), - p0); - return ++base_type::m_step < base_type::m_count; - } - - private: - line_interpolator_aa0(const line_interpolator_aa0&); - const line_interpolator_aa0& - operator = (const line_interpolator_aa0&); - - //--------------------------------------------------------------------- - distance_interpolator1 m_di; - }; - - - - - - - //====================================================line_interpolator_aa1 - template class line_interpolator_aa1 : - public line_interpolator_aa_base - { - public: - typedef Renderer renderer_type; - typedef typename Renderer::color_type color_type; - typedef line_interpolator_aa_base base_type; - - //--------------------------------------------------------------------- - line_interpolator_aa1(renderer_type& ren, const line_parameters& lp, - int sx, int sy) : - line_interpolator_aa_base(ren, lp), - m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, - lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask) - { - int dist1_start; - int dist2_start; - - int npix = 1; - - if(lp.vertical) - { - do - { - --base_type::m_li; - base_type::m_y -= lp.inc; - base_type::m_x = (base_type::m_lp->x1 + base_type::m_li.y()) >> line_subpixel_shift; - - if(lp.inc > 0) m_di.dec_y(base_type::m_x - base_type::m_old_x); - else m_di.inc_y(base_type::m_x - base_type::m_old_x); - - base_type::m_old_x = base_type::m_x; - - dist1_start = dist2_start = m_di.dist_start(); - - int dx = 0; - if(dist1_start < 0) ++npix; - do - { - dist1_start += m_di.dy_start(); - dist2_start -= m_di.dy_start(); - if(dist1_start < 0) ++npix; - if(dist2_start < 0) ++npix; - ++dx; - } - while(base_type::m_dist[dx] <= base_type::m_width); - --base_type::m_step; - if(npix == 0) break; - npix = 0; - } - while(base_type::m_step >= -base_type::m_max_extent); - } - else - { - do - { - --base_type::m_li; - base_type::m_x -= lp.inc; - base_type::m_y = (base_type::m_lp->y1 + base_type::m_li.y()) >> line_subpixel_shift; - - if(lp.inc > 0) m_di.dec_x(base_type::m_y - base_type::m_old_y); - else m_di.inc_x(base_type::m_y - base_type::m_old_y); - - base_type::m_old_y = base_type::m_y; - - dist1_start = dist2_start = m_di.dist_start(); - - int dy = 0; - if(dist1_start < 0) ++npix; - do - { - dist1_start -= m_di.dx_start(); - dist2_start += m_di.dx_start(); - if(dist1_start < 0) ++npix; - if(dist2_start < 0) ++npix; - ++dy; - } - while(base_type::m_dist[dy] <= base_type::m_width); - --base_type::m_step; - if(npix == 0) break; - npix = 0; - } - while(base_type::m_step >= -base_type::m_max_extent); - } - base_type::m_li.adjust_forward(); - } - - //--------------------------------------------------------------------- - bool step_hor() - { - int dist_start; - int dist; - int dy; - int s1 = base_type::step_hor_base(m_di); - - dist_start = m_di.dist_start(); - cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; - cover_type* p1 = p0; - - *p1 = 0; - if(dist_start <= 0) - { - *p1 = (cover_type)base_type::m_ren.cover(s1); - } - ++p1; - - dy = 1; - while((dist = base_type::m_dist[dy] - s1) <= base_type::m_width) - { - dist_start -= m_di.dx_start(); - *p1 = 0; - if(dist_start <= 0) - { - *p1 = (cover_type)base_type::m_ren.cover(dist); - } - ++p1; - ++dy; - } - - dy = 1; - dist_start = m_di.dist_start(); - while((dist = base_type::m_dist[dy] + s1) <= base_type::m_width) - { - dist_start += m_di.dx_start(); - *--p0 = 0; - if(dist_start <= 0) - { - *p0 = (cover_type)base_type::m_ren.cover(dist); - } - ++dy; - } - - base_type::m_ren.blend_solid_vspan(base_type::m_x, - base_type::m_y - dy + 1, - unsigned(p1 - p0), - p0); - return ++base_type::m_step < base_type::m_count; - } - - //--------------------------------------------------------------------- - bool step_ver() - { - int dist_start; - int dist; - int dx; - int s1 = base_type::step_ver_base(m_di); - cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; - cover_type* p1 = p0; - - dist_start = m_di.dist_start(); - - *p1 = 0; - if(dist_start <= 0) - { - *p1 = (cover_type)base_type::m_ren.cover(s1); - } - ++p1; - - dx = 1; - while((dist = base_type::m_dist[dx] - s1) <= base_type::m_width) - { - dist_start += m_di.dy_start(); - *p1 = 0; - if(dist_start <= 0) - { - *p1 = (cover_type)base_type::m_ren.cover(dist); - } - ++p1; - ++dx; - } - - dx = 1; - dist_start = m_di.dist_start(); - while((dist = base_type::m_dist[dx] + s1) <= base_type::m_width) - { - dist_start -= m_di.dy_start(); - *--p0 = 0; - if(dist_start <= 0) - { - *p0 = (cover_type)base_type::m_ren.cover(dist); - } - ++dx; - } - base_type::m_ren.blend_solid_hspan(base_type::m_x - dx + 1, - base_type::m_y, - unsigned(p1 - p0), - p0); - return ++base_type::m_step < base_type::m_count; - } - - private: - line_interpolator_aa1(const line_interpolator_aa1&); - const line_interpolator_aa1& - operator = (const line_interpolator_aa1&); - - //--------------------------------------------------------------------- - distance_interpolator2 m_di; - }; - - - - - - - - - - - - - //====================================================line_interpolator_aa2 - template class line_interpolator_aa2 : - public line_interpolator_aa_base - { - public: - typedef Renderer renderer_type; - typedef typename Renderer::color_type color_type; - typedef line_interpolator_aa_base base_type; - - //--------------------------------------------------------------------- - line_interpolator_aa2(renderer_type& ren, const line_parameters& lp, - int ex, int ey) : - line_interpolator_aa_base(ren, lp), - m_di(lp.x1, lp.y1, lp.x2, lp.y2, ex, ey, - lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask, - 0) - { - base_type::m_li.adjust_forward(); - base_type::m_step -= base_type::m_max_extent; - } - - //--------------------------------------------------------------------- - bool step_hor() - { - int dist_end; - int dist; - int dy; - int s1 = base_type::step_hor_base(m_di); - cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; - cover_type* p1 = p0; - - dist_end = m_di.dist_end(); - - int npix = 0; - *p1 = 0; - if(dist_end > 0) - { - *p1 = (cover_type)base_type::m_ren.cover(s1); - ++npix; - } - ++p1; - - dy = 1; - while((dist = base_type::m_dist[dy] - s1) <= base_type::m_width) - { - dist_end -= m_di.dx_end(); - *p1 = 0; - if(dist_end > 0) - { - *p1 = (cover_type)base_type::m_ren.cover(dist); - ++npix; - } - ++p1; - ++dy; - } - - dy = 1; - dist_end = m_di.dist_end(); - while((dist = base_type::m_dist[dy] + s1) <= base_type::m_width) - { - dist_end += m_di.dx_end(); - *--p0 = 0; - if(dist_end > 0) - { - *p0 = (cover_type)base_type::m_ren.cover(dist); - ++npix; - } - ++dy; - } - base_type::m_ren.blend_solid_vspan(base_type::m_x, - base_type::m_y - dy + 1, - unsigned(p1 - p0), - p0); - return npix && ++base_type::m_step < base_type::m_count; - } - - //--------------------------------------------------------------------- - bool step_ver() - { - int dist_end; - int dist; - int dx; - int s1 = base_type::step_ver_base(m_di); - cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; - cover_type* p1 = p0; - - dist_end = m_di.dist_end(); - - int npix = 0; - *p1 = 0; - if(dist_end > 0) - { - *p1 = (cover_type)base_type::m_ren.cover(s1); - ++npix; - } - ++p1; - - dx = 1; - while((dist = base_type::m_dist[dx] - s1) <= base_type::m_width) - { - dist_end += m_di.dy_end(); - *p1 = 0; - if(dist_end > 0) - { - *p1 = (cover_type)base_type::m_ren.cover(dist); - ++npix; - } - ++p1; - ++dx; - } - - dx = 1; - dist_end = m_di.dist_end(); - while((dist = base_type::m_dist[dx] + s1) <= base_type::m_width) - { - dist_end -= m_di.dy_end(); - *--p0 = 0; - if(dist_end > 0) - { - *p0 = (cover_type)base_type::m_ren.cover(dist); - ++npix; - } - ++dx; - } - base_type::m_ren.blend_solid_hspan(base_type::m_x - dx + 1, - base_type::m_y, - unsigned(p1 - p0), - p0); - return npix && ++base_type::m_step < base_type::m_count; - } - - private: - line_interpolator_aa2(const line_interpolator_aa2&); - const line_interpolator_aa2& - operator = (const line_interpolator_aa2&); - - //--------------------------------------------------------------------- - distance_interpolator2 m_di; - }; - - - - - - - - - - - //====================================================line_interpolator_aa3 - template class line_interpolator_aa3 : - public line_interpolator_aa_base - { - public: - typedef Renderer renderer_type; - typedef typename Renderer::color_type color_type; - typedef line_interpolator_aa_base base_type; - - //--------------------------------------------------------------------- - line_interpolator_aa3(renderer_type& ren, const line_parameters& lp, - int sx, int sy, int ex, int ey) : - line_interpolator_aa_base(ren, lp), - m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, ex, ey, - lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask) - { - int dist1_start; - int dist2_start; - int npix = 1; - if(lp.vertical) - { - do - { - --base_type::m_li; - base_type::m_y -= lp.inc; - base_type::m_x = (base_type::m_lp->x1 + base_type::m_li.y()) >> line_subpixel_shift; - - if(lp.inc > 0) m_di.dec_y(base_type::m_x - base_type::m_old_x); - else m_di.inc_y(base_type::m_x - base_type::m_old_x); - - base_type::m_old_x = base_type::m_x; - - dist1_start = dist2_start = m_di.dist_start(); - - int dx = 0; - if(dist1_start < 0) ++npix; - do - { - dist1_start += m_di.dy_start(); - dist2_start -= m_di.dy_start(); - if(dist1_start < 0) ++npix; - if(dist2_start < 0) ++npix; - ++dx; - } - while(base_type::m_dist[dx] <= base_type::m_width); - if(npix == 0) break; - npix = 0; - } - while(--base_type::m_step >= -base_type::m_max_extent); - } - else - { - do - { - --base_type::m_li; - base_type::m_x -= lp.inc; - base_type::m_y = (base_type::m_lp->y1 + base_type::m_li.y()) >> line_subpixel_shift; - - if(lp.inc > 0) m_di.dec_x(base_type::m_y - base_type::m_old_y); - else m_di.inc_x(base_type::m_y - base_type::m_old_y); - - base_type::m_old_y = base_type::m_y; - - dist1_start = dist2_start = m_di.dist_start(); - - int dy = 0; - if(dist1_start < 0) ++npix; - do - { - dist1_start -= m_di.dx_start(); - dist2_start += m_di.dx_start(); - if(dist1_start < 0) ++npix; - if(dist2_start < 0) ++npix; - ++dy; - } - while(base_type::m_dist[dy] <= base_type::m_width); - if(npix == 0) break; - npix = 0; - } - while(--base_type::m_step >= -base_type::m_max_extent); - } - base_type::m_li.adjust_forward(); - base_type::m_step -= base_type::m_max_extent; - } - - - //--------------------------------------------------------------------- - bool step_hor() - { - int dist_start; - int dist_end; - int dist; - int dy; - int s1 = base_type::step_hor_base(m_di); - cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; - cover_type* p1 = p0; - - dist_start = m_di.dist_start(); - dist_end = m_di.dist_end(); - - int npix = 0; - *p1 = 0; - if(dist_end > 0) - { - if(dist_start <= 0) - { - *p1 = (cover_type)base_type::m_ren.cover(s1); - } - ++npix; - } - ++p1; - - dy = 1; - while((dist = base_type::m_dist[dy] - s1) <= base_type::m_width) - { - dist_start -= m_di.dx_start(); - dist_end -= m_di.dx_end(); - *p1 = 0; - if(dist_end > 0 && dist_start <= 0) - { - *p1 = (cover_type)base_type::m_ren.cover(dist); - ++npix; - } - ++p1; - ++dy; - } - - dy = 1; - dist_start = m_di.dist_start(); - dist_end = m_di.dist_end(); - while((dist = base_type::m_dist[dy] + s1) <= base_type::m_width) - { - dist_start += m_di.dx_start(); - dist_end += m_di.dx_end(); - *--p0 = 0; - if(dist_end > 0 && dist_start <= 0) - { - *p0 = (cover_type)base_type::m_ren.cover(dist); - ++npix; - } - ++dy; - } - base_type::m_ren.blend_solid_vspan(base_type::m_x, - base_type::m_y - dy + 1, - unsigned(p1 - p0), - p0); - return npix && ++base_type::m_step < base_type::m_count; - } - - //--------------------------------------------------------------------- - bool step_ver() - { - int dist_start; - int dist_end; - int dist; - int dx; - int s1 = base_type::step_ver_base(m_di); - cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; - cover_type* p1 = p0; - - dist_start = m_di.dist_start(); - dist_end = m_di.dist_end(); - - int npix = 0; - *p1 = 0; - if(dist_end > 0) - { - if(dist_start <= 0) - { - *p1 = (cover_type)base_type::m_ren.cover(s1); - } - ++npix; - } - ++p1; - - dx = 1; - while((dist = base_type::m_dist[dx] - s1) <= base_type::m_width) - { - dist_start += m_di.dy_start(); - dist_end += m_di.dy_end(); - *p1 = 0; - if(dist_end > 0 && dist_start <= 0) - { - *p1 = (cover_type)base_type::m_ren.cover(dist); - ++npix; - } - ++p1; - ++dx; - } - - dx = 1; - dist_start = m_di.dist_start(); - dist_end = m_di.dist_end(); - while((dist = base_type::m_dist[dx] + s1) <= base_type::m_width) - { - dist_start -= m_di.dy_start(); - dist_end -= m_di.dy_end(); - *--p0 = 0; - if(dist_end > 0 && dist_start <= 0) - { - *p0 = (cover_type)base_type::m_ren.cover(dist); - ++npix; - } - ++dx; - } - base_type::m_ren.blend_solid_hspan(base_type::m_x - dx + 1, - base_type::m_y, - unsigned(p1 - p0), - p0); - return npix && ++base_type::m_step < base_type::m_count; - } - - private: - line_interpolator_aa3(const line_interpolator_aa3&); - const line_interpolator_aa3& - operator = (const line_interpolator_aa3&); - - //--------------------------------------------------------------------- - distance_interpolator3 m_di; - }; - - - - - //==========================================================line_profile_aa - // - // See Implementation agg_line_profile_aa.cpp - // - class line_profile_aa - { - public: - //--------------------------------------------------------------------- - typedef int8u value_type; - enum subpixel_scale_e - { - subpixel_shift = line_subpixel_shift, - subpixel_scale = 1 << subpixel_shift, - subpixel_mask = subpixel_scale - 1 - }; - - enum aa_scale_e - { - aa_shift = 8, - aa_scale = 1 << aa_shift, - aa_mask = aa_scale - 1 - }; - - //--------------------------------------------------------------------- - line_profile_aa() : - m_subpixel_width(0), - m_min_width(1.0), - m_smoother_width(1.0) - { - int i; - for(i = 0; i < aa_scale; i++) m_gamma[i] = (value_type)i; - } - - //--------------------------------------------------------------------- - template - line_profile_aa(double w, const GammaF& gamma_function) : - m_subpixel_width(0), - m_min_width(1.0), - m_smoother_width(1.0) - { - gamma(gamma_function); - width(w); - } - - //--------------------------------------------------------------------- - void min_width(double w) { m_min_width = w; } - void smoother_width(double w) { m_smoother_width = w; } - - //--------------------------------------------------------------------- - template void gamma(const GammaF& gamma_function) - { - int i; - for(i = 0; i < aa_scale; i++) - { - m_gamma[i] = value_type( - uround(gamma_function(double(i) / aa_mask) * aa_mask)); - } - } - - void width(double w); - - unsigned profile_size() const { return m_profile.size(); } - int subpixel_width() const { return m_subpixel_width; } - - //--------------------------------------------------------------------- - double min_width() const { return m_min_width; } - double smoother_width() const { return m_smoother_width; } - - //--------------------------------------------------------------------- - value_type value(int dist) const - { - return m_profile[dist + subpixel_scale*2]; - } - - private: - line_profile_aa(const line_profile_aa&); - const line_profile_aa& operator = (const line_profile_aa&); - - value_type* profile(double w); - void set(double center_width, double smoother_width); - - //--------------------------------------------------------------------- - pod_array m_profile; - value_type m_gamma[aa_scale]; - int m_subpixel_width; - double m_min_width; - double m_smoother_width; - }; - - - //======================================================renderer_outline_aa - template class renderer_outline_aa - { - public: - //--------------------------------------------------------------------- - typedef BaseRenderer base_ren_type; - typedef renderer_outline_aa self_type; - typedef typename base_ren_type::color_type color_type; - - //--------------------------------------------------------------------- - renderer_outline_aa(base_ren_type& ren, const line_profile_aa& prof) : - m_ren(&ren), - m_profile(&prof), - m_clip_box(0,0,0,0), - m_clipping(false) - {} - void attach(base_ren_type& ren) { m_ren = &ren; } - - //--------------------------------------------------------------------- - void color(const color_type& c) { m_color = c; } - const color_type& color() const { return m_color; } - - //--------------------------------------------------------------------- - void profile(const line_profile_aa& prof) { m_profile = &prof; } - const line_profile_aa& profile() const { return *m_profile; } - line_profile_aa& profile() { return *m_profile; } - - //--------------------------------------------------------------------- - int subpixel_width() const { return m_profile->subpixel_width(); } - - //--------------------------------------------------------------------- - void reset_clipping() { m_clipping = false; } - void clip_box(double x1, double y1, double x2, double y2) - { - m_clip_box.x1 = line_coord_sat::conv(x1); - m_clip_box.y1 = line_coord_sat::conv(y1); - m_clip_box.x2 = line_coord_sat::conv(x2); - m_clip_box.y2 = line_coord_sat::conv(y2); - m_clipping = true; - } - - //--------------------------------------------------------------------- - int cover(int d) const - { - return m_profile->value(d); - } - - //------------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, unsigned len, const cover_type* covers) - { - m_ren->blend_solid_hspan(x, y, len, m_color, covers); - } - - //------------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, unsigned len, const cover_type* covers) - { - m_ren->blend_solid_vspan(x, y, len, m_color, covers); - } - - //------------------------------------------------------------------------- - static bool accurate_join_only() { return false; } - - //------------------------------------------------------------------------- - template - void semidot_hline(Cmp cmp, - int xc1, int yc1, int xc2, int yc2, - int x1, int y1, int x2) - { - cover_type covers[line_interpolator_aa_base::max_half_width * 2 + 4]; - cover_type* p0 = covers; - cover_type* p1 = covers; - int x = x1 << line_subpixel_shift; - int y = y1 << line_subpixel_shift; - int w = subpixel_width(); - distance_interpolator0 di(xc1, yc1, xc2, yc2, x, y); - x += line_subpixel_scale/2; - y += line_subpixel_scale/2; - - int x0 = x1; - int dx = x - xc1; - int dy = y - yc1; - do - { - int d = int(fast_sqrt(dx*dx + dy*dy)); - *p1 = 0; - if(cmp(di.dist()) && d <= w) - { - *p1 = (cover_type)cover(d); - } - ++p1; - dx += line_subpixel_scale; - di.inc_x(); - } - while(++x1 <= x2); - m_ren->blend_solid_hspan(x0, y1, - unsigned(p1 - p0), - color(), - p0); - } - - //------------------------------------------------------------------------- - template - void semidot(Cmp cmp, int xc1, int yc1, int xc2, int yc2) - { - if(m_clipping && clipping_flags(xc1, yc1, m_clip_box)) return; - - int r = ((subpixel_width() + line_subpixel_mask) >> line_subpixel_shift); - if(r < 1) r = 1; - ellipse_bresenham_interpolator ei(r, r); - int dx = 0; - int dy = -r; - int dy0 = dy; - int dx0 = dx; - int x = xc1 >> line_subpixel_shift; - int y = yc1 >> line_subpixel_shift; - - do - { - dx += ei.dx(); - dy += ei.dy(); - - if(dy != dy0) - { - semidot_hline(cmp, xc1, yc1, xc2, yc2, x-dx0, y+dy0, x+dx0); - semidot_hline(cmp, xc1, yc1, xc2, yc2, x-dx0, y-dy0, x+dx0); - } - dx0 = dx; - dy0 = dy; - ++ei; - } - while(dy < 0); - semidot_hline(cmp, xc1, yc1, xc2, yc2, x-dx0, y+dy0, x+dx0); - } - - //------------------------------------------------------------------------- - void pie_hline(int xc, int yc, int xp1, int yp1, int xp2, int yp2, - int xh1, int yh1, int xh2) - { - if(m_clipping && clipping_flags(xc, yc, m_clip_box)) return; - - cover_type covers[line_interpolator_aa_base::max_half_width * 2 + 4]; - cover_type* p0 = covers; - cover_type* p1 = covers; - int x = xh1 << line_subpixel_shift; - int y = yh1 << line_subpixel_shift; - int w = subpixel_width(); - - distance_interpolator00 di(xc, yc, xp1, yp1, xp2, yp2, x, y); - x += line_subpixel_scale/2; - y += line_subpixel_scale/2; - - int xh0 = xh1; - int dx = x - xc; - int dy = y - yc; - do - { - int d = int(fast_sqrt(dx*dx + dy*dy)); - *p1 = 0; - if(di.dist1() <= 0 && di.dist2() > 0 && d <= w) - { - *p1 = (cover_type)cover(d); - } - ++p1; - dx += line_subpixel_scale; - di.inc_x(); - } - while(++xh1 <= xh2); - m_ren->blend_solid_hspan(xh0, yh1, - unsigned(p1 - p0), - color(), - p0); - } - - - //------------------------------------------------------------------------- - void pie(int xc, int yc, int x1, int y1, int x2, int y2) - { - int r = ((subpixel_width() + line_subpixel_mask) >> line_subpixel_shift); - if(r < 1) r = 1; - ellipse_bresenham_interpolator ei(r, r); - int dx = 0; - int dy = -r; - int dy0 = dy; - int dx0 = dx; - int x = xc >> line_subpixel_shift; - int y = yc >> line_subpixel_shift; - - do - { - dx += ei.dx(); - dy += ei.dy(); - - if(dy != dy0) - { - pie_hline(xc, yc, x1, y1, x2, y2, x-dx0, y+dy0, x+dx0); - pie_hline(xc, yc, x1, y1, x2, y2, x-dx0, y-dy0, x+dx0); - } - dx0 = dx; - dy0 = dy; - ++ei; - } - while(dy < 0); - pie_hline(xc, yc, x1, y1, x2, y2, x-dx0, y+dy0, x+dx0); - } - - //------------------------------------------------------------------------- - void line0_no_clip(const line_parameters& lp) - { - if(lp.len > line_max_length) - { - line_parameters lp1, lp2; - lp.divide(lp1, lp2); - line0_no_clip(lp1); - line0_no_clip(lp2); - return; - } - - line_interpolator_aa0 li(*this, lp); - if(li.count()) - { - if(li.vertical()) - { - while(li.step_ver()); - } - else - { - while(li.step_hor()); - } - } - } - - //------------------------------------------------------------------------- - void line0(const line_parameters& lp) - { - if(m_clipping) - { - int x1 = lp.x1; - int y1 = lp.y1; - int x2 = lp.x2; - int y2 = lp.y2; - unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); - if((flags & 4) == 0) - { - if(flags) - { - line_parameters lp2(x1, y1, x2, y2, - uround(calc_distance(x1, y1, x2, y2))); - line0_no_clip(lp2); - } - else - { - line0_no_clip(lp); - } - } - } - else - { - line0_no_clip(lp); - } - } - - //------------------------------------------------------------------------- - void line1_no_clip(const line_parameters& lp, int sx, int sy) - { - if(lp.len > line_max_length) - { - line_parameters lp1, lp2; - lp.divide(lp1, lp2); - line1_no_clip(lp1, (lp.x1 + sx) >> 1, (lp.y1 + sy) >> 1); - line1_no_clip(lp2, lp1.x2 + (lp1.y2 - lp1.y1), lp1.y2 - (lp1.x2 - lp1.x1)); - return; - } - - fix_degenerate_bisectrix_start(lp, &sx, &sy); - line_interpolator_aa1 li(*this, lp, sx, sy); - if(li.vertical()) - { - while(li.step_ver()); - } - else - { - while(li.step_hor()); - } - } - - - //------------------------------------------------------------------------- - void line1(const line_parameters& lp, int sx, int sy) - { - if(m_clipping) - { - int x1 = lp.x1; - int y1 = lp.y1; - int x2 = lp.x2; - int y2 = lp.y2; - unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); - if((flags & 4) == 0) - { - if(flags) - { - line_parameters lp2(x1, y1, x2, y2, - uround(calc_distance(x1, y1, x2, y2))); - if(flags & 1) - { - sx = x1 + (y2 - y1); - sy = y1 - (x2 - x1); - } - else - { - while(abs(sx - lp.x1) + abs(sy - lp.y1) > lp2.len) - { - sx = (lp.x1 + sx) >> 1; - sy = (lp.y1 + sy) >> 1; - } - } - line1_no_clip(lp2, sx, sy); - } - else - { - line1_no_clip(lp, sx, sy); - } - } - } - else - { - line1_no_clip(lp, sx, sy); - } - } - - //------------------------------------------------------------------------- - void line2_no_clip(const line_parameters& lp, int ex, int ey) - { - if(lp.len > line_max_length) - { - line_parameters lp1, lp2; - lp.divide(lp1, lp2); - line2_no_clip(lp1, lp1.x2 + (lp1.y2 - lp1.y1), lp1.y2 - (lp1.x2 - lp1.x1)); - line2_no_clip(lp2, (lp.x2 + ex) >> 1, (lp.y2 + ey) >> 1); - return; - } - - fix_degenerate_bisectrix_end(lp, &ex, &ey); - line_interpolator_aa2 li(*this, lp, ex, ey); - if(li.vertical()) - { - while(li.step_ver()); - } - else - { - while(li.step_hor()); - } - } - - //------------------------------------------------------------------------- - void line2(const line_parameters& lp, int ex, int ey) - { - if(m_clipping) - { - int x1 = lp.x1; - int y1 = lp.y1; - int x2 = lp.x2; - int y2 = lp.y2; - unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); - if((flags & 4) == 0) - { - if(flags) - { - line_parameters lp2(x1, y1, x2, y2, - uround(calc_distance(x1, y1, x2, y2))); - if(flags & 2) - { - ex = x2 + (y2 - y1); - ey = y2 - (x2 - x1); - } - else - { - while(abs(ex - lp.x2) + abs(ey - lp.y2) > lp2.len) - { - ex = (lp.x2 + ex) >> 1; - ey = (lp.y2 + ey) >> 1; - } - } - line2_no_clip(lp2, ex, ey); - } - else - { - line2_no_clip(lp, ex, ey); - } - } - } - else - { - line2_no_clip(lp, ex, ey); - } - } - - //------------------------------------------------------------------------- - void line3_no_clip(const line_parameters& lp, - int sx, int sy, int ex, int ey) - { - if(lp.len > line_max_length) - { - line_parameters lp1, lp2; - lp.divide(lp1, lp2); - int mx = lp1.x2 + (lp1.y2 - lp1.y1); - int my = lp1.y2 - (lp1.x2 - lp1.x1); - line3_no_clip(lp1, (lp.x1 + sx) >> 1, (lp.y1 + sy) >> 1, mx, my); - line3_no_clip(lp2, mx, my, (lp.x2 + ex) >> 1, (lp.y2 + ey) >> 1); - return; - } - - fix_degenerate_bisectrix_start(lp, &sx, &sy); - fix_degenerate_bisectrix_end(lp, &ex, &ey); - line_interpolator_aa3 li(*this, lp, sx, sy, ex, ey); - if(li.vertical()) - { - while(li.step_ver()); - } - else - { - while(li.step_hor()); - } - } - - //------------------------------------------------------------------------- - void line3(const line_parameters& lp, - int sx, int sy, int ex, int ey) - { - if(m_clipping) - { - int x1 = lp.x1; - int y1 = lp.y1; - int x2 = lp.x2; - int y2 = lp.y2; - unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); - if((flags & 4) == 0) - { - if(flags) - { - line_parameters lp2(x1, y1, x2, y2, - uround(calc_distance(x1, y1, x2, y2))); - if(flags & 1) - { - sx = x1 + (y2 - y1); - sy = y1 - (x2 - x1); - } - else - { - while(abs(sx - lp.x1) + abs(sy - lp.y1) > lp2.len) - { - sx = (lp.x1 + sx) >> 1; - sy = (lp.y1 + sy) >> 1; - } - } - if(flags & 2) - { - ex = x2 + (y2 - y1); - ey = y2 - (x2 - x1); - } - else - { - while(abs(ex - lp.x2) + abs(ey - lp.y2) > lp2.len) - { - ex = (lp.x2 + ex) >> 1; - ey = (lp.y2 + ey) >> 1; - } - } - line3_no_clip(lp2, sx, sy, ex, ey); - } - else - { - line3_no_clip(lp, sx, sy, ex, ey); - } - } - } - else - { - line3_no_clip(lp, sx, sy, ex, ey); - } - } - - - private: - base_ren_type* m_ren; - const line_profile_aa* m_profile; - color_type m_color; - rect_i m_clip_box; - bool m_clipping; - }; - - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_renderer_outline_image.h corsix-th-0.62/agg/include/agg_renderer_outline_image.h --- corsix-th-0.30/agg/include/agg_renderer_outline_image.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_renderer_outline_image.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1013 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_RENDERER_OUTLINE_IMAGE_INCLUDED -#define AGG_RENDERER_OUTLINE_IMAGE_INCLUDED - -#include "agg_array.h" -#include "agg_math.h" -#include "agg_line_aa_basics.h" -#include "agg_dda_line.h" -#include "agg_rendering_buffer.h" -#include "agg_clip_liang_barsky.h" - - -namespace agg -{ - //========================================================line_image_scale - template class line_image_scale - { - public: - typedef typename Source::color_type color_type; - - line_image_scale(const Source& src, double height) : - m_source(src), - m_height(height), - m_scale(src.height() / height) - { - } - - double width() const { return m_source.width(); } - double height() const { return m_height; } - - color_type pixel(int x, int y) const - { - double src_y = (y + 0.5) * m_scale - 0.5; - int h = m_source.height() - 1; - int y1 = ufloor(src_y); - int y2 = y1 + 1; - color_type pix1 = (y1 < 0) ? color_type::no_color() : m_source.pixel(x, y1); - color_type pix2 = (y2 > h) ? color_type::no_color() : m_source.pixel(x, y2); - return pix1.gradient(pix2, src_y - y1); - } - - private: - line_image_scale(const line_image_scale&); - const line_image_scale& operator = (const line_image_scale&); - - const Source& m_source; - double m_height; - double m_scale; - }; - - - - //======================================================line_image_pattern - template class line_image_pattern - { - public: - typedef Filter filter_type; - typedef typename filter_type::color_type color_type; - - //-------------------------------------------------------------------- - line_image_pattern(const Filter& filter) : - m_filter(&filter), - m_dilation(filter.dilation() + 1), - m_dilation_hr(m_dilation << line_subpixel_shift), - m_data(), - m_width(0), - m_height(0), - m_width_hr(0), - m_half_height_hr(0), - m_offset_y_hr(0) - { - } - - // Create - //-------------------------------------------------------------------- - template - line_image_pattern(const Filter& filter, const Source& src) : - m_filter(&filter), - m_dilation(filter.dilation() + 1), - m_dilation_hr(m_dilation << line_subpixel_shift), - m_data(), - m_width(0), - m_height(0), - m_width_hr(0), - m_half_height_hr(0), - m_offset_y_hr(0) - { - create(src); - } - - // Create - //-------------------------------------------------------------------- - template void create(const Source& src) - { - m_height = uceil(src.height()); - m_width = uceil(src.width()); - m_width_hr = uround(src.width() * line_subpixel_scale); - m_half_height_hr = uround(src.height() * line_subpixel_scale/2); - m_offset_y_hr = m_dilation_hr + m_half_height_hr - line_subpixel_scale/2; - m_half_height_hr += line_subpixel_scale/2; - - m_data.resize((m_width + m_dilation * 2) * (m_height + m_dilation * 2)); - - m_buf.attach(&m_data[0], m_width + m_dilation * 2, - m_height + m_dilation * 2, - m_width + m_dilation * 2); - unsigned x, y; - color_type* d1; - color_type* d2; - for(y = 0; y < m_height; y++) - { - d1 = m_buf.row_ptr(y + m_dilation) + m_dilation; - for(x = 0; x < m_width; x++) - { - *d1++ = src.pixel(x, y); - } - } - - const color_type* s1; - const color_type* s2; - for(y = 0; y < m_dilation; y++) - { - //s1 = m_buf.row_ptr(m_height + m_dilation - 1) + m_dilation; - //s2 = m_buf.row_ptr(m_dilation) + m_dilation; - d1 = m_buf.row_ptr(m_dilation + m_height + y) + m_dilation; - d2 = m_buf.row_ptr(m_dilation - y - 1) + m_dilation; - for(x = 0; x < m_width; x++) - { - //*d1++ = color_type(*s1++, 0); - //*d2++ = color_type(*s2++, 0); - *d1++ = color_type::no_color(); - *d2++ = color_type::no_color(); - } - } - - unsigned h = m_height + m_dilation * 2; - for(y = 0; y < h; y++) - { - s1 = m_buf.row_ptr(y) + m_dilation; - s2 = m_buf.row_ptr(y) + m_dilation + m_width; - d1 = m_buf.row_ptr(y) + m_dilation + m_width; - d2 = m_buf.row_ptr(y) + m_dilation; - - for(x = 0; x < m_dilation; x++) - { - *d1++ = *s1++; - *--d2 = *--s2; - } - } - } - - //-------------------------------------------------------------------- - int pattern_width() const { return m_width_hr; } - int line_width() const { return m_half_height_hr; } - double width() const { return m_height; } - - //-------------------------------------------------------------------- - void pixel(color_type* p, int x, int y) const - { - m_filter->pixel_high_res(m_buf.rows(), - p, - x % m_width_hr + m_dilation_hr, - y + m_offset_y_hr); - } - - //-------------------------------------------------------------------- - const filter_type& filter() const { return *m_filter; } - - private: - line_image_pattern(const line_image_pattern&); - const line_image_pattern& - operator = (const line_image_pattern&); - - protected: - row_ptr_cache m_buf; - const filter_type* m_filter; - unsigned m_dilation; - int m_dilation_hr; - pod_array m_data; - unsigned m_width; - unsigned m_height; - int m_width_hr; - int m_half_height_hr; - int m_offset_y_hr; - }; - - - - - - - //=================================================line_image_pattern_pow2 - template class line_image_pattern_pow2 : - public line_image_pattern - { - public: - typedef Filter filter_type; - typedef typename filter_type::color_type color_type; - typedef line_image_pattern base_type; - - //-------------------------------------------------------------------- - line_image_pattern_pow2(const Filter& filter) : - line_image_pattern(filter), m_mask(line_subpixel_mask) {} - - //-------------------------------------------------------------------- - template - line_image_pattern_pow2(const Filter& filter, const Source& src) : - line_image_pattern(filter), m_mask(line_subpixel_mask) - { - create(src); - } - - //-------------------------------------------------------------------- - template void create(const Source& src) - { - line_image_pattern::create(src); - m_mask = 1; - while(m_mask < base_type::m_width) - { - m_mask <<= 1; - m_mask |= 1; - } - m_mask <<= line_subpixel_shift - 1; - m_mask |= line_subpixel_mask; - base_type::m_width_hr = m_mask + 1; - } - - //-------------------------------------------------------------------- - void pixel(color_type* p, int x, int y) const - { - base_type::m_filter->pixel_high_res( - base_type::m_buf.rows(), - p, - (x & m_mask) + base_type::m_dilation_hr, - y + base_type::m_offset_y_hr); - } - private: - unsigned m_mask; - }; - - - - - - - - //===================================================distance_interpolator4 - class distance_interpolator4 - { - public: - //--------------------------------------------------------------------- - distance_interpolator4() {} - distance_interpolator4(int x1, int y1, int x2, int y2, - int sx, int sy, int ex, int ey, - int len, double scale, int x, int y) : - m_dx(x2 - x1), - m_dy(y2 - y1), - m_dx_start(line_mr(sx) - line_mr(x1)), - m_dy_start(line_mr(sy) - line_mr(y1)), - m_dx_end(line_mr(ex) - line_mr(x2)), - m_dy_end(line_mr(ey) - line_mr(y2)), - - m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - - double(y + line_subpixel_scale/2 - y2) * double(m_dx))), - - m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(sx)) * m_dy_start - - (line_mr(y + line_subpixel_scale/2) - line_mr(sy)) * m_dx_start), - - m_dist_end((line_mr(x + line_subpixel_scale/2) - line_mr(ex)) * m_dy_end - - (line_mr(y + line_subpixel_scale/2) - line_mr(ey)) * m_dx_end), - m_len(uround(len / scale)) - { - double d = len * scale; - int dx = iround(((x2 - x1) << line_subpixel_shift) / d); - int dy = iround(((y2 - y1) << line_subpixel_shift) / d); - m_dx_pict = -dy; - m_dy_pict = dx; - m_dist_pict = ((x + line_subpixel_scale/2 - (x1 - dy)) * m_dy_pict - - (y + line_subpixel_scale/2 - (y1 + dx)) * m_dx_pict) >> - line_subpixel_shift; - - m_dx <<= line_subpixel_shift; - m_dy <<= line_subpixel_shift; - m_dx_start <<= line_mr_subpixel_shift; - m_dy_start <<= line_mr_subpixel_shift; - m_dx_end <<= line_mr_subpixel_shift; - m_dy_end <<= line_mr_subpixel_shift; - } - - //--------------------------------------------------------------------- - void inc_x() - { - m_dist += m_dy; - m_dist_start += m_dy_start; - m_dist_pict += m_dy_pict; - m_dist_end += m_dy_end; - } - - //--------------------------------------------------------------------- - void dec_x() - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - m_dist_pict -= m_dy_pict; - m_dist_end -= m_dy_end; - } - - //--------------------------------------------------------------------- - void inc_y() - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - m_dist_pict -= m_dx_pict; - m_dist_end -= m_dx_end; - } - - //--------------------------------------------------------------------- - void dec_y() - { - m_dist += m_dx; - m_dist_start += m_dx_start; - m_dist_pict += m_dx_pict; - m_dist_end += m_dx_end; - } - - //--------------------------------------------------------------------- - void inc_x(int dy) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - m_dist_pict += m_dy_pict; - m_dist_end += m_dy_end; - if(dy > 0) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - m_dist_pict -= m_dx_pict; - m_dist_end -= m_dx_end; - } - if(dy < 0) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - m_dist_pict += m_dx_pict; - m_dist_end += m_dx_end; - } - } - - //--------------------------------------------------------------------- - void dec_x(int dy) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - m_dist_pict -= m_dy_pict; - m_dist_end -= m_dy_end; - if(dy > 0) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - m_dist_pict -= m_dx_pict; - m_dist_end -= m_dx_end; - } - if(dy < 0) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - m_dist_pict += m_dx_pict; - m_dist_end += m_dx_end; - } - } - - //--------------------------------------------------------------------- - void inc_y(int dx) - { - m_dist -= m_dx; - m_dist_start -= m_dx_start; - m_dist_pict -= m_dx_pict; - m_dist_end -= m_dx_end; - if(dx > 0) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - m_dist_pict += m_dy_pict; - m_dist_end += m_dy_end; - } - if(dx < 0) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - m_dist_pict -= m_dy_pict; - m_dist_end -= m_dy_end; - } - } - - //--------------------------------------------------------------------- - void dec_y(int dx) - { - m_dist += m_dx; - m_dist_start += m_dx_start; - m_dist_pict += m_dx_pict; - m_dist_end += m_dx_end; - if(dx > 0) - { - m_dist += m_dy; - m_dist_start += m_dy_start; - m_dist_pict += m_dy_pict; - m_dist_end += m_dy_end; - } - if(dx < 0) - { - m_dist -= m_dy; - m_dist_start -= m_dy_start; - m_dist_pict -= m_dy_pict; - m_dist_end -= m_dy_end; - } - } - - //--------------------------------------------------------------------- - int dist() const { return m_dist; } - int dist_start() const { return m_dist_start; } - int dist_pict() const { return m_dist_pict; } - int dist_end() const { return m_dist_end; } - - //--------------------------------------------------------------------- - int dx() const { return m_dx; } - int dy() const { return m_dy; } - int dx_start() const { return m_dx_start; } - int dy_start() const { return m_dy_start; } - int dx_pict() const { return m_dx_pict; } - int dy_pict() const { return m_dy_pict; } - int dx_end() const { return m_dx_end; } - int dy_end() const { return m_dy_end; } - int len() const { return m_len; } - - private: - //--------------------------------------------------------------------- - int m_dx; - int m_dy; - int m_dx_start; - int m_dy_start; - int m_dx_pict; - int m_dy_pict; - int m_dx_end; - int m_dy_end; - - int m_dist; - int m_dist_start; - int m_dist_pict; - int m_dist_end; - int m_len; - }; - - - - - - //==================================================line_interpolator_image - template class line_interpolator_image - { - public: - typedef Renderer renderer_type; - typedef typename Renderer::color_type color_type; - - //--------------------------------------------------------------------- - enum max_half_width_e - { - max_half_width = 64 - }; - - //--------------------------------------------------------------------- - line_interpolator_image(renderer_type& ren, const line_parameters& lp, - int sx, int sy, int ex, int ey, - int pattern_start, - double scale_x) : - m_lp(lp), - m_li(lp.vertical ? line_dbl_hr(lp.x2 - lp.x1) : - line_dbl_hr(lp.y2 - lp.y1), - lp.vertical ? abs(lp.y2 - lp.y1) : - abs(lp.x2 - lp.x1) + 1), - m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, ex, ey, lp.len, scale_x, - lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask), - m_ren(ren), - m_x(lp.x1 >> line_subpixel_shift), - m_y(lp.y1 >> line_subpixel_shift), - m_old_x(m_x), - m_old_y(m_y), - m_count((lp.vertical ? abs((lp.y2 >> line_subpixel_shift) - m_y) : - abs((lp.x2 >> line_subpixel_shift) - m_x))), - m_width(ren.subpixel_width()), - //m_max_extent(m_width >> (line_subpixel_shift - 2)), - m_max_extent((m_width + line_subpixel_scale) >> line_subpixel_shift), - m_start(pattern_start + (m_max_extent + 2) * ren.pattern_width()), - m_step(0) - { - agg::dda2_line_interpolator li(0, lp.vertical ? - (lp.dy << agg::line_subpixel_shift) : - (lp.dx << agg::line_subpixel_shift), - lp.len); - - unsigned i; - int stop = m_width + line_subpixel_scale * 2; - for(i = 0; i < max_half_width; ++i) - { - m_dist_pos[i] = li.y(); - if(m_dist_pos[i] >= stop) break; - ++li; - } - m_dist_pos[i] = 0x7FFF0000; - - int dist1_start; - int dist2_start; - int npix = 1; - - if(lp.vertical) - { - do - { - --m_li; - m_y -= lp.inc; - m_x = (m_lp.x1 + m_li.y()) >> line_subpixel_shift; - - if(lp.inc > 0) m_di.dec_y(m_x - m_old_x); - else m_di.inc_y(m_x - m_old_x); - - m_old_x = m_x; - - dist1_start = dist2_start = m_di.dist_start(); - - int dx = 0; - if(dist1_start < 0) ++npix; - do - { - dist1_start += m_di.dy_start(); - dist2_start -= m_di.dy_start(); - if(dist1_start < 0) ++npix; - if(dist2_start < 0) ++npix; - ++dx; - } - while(m_dist_pos[dx] <= m_width); - if(npix == 0) break; - - npix = 0; - } - while(--m_step >= -m_max_extent); - } - else - { - do - { - --m_li; - - m_x -= lp.inc; - m_y = (m_lp.y1 + m_li.y()) >> line_subpixel_shift; - - if(lp.inc > 0) m_di.dec_x(m_y - m_old_y); - else m_di.inc_x(m_y - m_old_y); - - m_old_y = m_y; - - dist1_start = dist2_start = m_di.dist_start(); - - int dy = 0; - if(dist1_start < 0) ++npix; - do - { - dist1_start -= m_di.dx_start(); - dist2_start += m_di.dx_start(); - if(dist1_start < 0) ++npix; - if(dist2_start < 0) ++npix; - ++dy; - } - while(m_dist_pos[dy] <= m_width); - if(npix == 0) break; - - npix = 0; - } - while(--m_step >= -m_max_extent); - } - m_li.adjust_forward(); - m_step -= m_max_extent; - } - - //--------------------------------------------------------------------- - bool step_hor() - { - ++m_li; - m_x += m_lp.inc; - m_y = (m_lp.y1 + m_li.y()) >> line_subpixel_shift; - - if(m_lp.inc > 0) m_di.inc_x(m_y - m_old_y); - else m_di.dec_x(m_y - m_old_y); - - m_old_y = m_y; - - int s1 = m_di.dist() / m_lp.len; - int s2 = -s1; - - if(m_lp.inc < 0) s1 = -s1; - - int dist_start; - int dist_pict; - int dist_end; - int dy; - int dist; - - dist_start = m_di.dist_start(); - dist_pict = m_di.dist_pict() + m_start; - dist_end = m_di.dist_end(); - color_type* p0 = m_colors + max_half_width + 2; - color_type* p1 = p0; - - int npix = 0; - p1->clear(); - if(dist_end > 0) - { - if(dist_start <= 0) - { - m_ren.pixel(p1, dist_pict, s2); - } - ++npix; - } - ++p1; - - dy = 1; - while((dist = m_dist_pos[dy]) - s1 <= m_width) - { - dist_start -= m_di.dx_start(); - dist_pict -= m_di.dx_pict(); - dist_end -= m_di.dx_end(); - p1->clear(); - if(dist_end > 0 && dist_start <= 0) - { - if(m_lp.inc > 0) dist = -dist; - m_ren.pixel(p1, dist_pict, s2 - dist); - ++npix; - } - ++p1; - ++dy; - } - - dy = 1; - dist_start = m_di.dist_start(); - dist_pict = m_di.dist_pict() + m_start; - dist_end = m_di.dist_end(); - while((dist = m_dist_pos[dy]) + s1 <= m_width) - { - dist_start += m_di.dx_start(); - dist_pict += m_di.dx_pict(); - dist_end += m_di.dx_end(); - --p0; - p0->clear(); - if(dist_end > 0 && dist_start <= 0) - { - if(m_lp.inc > 0) dist = -dist; - m_ren.pixel(p0, dist_pict, s2 + dist); - ++npix; - } - ++dy; - } - m_ren.blend_color_vspan(m_x, - m_y - dy + 1, - unsigned(p1 - p0), - p0); - return npix && ++m_step < m_count; - } - - - - //--------------------------------------------------------------------- - bool step_ver() - { - ++m_li; - m_y += m_lp.inc; - m_x = (m_lp.x1 + m_li.y()) >> line_subpixel_shift; - - if(m_lp.inc > 0) m_di.inc_y(m_x - m_old_x); - else m_di.dec_y(m_x - m_old_x); - - m_old_x = m_x; - - int s1 = m_di.dist() / m_lp.len; - int s2 = -s1; - - if(m_lp.inc > 0) s1 = -s1; - - int dist_start; - int dist_pict; - int dist_end; - int dist; - int dx; - - dist_start = m_di.dist_start(); - dist_pict = m_di.dist_pict() + m_start; - dist_end = m_di.dist_end(); - color_type* p0 = m_colors + max_half_width + 2; - color_type* p1 = p0; - - int npix = 0; - p1->clear(); - if(dist_end > 0) - { - if(dist_start <= 0) - { - m_ren.pixel(p1, dist_pict, s2); - } - ++npix; - } - ++p1; - - dx = 1; - while((dist = m_dist_pos[dx]) - s1 <= m_width) - { - dist_start += m_di.dy_start(); - dist_pict += m_di.dy_pict(); - dist_end += m_di.dy_end(); - p1->clear(); - if(dist_end > 0 && dist_start <= 0) - { - if(m_lp.inc > 0) dist = -dist; - m_ren.pixel(p1, dist_pict, s2 + dist); - ++npix; - } - ++p1; - ++dx; - } - - dx = 1; - dist_start = m_di.dist_start(); - dist_pict = m_di.dist_pict() + m_start; - dist_end = m_di.dist_end(); - while((dist = m_dist_pos[dx]) + s1 <= m_width) - { - dist_start -= m_di.dy_start(); - dist_pict -= m_di.dy_pict(); - dist_end -= m_di.dy_end(); - --p0; - p0->clear(); - if(dist_end > 0 && dist_start <= 0) - { - if(m_lp.inc > 0) dist = -dist; - m_ren.pixel(p0, dist_pict, s2 - dist); - ++npix; - } - ++dx; - } - m_ren.blend_color_hspan(m_x - dx + 1, - m_y, - unsigned(p1 - p0), - p0); - return npix && ++m_step < m_count; - } - - - //--------------------------------------------------------------------- - int pattern_end() const { return m_start + m_di.len(); } - - //--------------------------------------------------------------------- - bool vertical() const { return m_lp.vertical; } - int width() const { return m_width; } - int count() const { return m_count; } - - private: - line_interpolator_image(const line_interpolator_image&); - const line_interpolator_image& - operator = (const line_interpolator_image&); - - protected: - const line_parameters& m_lp; - dda2_line_interpolator m_li; - distance_interpolator4 m_di; - renderer_type& m_ren; - int m_plen; - int m_x; - int m_y; - int m_old_x; - int m_old_y; - int m_count; - int m_width; - int m_max_extent; - int m_start; - int m_step; - int m_dist_pos[max_half_width + 1]; - color_type m_colors[max_half_width * 2 + 4]; - }; - - - - - - - - - //===================================================renderer_outline_image - template - class renderer_outline_image - { - public: - //--------------------------------------------------------------------- - typedef BaseRenderer base_ren_type; - typedef renderer_outline_image self_type; - typedef typename base_ren_type::color_type color_type; - typedef ImagePattern pattern_type; - - - //--------------------------------------------------------------------- - renderer_outline_image(base_ren_type& ren, const pattern_type& patt) : - m_ren(&ren), - m_pattern(&patt), - m_start(0), - m_scale_x(1.0), - m_clip_box(0,0,0,0), - m_clipping(false) - {} - void attach(base_ren_type& ren) { m_ren = &ren; } - - //--------------------------------------------------------------------- - void pattern(const pattern_type& p) { m_pattern = &p; } - const pattern_type& pattern() const { return *m_pattern; } - - //--------------------------------------------------------------------- - void reset_clipping() { m_clipping = false; } - void clip_box(double x1, double y1, double x2, double y2) - { - m_clip_box.x1 = line_coord_sat::conv(x1); - m_clip_box.y1 = line_coord_sat::conv(y1); - m_clip_box.x2 = line_coord_sat::conv(x2); - m_clip_box.y2 = line_coord_sat::conv(y2); - m_clipping = true; - } - - //--------------------------------------------------------------------- - void scale_x(double s) { m_scale_x = s; } - double scale_x() const { return m_scale_x; } - - //--------------------------------------------------------------------- - void start_x(double s) { m_start = iround(s * line_subpixel_scale); } - double start_x() const { return double(m_start) / line_subpixel_scale; } - - //--------------------------------------------------------------------- - int subpixel_width() const { return m_pattern->line_width(); } - int pattern_width() const { return m_pattern->pattern_width(); } - double width() const { return double(subpixel_width()) / line_subpixel_scale; } - - //------------------------------------------------------------------------- - void pixel(color_type* p, int x, int y) const - { - m_pattern->pixel(p, x, y); - } - - //------------------------------------------------------------------------- - void blend_color_hspan(int x, int y, unsigned len, const color_type* colors) - { - m_ren->blend_color_hspan(x, y, len, colors, 0); - } - - //------------------------------------------------------------------------- - void blend_color_vspan(int x, int y, unsigned len, const color_type* colors) - { - m_ren->blend_color_vspan(x, y, len, colors, 0); - } - - //------------------------------------------------------------------------- - static bool accurate_join_only() { return true; } - - //------------------------------------------------------------------------- - template - void semidot(Cmp, int, int, int, int) - { - } - - //------------------------------------------------------------------------- - void pie(int, int, int, int, int, int) - { - } - - //------------------------------------------------------------------------- - void line0(const line_parameters&) - { - } - - //------------------------------------------------------------------------- - void line1(const line_parameters&, int, int) - { - } - - //------------------------------------------------------------------------- - void line2(const line_parameters&, int, int) - { - } - - //------------------------------------------------------------------------- - void line3_no_clip(const line_parameters& lp, - int sx, int sy, int ex, int ey) - { - if(lp.len > line_max_length) - { - line_parameters lp1, lp2; - lp.divide(lp1, lp2); - int mx = lp1.x2 + (lp1.y2 - lp1.y1); - int my = lp1.y2 - (lp1.x2 - lp1.x1); - line3_no_clip(lp1, (lp.x1 + sx) >> 1, (lp.y1 + sy) >> 1, mx, my); - line3_no_clip(lp2, mx, my, (lp.x2 + ex) >> 1, (lp.y2 + ey) >> 1); - return; - } - - fix_degenerate_bisectrix_start(lp, &sx, &sy); - fix_degenerate_bisectrix_end(lp, &ex, &ey); - line_interpolator_image li(*this, lp, - sx, sy, - ex, ey, - m_start, m_scale_x); - if(li.vertical()) - { - while(li.step_ver()); - } - else - { - while(li.step_hor()); - } - m_start += uround(lp.len / m_scale_x); - } - - //------------------------------------------------------------------------- - void line3(const line_parameters& lp, - int sx, int sy, int ex, int ey) - { - if(m_clipping) - { - int x1 = lp.x1; - int y1 = lp.y1; - int x2 = lp.x2; - int y2 = lp.y2; - unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); - int start = m_start; - if((flags & 4) == 0) - { - if(flags) - { - line_parameters lp2(x1, y1, x2, y2, - uround(calc_distance(x1, y1, x2, y2))); - if(flags & 1) - { - m_start += uround(calc_distance(lp.x1, lp.y1, x1, y1) / m_scale_x); - sx = x1 + (y2 - y1); - sy = y1 - (x2 - x1); - } - else - { - while(abs(sx - lp.x1) + abs(sy - lp.y1) > lp2.len) - { - sx = (lp.x1 + sx) >> 1; - sy = (lp.y1 + sy) >> 1; - } - } - if(flags & 2) - { - ex = x2 + (y2 - y1); - ey = y2 - (x2 - x1); - } - else - { - while(abs(ex - lp.x2) + abs(ey - lp.y2) > lp2.len) - { - ex = (lp.x2 + ex) >> 1; - ey = (lp.y2 + ey) >> 1; - } - } - line3_no_clip(lp2, sx, sy, ex, ey); - } - else - { - line3_no_clip(lp, sx, sy, ex, ey); - } - } - m_start = start + uround(lp.len / m_scale_x); - } - else - { - line3_no_clip(lp, sx, sy, ex, ey); - } - } - - private: - base_ren_type* m_ren; - const pattern_type* m_pattern; - int m_start; - double m_scale_x; - rect_i m_clip_box; - bool m_clipping; - }; - - - - - -} - - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_renderer_primitives.h corsix-th-0.62/agg/include/agg_renderer_primitives.h --- corsix-th-0.30/agg/include/agg_renderer_primitives.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_renderer_primitives.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,224 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class renderer_primitives -// -//---------------------------------------------------------------------------- - -#ifndef AGG_RENDERER_PRIMITIVES_INCLUDED -#define AGG_RENDERER_PRIMITIVES_INCLUDED - -#include "agg_basics.h" -#include "agg_renderer_base.h" -#include "agg_dda_line.h" -#include "agg_ellipse_bresenham.h" - -namespace agg -{ - //-----------------------------------------------------renderer_primitives - template class renderer_primitives - { - public: - typedef BaseRenderer base_ren_type; - typedef typename base_ren_type::color_type color_type; - - //-------------------------------------------------------------------- - explicit renderer_primitives(base_ren_type& ren) : - m_ren(&ren), - m_fill_color(), - m_line_color(), - m_curr_x(0), - m_curr_y(0) - {} - void attach(base_ren_type& ren) { m_ren = &ren; } - - //-------------------------------------------------------------------- - static int coord(double c) - { - return iround(c * line_bresenham_interpolator::subpixel_scale); - } - - //-------------------------------------------------------------------- - void fill_color(const color_type& c) { m_fill_color = c; } - void line_color(const color_type& c) { m_line_color = c; } - const color_type& fill_color() const { return m_fill_color; } - const color_type& line_color() const { return m_line_color; } - - //-------------------------------------------------------------------- - void rectangle(int x1, int y1, int x2, int y2) - { - m_ren->blend_hline(x1, y1, x2-1, m_line_color, cover_full); - m_ren->blend_vline(x2, y1, y2-1, m_line_color, cover_full); - m_ren->blend_hline(x1+1, y2, x2, m_line_color, cover_full); - m_ren->blend_vline(x1, y1+1, y2, m_line_color, cover_full); - } - - //-------------------------------------------------------------------- - void solid_rectangle(int x1, int y1, int x2, int y2) - { - m_ren->blend_bar(x1, y1, x2, y2, m_fill_color, cover_full); - } - - //-------------------------------------------------------------------- - void outlined_rectangle(int x1, int y1, int x2, int y2) - { - rectangle(x1, y1, x2, y2); - m_ren->blend_bar(x1+1, y1+1, x2-1, y2-1, m_fill_color, cover_full); - } - - //-------------------------------------------------------------------- - void ellipse(int x, int y, int rx, int ry) - { - ellipse_bresenham_interpolator ei(rx, ry); - int dx = 0; - int dy = -ry; - do - { - dx += ei.dx(); - dy += ei.dy(); - m_ren->blend_pixel(x + dx, y + dy, m_line_color, cover_full); - m_ren->blend_pixel(x + dx, y - dy, m_line_color, cover_full); - m_ren->blend_pixel(x - dx, y - dy, m_line_color, cover_full); - m_ren->blend_pixel(x - dx, y + dy, m_line_color, cover_full); - ++ei; - } - while(dy < 0); - } - - //-------------------------------------------------------------------- - void solid_ellipse(int x, int y, int rx, int ry) - { - ellipse_bresenham_interpolator ei(rx, ry); - int dx = 0; - int dy = -ry; - int dy0 = dy; - int dx0 = dx; - - do - { - dx += ei.dx(); - dy += ei.dy(); - - if(dy != dy0) - { - m_ren->blend_hline(x-dx0, y+dy0, x+dx0, m_fill_color, cover_full); - m_ren->blend_hline(x-dx0, y-dy0, x+dx0, m_fill_color, cover_full); - } - dx0 = dx; - dy0 = dy; - ++ei; - } - while(dy < 0); - m_ren->blend_hline(x-dx0, y+dy0, x+dx0, m_fill_color, cover_full); - } - - //-------------------------------------------------------------------- - void outlined_ellipse(int x, int y, int rx, int ry) - { - ellipse_bresenham_interpolator ei(rx, ry); - int dx = 0; - int dy = -ry; - - do - { - dx += ei.dx(); - dy += ei.dy(); - - m_ren->blend_pixel(x + dx, y + dy, m_line_color, cover_full); - m_ren->blend_pixel(x + dx, y - dy, m_line_color, cover_full); - m_ren->blend_pixel(x - dx, y - dy, m_line_color, cover_full); - m_ren->blend_pixel(x - dx, y + dy, m_line_color, cover_full); - - if(ei.dy() && dx) - { - m_ren->blend_hline(x-dx+1, y+dy, x+dx-1, m_fill_color, cover_full); - m_ren->blend_hline(x-dx+1, y-dy, x+dx-1, m_fill_color, cover_full); - } - ++ei; - } - while(dy < 0); - } - - //-------------------------------------------------------------------- - void line(int x1, int y1, int x2, int y2, bool last=false) - { - line_bresenham_interpolator li(x1, y1, x2, y2); - - unsigned len = li.len(); - if(len == 0) - { - if(last) - { - m_ren->blend_pixel(li.line_lr(x1), li.line_lr(y1), m_line_color, cover_full); - } - return; - } - - if(last) ++len; - - if(li.is_ver()) - { - do - { - m_ren->blend_pixel(li.x2(), li.y1(), m_line_color, cover_full); - li.vstep(); - } - while(--len); - } - else - { - do - { - m_ren->blend_pixel(li.x1(), li.y2(), m_line_color, cover_full); - li.hstep(); - } - while(--len); - } - } - - //-------------------------------------------------------------------- - void move_to(int x, int y) - { - m_curr_x = x; - m_curr_y = y; - } - - //-------------------------------------------------------------------- - void line_to(int x, int y, bool last=false) - { - line(m_curr_x, m_curr_y, x, y, last); - m_curr_x = x; - m_curr_y = y; - } - - //-------------------------------------------------------------------- - const base_ren_type& ren() const { return *m_ren; } - base_ren_type& ren() { return *m_ren; } - - //-------------------------------------------------------------------- - const rendering_buffer& rbuf() const { return m_ren->rbuf(); } - rendering_buffer& rbuf() { return m_ren->rbuf(); } - - private: - base_ren_type* m_ren; - color_type m_fill_color; - color_type m_line_color; - int m_curr_x; - int m_curr_y; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_renderer_raster_text.h corsix-th-0.62/agg/include/agg_renderer_raster_text.h --- corsix-th-0.30/agg/include/agg_renderer_raster_text.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_renderer_raster_text.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,264 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_RENDERER_RASTER_TEXT_INCLUDED -#define AGG_RENDERER_RASTER_TEXT_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //==============================================renderer_raster_htext_solid - template - class renderer_raster_htext_solid - { - public: - typedef BaseRenderer ren_type; - typedef GlyphGenerator glyph_gen_type; - typedef typename glyph_gen_type::glyph_rect glyph_rect; - typedef typename ren_type::color_type color_type; - - renderer_raster_htext_solid(ren_type& ren, glyph_gen_type& glyph) : - m_ren(&ren), - m_glyph(&glyph) - {} - void attach(ren_type& ren) { m_ren = &ren; } - - //-------------------------------------------------------------------- - void color(const color_type& c) { m_color = c; } - const color_type& color() const { return m_color; } - - //-------------------------------------------------------------------- - template - void render_text(double x, double y, const CharT* str, bool flip=false) - { - glyph_rect r; - while(*str) - { - m_glyph->prepare(&r, x, y, *str, flip); - if(r.x2 >= r.x1) - { - int i; - if(flip) - { - for(i = r.y1; i <= r.y2; i++) - { - m_ren->blend_solid_hspan(r.x1, i, (r.x2 - r.x1 + 1), - m_color, - m_glyph->span(r.y2 - i)); - } - } - else - { - for(i = r.y1; i <= r.y2; i++) - { - m_ren->blend_solid_hspan(r.x1, i, (r.x2 - r.x1 + 1), - m_color, - m_glyph->span(i - r.y1)); - } - } - } - x += r.dx; - y += r.dy; - ++str; - } - } - - private: - ren_type* m_ren; - glyph_gen_type* m_glyph; - color_type m_color; - }; - - - - //=============================================renderer_raster_vtext_solid - template - class renderer_raster_vtext_solid - { - public: - typedef BaseRenderer ren_type; - typedef GlyphGenerator glyph_gen_type; - typedef typename glyph_gen_type::glyph_rect glyph_rect; - typedef typename ren_type::color_type color_type; - - renderer_raster_vtext_solid(ren_type& ren, glyph_gen_type& glyph) : - m_ren(&ren), - m_glyph(&glyph) - { - } - - //-------------------------------------------------------------------- - void color(const color_type& c) { m_color = c; } - const color_type& color() const { return m_color; } - - //-------------------------------------------------------------------- - template - void render_text(double x, double y, const CharT* str, bool flip=false) - { - glyph_rect r; - while(*str) - { - m_glyph->prepare(&r, x, y, *str, !flip); - if(r.x2 >= r.x1) - { - int i; - if(flip) - { - for(i = r.y1; i <= r.y2; i++) - { - m_ren->blend_solid_vspan(i, r.x1, (r.x2 - r.x1 + 1), - m_color, - m_glyph->span(i - r.y1)); - } - } - else - { - for(i = r.y1; i <= r.y2; i++) - { - m_ren->blend_solid_vspan(i, r.x1, (r.x2 - r.x1 + 1), - m_color, - m_glyph->span(r.y2 - i)); - } - } - } - x += r.dx; - y += r.dy; - ++str; - } - } - - private: - ren_type* m_ren; - glyph_gen_type* m_glyph; - color_type m_color; - }; - - - - - - - //===================================================renderer_raster_htext - template - class renderer_raster_htext - { - public: - typedef ScanlineRenderer ren_type; - typedef GlyphGenerator glyph_gen_type; - typedef typename glyph_gen_type::glyph_rect glyph_rect; - - class scanline_single_span - { - public: - typedef agg::cover_type cover_type; - - //---------------------------------------------------------------- - struct const_span - { - int x; - unsigned len; - const cover_type* covers; - - const_span() {} - const_span(int x_, unsigned len_, const cover_type* covers_) : - x(x_), len(len_), covers(covers_) - {} - }; - - typedef const const_span* const_iterator; - - //---------------------------------------------------------------- - scanline_single_span(int x, int y, unsigned len, - const cover_type* covers) : - m_y(y), - m_span(x, len, covers) - {} - - //---------------------------------------------------------------- - int y() const { return m_y; } - unsigned num_spans() const { return 1; } - const_iterator begin() const { return &m_span; } - - private: - //---------------------------------------------------------------- - int m_y; - const_span m_span; - }; - - - - //-------------------------------------------------------------------- - renderer_raster_htext(ren_type& ren, glyph_gen_type& glyph) : - m_ren(&ren), - m_glyph(&glyph) - { - } - - - //-------------------------------------------------------------------- - template - void render_text(double x, double y, const CharT* str, bool flip=false) - { - glyph_rect r; - while(*str) - { - m_glyph->prepare(&r, x, y, *str, flip); - if(r.x2 >= r.x1) - { - m_ren->prepare(); - int i; - if(flip) - { - for(i = r.y1; i <= r.y2; i++) - { - m_ren->render( - scanline_single_span(r.x1, - i, - (r.x2 - r.x1 + 1), - m_glyph->span(r.y2 - i))); - } - } - else - { - for(i = r.y1; i <= r.y2; i++) - { - m_ren->render( - scanline_single_span(r.x1, - i, - (r.x2 - r.x1 + 1), - m_glyph->span(i - r.y1))); - } - } - } - x += r.dx; - y += r.dy; - ++str; - } - } - - private: - ren_type* m_ren; - glyph_gen_type* m_glyph; - }; - - - - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_renderer_scanline.h corsix-th-0.62/agg/include/agg_renderer_scanline.h --- corsix-th-0.30/agg/include/agg_renderer_scanline.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_renderer_scanline.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,852 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_RENDERER_SCANLINE_INCLUDED -#define AGG_RENDERER_SCANLINE_INCLUDED - -#include "agg_basics.h" -#include "agg_renderer_base.h" - -namespace agg -{ - - //================================================render_scanline_aa_solid - template - void render_scanline_aa_solid(const Scanline& sl, - BaseRenderer& ren, - const ColorT& color) - { - int y = sl.y(); - unsigned num_spans = sl.num_spans(); - typename Scanline::const_iterator span = sl.begin(); - - for(;;) - { - int x = span->x; - if(span->len > 0) - { - ren.blend_solid_hspan(x, y, (unsigned)span->len, - color, - span->covers); - } - else - { - ren.blend_hline(x, y, (unsigned)(x - span->len - 1), - color, - *(span->covers)); - } - if(--num_spans == 0) break; - ++span; - } - } - - //===============================================render_scanlines_aa_solid - template - void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl, - BaseRenderer& ren, const ColorT& color) - { - if(ras.rewind_scanlines()) - { - // Explicitly convert "color" to the BaseRenderer color type. - // For example, it can be called with color type "rgba", while - // "rgba8" is needed. Otherwise it will be implicitly - // converted in the loop many times. - //---------------------- - typename BaseRenderer::color_type ren_color(color); - - sl.reset(ras.min_x(), ras.max_x()); - while(ras.sweep_scanline(sl)) - { - //render_scanline_aa_solid(sl, ren, ren_color); - - // This code is equivalent to the above call (copy/paste). - // It's just a "manual" optimization for old compilers, - // like Microsoft Visual C++ v6.0 - //------------------------------- - int y = sl.y(); - unsigned num_spans = sl.num_spans(); - typename Scanline::const_iterator span = sl.begin(); - - for(;;) - { - int x = span->x; - if(span->len > 0) - { - ren.blend_solid_hspan(x, y, (unsigned)span->len, - ren_color, - span->covers); - } - else - { - ren.blend_hline(x, y, (unsigned)(x - span->len - 1), - ren_color, - *(span->covers)); - } - if(--num_spans == 0) break; - ++span; - } - } - } - } - - //==============================================renderer_scanline_aa_solid - template class renderer_scanline_aa_solid - { - public: - typedef BaseRenderer base_ren_type; - typedef typename base_ren_type::color_type color_type; - - //-------------------------------------------------------------------- - renderer_scanline_aa_solid() : m_ren(0) {} - explicit renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {} - void attach(base_ren_type& ren) - { - m_ren = &ren; - } - - //-------------------------------------------------------------------- - void color(const color_type& c) { m_color = c; } - const color_type& color() const { return m_color; } - - //-------------------------------------------------------------------- - void prepare() {} - - //-------------------------------------------------------------------- - template void render(const Scanline& sl) - { - render_scanline_aa_solid(sl, *m_ren, m_color); - } - - private: - base_ren_type* m_ren; - color_type m_color; - }; - - - - - - - - - - - - - - //======================================================render_scanline_aa - template - void render_scanline_aa(const Scanline& sl, BaseRenderer& ren, - SpanAllocator& alloc, SpanGenerator& span_gen) - { - int y = sl.y(); - - unsigned num_spans = sl.num_spans(); - typename Scanline::const_iterator span = sl.begin(); - for(;;) - { - int x = span->x; - int len = span->len; - const typename Scanline::cover_type* covers = span->covers; - - if(len < 0) len = -len; - typename BaseRenderer::color_type* colors = alloc.allocate(len); - span_gen.generate(colors, x, y, len); - ren.blend_color_hspan(x, y, len, colors, - (span->len < 0) ? 0 : covers, *covers); - - if(--num_spans == 0) break; - ++span; - } - } - - //=====================================================render_scanlines_aa - template - void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, - SpanAllocator& alloc, SpanGenerator& span_gen) - { - if(ras.rewind_scanlines()) - { - sl.reset(ras.min_x(), ras.max_x()); - span_gen.prepare(); - while(ras.sweep_scanline(sl)) - { - render_scanline_aa(sl, ren, alloc, span_gen); - } - } - } - - //====================================================renderer_scanline_aa - template - class renderer_scanline_aa - { - public: - typedef BaseRenderer base_ren_type; - typedef SpanAllocator alloc_type; - typedef SpanGenerator span_gen_type; - - //-------------------------------------------------------------------- - renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {} - renderer_scanline_aa(base_ren_type& ren, - alloc_type& alloc, - span_gen_type& span_gen) : - m_ren(&ren), - m_alloc(&alloc), - m_span_gen(&span_gen) - {} - void attach(base_ren_type& ren, - alloc_type& alloc, - span_gen_type& span_gen) - { - m_ren = &ren; - m_alloc = &alloc; - m_span_gen = &span_gen; - } - - //-------------------------------------------------------------------- - void prepare() { m_span_gen->prepare(); } - - //-------------------------------------------------------------------- - template void render(const Scanline& sl) - { - render_scanline_aa(sl, *m_ren, *m_alloc, *m_span_gen); - } - - private: - base_ren_type* m_ren; - alloc_type* m_alloc; - span_gen_type* m_span_gen; - }; - - - - - - - //===============================================render_scanline_bin_solid - template - void render_scanline_bin_solid(const Scanline& sl, - BaseRenderer& ren, - const ColorT& color) - { - unsigned num_spans = sl.num_spans(); - typename Scanline::const_iterator span = sl.begin(); - for(;;) - { - ren.blend_hline(span->x, - sl.y(), - span->x - 1 + ((span->len < 0) ? - -span->len : - span->len), - color, - cover_full); - if(--num_spans == 0) break; - ++span; - } - } - - //==============================================render_scanlines_bin_solid - template - void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl, - BaseRenderer& ren, const ColorT& color) - { - if(ras.rewind_scanlines()) - { - // Explicitly convert "color" to the BaseRenderer color type. - // For example, it can be called with color type "rgba", while - // "rgba8" is needed. Otherwise it will be implicitly - // converted in the loop many times. - //---------------------- - typename BaseRenderer::color_type ren_color(color); - - sl.reset(ras.min_x(), ras.max_x()); - while(ras.sweep_scanline(sl)) - { - //render_scanline_bin_solid(sl, ren, ren_color); - - // This code is equivalent to the above call (copy/paste). - // It's just a "manual" optimization for old compilers, - // like Microsoft Visual C++ v6.0 - //------------------------------- - unsigned num_spans = sl.num_spans(); - typename Scanline::const_iterator span = sl.begin(); - for(;;) - { - ren.blend_hline(span->x, - sl.y(), - span->x - 1 + ((span->len < 0) ? - -span->len : - span->len), - ren_color, - cover_full); - if(--num_spans == 0) break; - ++span; - } - } - } - } - - //=============================================renderer_scanline_bin_solid - template class renderer_scanline_bin_solid - { - public: - typedef BaseRenderer base_ren_type; - typedef typename base_ren_type::color_type color_type; - - //-------------------------------------------------------------------- - renderer_scanline_bin_solid() : m_ren(0) {} - explicit renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {} - void attach(base_ren_type& ren) - { - m_ren = &ren; - } - - //-------------------------------------------------------------------- - void color(const color_type& c) { m_color = c; } - const color_type& color() const { return m_color; } - - //-------------------------------------------------------------------- - void prepare() {} - - //-------------------------------------------------------------------- - template void render(const Scanline& sl) - { - render_scanline_bin_solid(sl, *m_ren, m_color); - } - - private: - base_ren_type* m_ren; - color_type m_color; - }; - - - - - - - - - //======================================================render_scanline_bin - template - void render_scanline_bin(const Scanline& sl, BaseRenderer& ren, - SpanAllocator& alloc, SpanGenerator& span_gen) - { - int y = sl.y(); - - unsigned num_spans = sl.num_spans(); - typename Scanline::const_iterator span = sl.begin(); - for(;;) - { - int x = span->x; - int len = span->len; - if(len < 0) len = -len; - typename BaseRenderer::color_type* colors = alloc.allocate(len); - span_gen.generate(colors, x, y, len); - ren.blend_color_hspan(x, y, len, colors, 0, cover_full); - if(--num_spans == 0) break; - ++span; - } - } - - //=====================================================render_scanlines_bin - template - void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, - SpanAllocator& alloc, SpanGenerator& span_gen) - { - if(ras.rewind_scanlines()) - { - sl.reset(ras.min_x(), ras.max_x()); - span_gen.prepare(); - while(ras.sweep_scanline(sl)) - { - render_scanline_bin(sl, ren, alloc, span_gen); - } - } - } - - //====================================================renderer_scanline_bin - template - class renderer_scanline_bin - { - public: - typedef BaseRenderer base_ren_type; - typedef SpanAllocator alloc_type; - typedef SpanGenerator span_gen_type; - - //-------------------------------------------------------------------- - renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {} - renderer_scanline_bin(base_ren_type& ren, - alloc_type& alloc, - span_gen_type& span_gen) : - m_ren(&ren), - m_alloc(&alloc), - m_span_gen(&span_gen) - {} - void attach(base_ren_type& ren, - alloc_type& alloc, - span_gen_type& span_gen) - { - m_ren = &ren; - m_alloc = &alloc; - m_span_gen = &span_gen; - } - - //-------------------------------------------------------------------- - void prepare() { m_span_gen->prepare(); } - - //-------------------------------------------------------------------- - template void render(const Scanline& sl) - { - render_scanline_bin(sl, *m_ren, *m_alloc, *m_span_gen); - } - - private: - base_ren_type* m_ren; - alloc_type* m_alloc; - span_gen_type* m_span_gen; - }; - - - - - - - - - - - //========================================================render_scanlines - template - void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren) - { - if(ras.rewind_scanlines()) - { - sl.reset(ras.min_x(), ras.max_x()); - ren.prepare(); - while(ras.sweep_scanline(sl)) - { - ren.render(sl); - } - } - } - - //========================================================render_all_paths - template - void render_all_paths(Rasterizer& ras, - Scanline& sl, - Renderer& r, - VertexSource& vs, - const ColorStorage& as, - const PathId& path_id, - unsigned num_paths) - { - for(unsigned i = 0; i < num_paths; i++) - { - ras.reset(); - ras.add_path(vs, path_id[i]); - r.color(as[i]); - render_scanlines(ras, sl, r); - } - } - - - - - - - //=============================================render_scanlines_compound - template - void render_scanlines_compound(Rasterizer& ras, - ScanlineAA& sl_aa, - ScanlineBin& sl_bin, - BaseRenderer& ren, - SpanAllocator& alloc, - StyleHandler& sh) - { - if(ras.rewind_scanlines()) - { - int min_x = ras.min_x(); - int len = ras.max_x() - min_x + 2; - sl_aa.reset(min_x, ras.max_x()); - sl_bin.reset(min_x, ras.max_x()); - - typedef typename BaseRenderer::color_type color_type; - color_type* color_span = alloc.allocate(len * 2); - color_type* mix_buffer = color_span + len; - unsigned num_spans; - - unsigned num_styles; - unsigned style; - bool solid; - while((num_styles = ras.sweep_styles()) > 0) - { - typename ScanlineAA::const_iterator span_aa; - if(num_styles == 1) - { - // Optimization for a single style. Happens often - //------------------------- - if(ras.sweep_scanline(sl_aa, 0)) - { - style = ras.style(0); - if(sh.is_solid(style)) - { - // Just solid fill - //----------------------- - render_scanline_aa_solid(sl_aa, ren, sh.color(style)); - } - else - { - // Arbitrary span generator - //----------------------- - span_aa = sl_aa.begin(); - num_spans = sl_aa.num_spans(); - for(;;) - { - len = span_aa->len; - sh.generate_span(color_span, - span_aa->x, - sl_aa.y(), - len, - style); - - ren.blend_color_hspan(span_aa->x, - sl_aa.y(), - span_aa->len, - color_span, - span_aa->covers); - if(--num_spans == 0) break; - ++span_aa; - } - } - } - } - else - { - if(ras.sweep_scanline(sl_bin, -1)) - { - // Clear the spans of the mix_buffer - //-------------------- - typename ScanlineBin::const_iterator span_bin = sl_bin.begin(); - num_spans = sl_bin.num_spans(); - for(;;) - { - memset(mix_buffer + span_bin->x - min_x, - 0, - span_bin->len * sizeof(color_type)); - - if(--num_spans == 0) break; - ++span_bin; - } - - unsigned i; - for(i = 0; i < num_styles; i++) - { - style = ras.style(i); - solid = sh.is_solid(style); - - if(ras.sweep_scanline(sl_aa, i)) - { - color_type* colors; - color_type* cspan; - typename ScanlineAA::cover_type* covers; - span_aa = sl_aa.begin(); - num_spans = sl_aa.num_spans(); - if(solid) - { - // Just solid fill - //----------------------- - for(;;) - { - color_type c = sh.color(style); - len = span_aa->len; - colors = mix_buffer + span_aa->x - min_x; - covers = span_aa->covers; - do - { - if(*covers == cover_full) - { - *colors = c; - } - else - { - colors->add(c, *covers); - } - ++colors; - ++covers; - } - while(--len); - if(--num_spans == 0) break; - ++span_aa; - } - } - else - { - // Arbitrary span generator - //----------------------- - for(;;) - { - len = span_aa->len; - colors = mix_buffer + span_aa->x - min_x; - cspan = color_span; - sh.generate_span(cspan, - span_aa->x, - sl_aa.y(), - len, - style); - covers = span_aa->covers; - do - { - if(*covers == cover_full) - { - *colors = *cspan; - } - else - { - colors->add(*cspan, *covers); - } - ++cspan; - ++colors; - ++covers; - } - while(--len); - if(--num_spans == 0) break; - ++span_aa; - } - } - } - } - - // Emit the blended result as a color hspan - //------------------------- - span_bin = sl_bin.begin(); - num_spans = sl_bin.num_spans(); - for(;;) - { - ren.blend_color_hspan(span_bin->x, - sl_bin.y(), - span_bin->len, - mix_buffer + span_bin->x - min_x, - 0, - cover_full); - if(--num_spans == 0) break; - ++span_bin; - } - } // if(ras.sweep_scanline(sl_bin, -1)) - } // if(num_styles == 1) ... else - } // while((num_styles = ras.sweep_styles()) > 0) - } // if(ras.rewind_scanlines()) - } - - //=======================================render_scanlines_compound_layered - template - void render_scanlines_compound_layered(Rasterizer& ras, - ScanlineAA& sl_aa, - BaseRenderer& ren, - SpanAllocator& alloc, - StyleHandler& sh) - { - if(ras.rewind_scanlines()) - { - int min_x = ras.min_x(); - int len = ras.max_x() - min_x + 2; - sl_aa.reset(min_x, ras.max_x()); - - typedef typename BaseRenderer::color_type color_type; - color_type* color_span = alloc.allocate(len * 2); - color_type* mix_buffer = color_span + len; - cover_type* cover_buffer = ras.allocate_cover_buffer(len); - unsigned num_spans; - - unsigned num_styles; - unsigned style; - bool solid; - while((num_styles = ras.sweep_styles()) > 0) - { - typename ScanlineAA::const_iterator span_aa; - if(num_styles == 1) - { - // Optimization for a single style. Happens often - //------------------------- - if(ras.sweep_scanline(sl_aa, 0)) - { - style = ras.style(0); - if(sh.is_solid(style)) - { - // Just solid fill - //----------------------- - render_scanline_aa_solid(sl_aa, ren, sh.color(style)); - } - else - { - // Arbitrary span generator - //----------------------- - span_aa = sl_aa.begin(); - num_spans = sl_aa.num_spans(); - for(;;) - { - len = span_aa->len; - sh.generate_span(color_span, - span_aa->x, - sl_aa.y(), - len, - style); - - ren.blend_color_hspan(span_aa->x, - sl_aa.y(), - span_aa->len, - color_span, - span_aa->covers); - if(--num_spans == 0) break; - ++span_aa; - } - } - } - } - else - { - int sl_start = ras.scanline_start(); - unsigned sl_len = ras.scanline_length(); - - if(sl_len) - { - memset(mix_buffer + sl_start - min_x, - 0, - sl_len * sizeof(color_type)); - - memset(cover_buffer + sl_start - min_x, - 0, - sl_len * sizeof(cover_type)); - - int sl_y = 0x7FFFFFFF; - unsigned i; - for(i = 0; i < num_styles; i++) - { - style = ras.style(i); - solid = sh.is_solid(style); - - if(ras.sweep_scanline(sl_aa, i)) - { - unsigned cover; - color_type* colors; - color_type* cspan; - cover_type* src_covers; - cover_type* dst_covers; - span_aa = sl_aa.begin(); - num_spans = sl_aa.num_spans(); - sl_y = sl_aa.y(); - if(solid) - { - // Just solid fill - //----------------------- - for(;;) - { - color_type c = sh.color(style); - len = span_aa->len; - colors = mix_buffer + span_aa->x - min_x; - src_covers = span_aa->covers; - dst_covers = cover_buffer + span_aa->x - min_x; - do - { - cover = *src_covers; - if(*dst_covers + cover > cover_full) - { - cover = cover_full - *dst_covers; - } - if(cover) - { - colors->add(c, cover); - *dst_covers += cover; - } - ++colors; - ++src_covers; - ++dst_covers; - } - while(--len); - if(--num_spans == 0) break; - ++span_aa; - } - } - else - { - // Arbitrary span generator - //----------------------- - for(;;) - { - len = span_aa->len; - colors = mix_buffer + span_aa->x - min_x; - cspan = color_span; - sh.generate_span(cspan, - span_aa->x, - sl_aa.y(), - len, - style); - src_covers = span_aa->covers; - dst_covers = cover_buffer + span_aa->x - min_x; - do - { - cover = *src_covers; - if(*dst_covers + cover > cover_full) - { - cover = cover_full - *dst_covers; - } - if(cover) - { - colors->add(*cspan, cover); - *dst_covers += cover; - } - ++cspan; - ++colors; - ++src_covers; - ++dst_covers; - } - while(--len); - if(--num_spans == 0) break; - ++span_aa; - } - } - } - } - ren.blend_color_hspan(sl_start, - sl_y, - sl_len, - mix_buffer + sl_start - min_x, - 0, - cover_full); - } //if(sl_len) - } //if(num_styles == 1) ... else - } //while((num_styles = ras.sweep_styles()) > 0) - } //if(ras.rewind_scanlines()) - } - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_rendering_buffer_dynarow.h corsix-th-0.62/agg/include/agg_rendering_buffer_dynarow.h --- corsix-th-0.30/agg/include/agg_rendering_buffer_dynarow.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rendering_buffer_dynarow.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,137 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class rendering_buffer_dynarow -// -//---------------------------------------------------------------------------- - -#ifndef AGG_RENDERING_BUFFER_DYNAROW_INCLUDED -#define AGG_RENDERING_BUFFER_DYNAROW_INCLUDED - -#include "agg_array.h" - -namespace agg -{ - - //===============================================rendering_buffer_dynarow - // Rendering buffer class with dynamic allocation of the rows. - // The rows are allocated as needed when requesting for span_ptr(). - // The class automatically calculates min_x and max_x for each row. - // Generally it's more efficient to use this class as a temporary buffer - // for rendering a few lines and then to blend it with another buffer. - // - class rendering_buffer_dynarow - { - public: - typedef row_info row_data; - - //------------------------------------------------------------------- - ~rendering_buffer_dynarow() - { - init(0,0,0); - } - - //------------------------------------------------------------------- - rendering_buffer_dynarow() : - m_rows(), - m_width(0), - m_height(0), - m_byte_width(0) - { - } - - // Allocate and clear the buffer - //-------------------------------------------------------------------- - rendering_buffer_dynarow(unsigned width, unsigned height, - unsigned byte_width) : - m_rows(height), - m_width(width), - m_height(height), - m_byte_width(byte_width) - { - memset(&m_rows[0], 0, sizeof(row_data) * height); - } - - // Allocate and clear the buffer - //-------------------------------------------------------------------- - void init(unsigned width, unsigned height, unsigned byte_width) - { - unsigned i; - for(i = 0; i < m_height; ++i) - { - pod_allocator::deallocate((int8u*)m_rows[i].ptr, m_byte_width); - } - if(width && height) - { - m_width = width; - m_height = height; - m_byte_width = byte_width; - m_rows.resize(height); - memset(&m_rows[0], 0, sizeof(row_data) * height); - } - } - - //-------------------------------------------------------------------- - unsigned width() const { return m_width; } - unsigned height() const { return m_height; } - unsigned byte_width() const { return m_byte_width; } - - // The main function used for rendering. Returns pointer to the - // pre-allocated span. Memory for the row is allocated as needed. - //-------------------------------------------------------------------- - int8u* row_ptr(int x, int y, unsigned len) - { - row_data* r = &m_rows[y]; - int x2 = x + len - 1; - if(r->ptr) - { - if(x < r->x1) { r->x1 = x; } - if(x2 > r->x2) { r->x2 = x2; } - } - else - { - int8u* p = pod_allocator::allocate(m_byte_width); - r->ptr = p; - r->x1 = x; - r->x2 = x2; - memset(p, 0, m_byte_width); - } - return (int8u*)r->ptr; - } - - //-------------------------------------------------------------------- - const int8u* row_ptr(int y) const { return m_rows[y].ptr; } - int8u* row_ptr(int y) { return row_ptr(0, y, m_width); } - row_data row (int y) const { return m_rows[y]; } - - private: - //-------------------------------------------------------------------- - // Prohibit copying - rendering_buffer_dynarow(const rendering_buffer_dynarow&); - const rendering_buffer_dynarow& operator = (const rendering_buffer_dynarow&); - - private: - //-------------------------------------------------------------------- - pod_array m_rows; // Pointers to each row of the buffer - unsigned m_width; // Width in pixels - unsigned m_height; // Height in pixels - unsigned m_byte_width; // Width in bytes - }; - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_rendering_buffer.h corsix-th-0.62/agg/include/agg_rendering_buffer.h --- corsix-th-0.30/agg/include/agg_rendering_buffer.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rendering_buffer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,300 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class rendering_buffer -// -//---------------------------------------------------------------------------- - -#ifndef AGG_RENDERING_BUFFER_INCLUDED -#define AGG_RENDERING_BUFFER_INCLUDED - -#include "agg_array.h" - -namespace agg -{ - - //===========================================================row_accessor - template class row_accessor - { - public: - typedef const_row_info row_data; - - //------------------------------------------------------------------- - row_accessor() : - m_buf(0), - m_start(0), - m_width(0), - m_height(0), - m_stride(0) - { - } - - //-------------------------------------------------------------------- - row_accessor(T* buf, unsigned width, unsigned height, int stride) : - m_buf(0), - m_start(0), - m_width(0), - m_height(0), - m_stride(0) - { - attach(buf, width, height, stride); - } - - - //-------------------------------------------------------------------- - void attach(T* buf, unsigned width, unsigned height, int stride) - { - m_buf = m_start = buf; - m_width = width; - m_height = height; - m_stride = stride; - if(stride < 0) - { - m_start = m_buf - int(height - 1) * stride; - } - } - - //-------------------------------------------------------------------- - AGG_INLINE T* buf() { return m_buf; } - AGG_INLINE const T* buf() const { return m_buf; } - AGG_INLINE unsigned width() const { return m_width; } - AGG_INLINE unsigned height() const { return m_height; } - AGG_INLINE int stride() const { return m_stride; } - AGG_INLINE unsigned stride_abs() const - { - return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); - } - - //-------------------------------------------------------------------- - AGG_INLINE T* row_ptr(int, int y, unsigned) - { - return m_start + y * m_stride; - } - AGG_INLINE T* row_ptr(int y) { return m_start + y * m_stride; } - AGG_INLINE const T* row_ptr(int y) const { return m_start + y * m_stride; } - AGG_INLINE row_data row (int y) const - { - return row_data(0, m_width-1, row_ptr(y)); - } - - //-------------------------------------------------------------------- - template - void copy_from(const RenBuf& src) - { - unsigned h = height(); - if(src.height() < h) h = src.height(); - - unsigned l = stride_abs(); - if(src.stride_abs() < l) l = src.stride_abs(); - - l *= sizeof(T); - - unsigned y; - unsigned w = width(); - for (y = 0; y < h; y++) - { - memcpy(row_ptr(0, y, w), src.row_ptr(y), l); - } - } - - //-------------------------------------------------------------------- - void clear(T value) - { - unsigned y; - unsigned w = width(); - unsigned stride = stride_abs(); - for(y = 0; y < height(); y++) - { - T* p = row_ptr(0, y, w); - unsigned x; - for(x = 0; x < stride; x++) - { - *p++ = value; - } - } - } - - private: - //-------------------------------------------------------------------- - T* m_buf; // Pointer to renrdering buffer - T* m_start; // Pointer to first pixel depending on stride - unsigned m_width; // Width in pixels - unsigned m_height; // Height in pixels - int m_stride; // Number of bytes per row. Can be < 0 - }; - - - - - //==========================================================row_ptr_cache - template class row_ptr_cache - { - public: - typedef const_row_info row_data; - - //------------------------------------------------------------------- - row_ptr_cache() : - m_buf(0), - m_rows(), - m_width(0), - m_height(0), - m_stride(0) - { - } - - //-------------------------------------------------------------------- - row_ptr_cache(T* buf, unsigned width, unsigned height, int stride) : - m_buf(0), - m_rows(), - m_width(0), - m_height(0), - m_stride(0) - { - attach(buf, width, height, stride); - } - - //-------------------------------------------------------------------- - void attach(T* buf, unsigned width, unsigned height, int stride) - { - m_buf = buf; - m_width = width; - m_height = height; - m_stride = stride; - if(height > m_rows.size()) - { - m_rows.resize(height); - } - - T* row_ptr = m_buf; - - if(stride < 0) - { - row_ptr = m_buf - int(height - 1) * stride; - } - - T** rows = &m_rows[0]; - - while(height--) - { - *rows++ = row_ptr; - row_ptr += stride; - } - } - - //-------------------------------------------------------------------- - AGG_INLINE T* buf() { return m_buf; } - AGG_INLINE const T* buf() const { return m_buf; } - AGG_INLINE unsigned width() const { return m_width; } - AGG_INLINE unsigned height() const { return m_height; } - AGG_INLINE int stride() const { return m_stride; } - AGG_INLINE unsigned stride_abs() const - { - return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); - } - - //-------------------------------------------------------------------- - AGG_INLINE T* row_ptr(int, int y, unsigned) - { - return m_rows[y]; - } - AGG_INLINE T* row_ptr(int y) { return m_rows[y]; } - AGG_INLINE const T* row_ptr(int y) const { return m_rows[y]; } - AGG_INLINE row_data row (int y) const - { - return row_data(0, m_width-1, m_rows[y]); - } - - //-------------------------------------------------------------------- - T const* const* rows() const { return &m_rows[0]; } - - //-------------------------------------------------------------------- - template - void copy_from(const RenBuf& src) - { - unsigned h = height(); - if(src.height() < h) h = src.height(); - - unsigned l = stride_abs(); - if(src.stride_abs() < l) l = src.stride_abs(); - - l *= sizeof(T); - - unsigned y; - unsigned w = width(); - for (y = 0; y < h; y++) - { - memcpy(row_ptr(0, y, w), src.row_ptr(y), l); - } - } - - //-------------------------------------------------------------------- - void clear(T value) - { - unsigned y; - unsigned w = width(); - unsigned stride = stride_abs(); - for(y = 0; y < height(); y++) - { - T* p = row_ptr(0, y, w); - unsigned x; - for(x = 0; x < stride; x++) - { - *p++ = value; - } - } - } - - private: - //-------------------------------------------------------------------- - T* m_buf; // Pointer to renrdering buffer - pod_array m_rows; // Pointers to each row of the buffer - unsigned m_width; // Width in pixels - unsigned m_height; // Height in pixels - int m_stride; // Number of bytes per row. Can be < 0 - }; - - - - - //========================================================rendering_buffer - // - // The definition of the main type for accessing the rows in the frame - // buffer. It provides functionality to navigate to the rows in a - // rectangular matrix, from top to bottom or from bottom to top depending - // on stride. - // - // row_accessor is cheap to create/destroy, but performs one multiplication - // when calling row_ptr(). - // - // row_ptr_cache creates an array of pointers to rows, so, the access - // via row_ptr() may be faster. But it requires memory allocation - // when creating. For example, on typical Intel Pentium hardware - // row_ptr_cache speeds span_image_filter_rgb_nn up to 10% - // - // It's used only in short hand typedefs like pixfmt_rgba32 and can be - // redefined in agg_config.h - // In real applications you can use both, depending on your needs - //------------------------------------------------------------------------ -#ifdef AGG_RENDERING_BUFFER - typedef AGG_RENDERING_BUFFER rendering_buffer; -#else -// typedef row_ptr_cache rendering_buffer; - typedef row_accessor rendering_buffer; -#endif - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_rounded_rect.h corsix-th-0.62/agg/include/agg_rounded_rect.h --- corsix-th-0.30/agg/include/agg_rounded_rect.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_rounded_rect.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Rounded rectangle vertex generator -// -//---------------------------------------------------------------------------- - -#ifndef AGG_ROUNDED_RECT_INCLUDED -#define AGG_ROUNDED_RECT_INCLUDED - -#include "agg_basics.h" -#include "agg_arc.h" - -namespace agg -{ - //------------------------------------------------------------rounded_rect - // - // See Implemantation agg_rounded_rect.cpp - // - class rounded_rect - { - public: - rounded_rect() {} - rounded_rect(double x1, double y1, double x2, double y2, double r); - - void rect(double x1, double y1, double x2, double y2); - void radius(double r); - void radius(double rx, double ry); - void radius(double rx_bottom, double ry_bottom, double rx_top, double ry_top); - void radius(double rx1, double ry1, double rx2, double ry2, - double rx3, double ry3, double rx4, double ry4); - void normalize_radius(); - - void approximation_scale(double s) { m_arc.approximation_scale(s); } - double approximation_scale() const { return m_arc.approximation_scale(); } - - void rewind(unsigned); - unsigned vertex(double* x, double* y); - - private: - double m_x1; - double m_y1; - double m_x2; - double m_y2; - double m_rx1; - double m_ry1; - double m_rx2; - double m_ry2; - double m_rx3; - double m_ry3; - double m_rx4; - double m_ry4; - unsigned m_status; - arc m_arc; - }; - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_scanline_bin.h corsix-th-0.62/agg/include/agg_scanline_bin.h --- corsix-th-0.30/agg/include/agg_scanline_bin.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_scanline_bin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,264 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Class scanline_bin - binary scanline. -// -//---------------------------------------------------------------------------- -// -// Adaptation for 32-bit screen coordinates (scanline32_bin) has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_SCANLINE_BIN_INCLUDED -#define AGG_SCANLINE_BIN_INCLUDED - -#include "agg_array.h" - -namespace agg -{ - - //=============================================================scanline_bin - // - // This is binary scaline container which supports the interface - // used in the rasterizer::render(). See description of agg_scanline_u8 - // for details. - // - //------------------------------------------------------------------------ - class scanline_bin - { - public: - typedef int32 coord_type; - - struct span - { - int16 x; - int16 len; - }; - - typedef const span* const_iterator; - - //-------------------------------------------------------------------- - scanline_bin() : - m_last_x(0x7FFFFFF0), - m_spans(), - m_cur_span(0) - { - } - - //-------------------------------------------------------------------- - void reset(int min_x, int max_x) - { - unsigned max_len = max_x - min_x + 3; - if(max_len > m_spans.size()) - { - m_spans.resize(max_len); - } - m_last_x = 0x7FFFFFF0; - m_cur_span = &m_spans[0]; - } - - //-------------------------------------------------------------------- - void add_cell(int x, unsigned) - { - if(x == m_last_x+1) - { - m_cur_span->len++; - } - else - { - ++m_cur_span; - m_cur_span->x = (int16)x; - m_cur_span->len = 1; - } - m_last_x = x; - } - - //-------------------------------------------------------------------- - void add_span(int x, unsigned len, unsigned) - { - if(x == m_last_x+1) - { - m_cur_span->len = (int16)(m_cur_span->len + len); - } - else - { - ++m_cur_span; - m_cur_span->x = (int16)x; - m_cur_span->len = (int16)len; - } - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void add_cells(int x, unsigned len, const void*) - { - add_span(x, len, 0); - } - - //-------------------------------------------------------------------- - void finalize(int y) - { - m_y = y; - } - - //-------------------------------------------------------------------- - void reset_spans() - { - m_last_x = 0x7FFFFFF0; - m_cur_span = &m_spans[0]; - } - - //-------------------------------------------------------------------- - int y() const { return m_y; } - unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } - const_iterator begin() const { return &m_spans[1]; } - - private: - scanline_bin(const scanline_bin&); - const scanline_bin operator = (const scanline_bin&); - - int m_last_x; - int m_y; - pod_array m_spans; - span* m_cur_span; - }; - - - - - - - //===========================================================scanline32_bin - class scanline32_bin - { - public: - typedef int32 coord_type; - - //-------------------------------------------------------------------- - struct span - { - span() {} - span(coord_type x_, coord_type len_) : x(x_), len(len_) {} - - coord_type x; - coord_type len; - }; - typedef pod_bvector span_array_type; - - - //-------------------------------------------------------------------- - class const_iterator - { - public: - const_iterator(const span_array_type& spans) : - m_spans(spans), - m_span_idx(0) - {} - - const span& operator*() const { return m_spans[m_span_idx]; } - const span* operator->() const { return &m_spans[m_span_idx]; } - - void operator ++ () { ++m_span_idx; } - - private: - const span_array_type& m_spans; - unsigned m_span_idx; - }; - - - //-------------------------------------------------------------------- - scanline32_bin() : m_max_len(0), m_last_x(0x7FFFFFF0) {} - - //-------------------------------------------------------------------- - void reset(int min_x, int max_x) - { - m_last_x = 0x7FFFFFF0; - m_spans.remove_all(); - } - - //-------------------------------------------------------------------- - void add_cell(int x, unsigned) - { - if(x == m_last_x+1) - { - m_spans.last().len++; - } - else - { - m_spans.add(span(coord_type(x), 1)); - } - m_last_x = x; - } - - //-------------------------------------------------------------------- - void add_span(int x, unsigned len, unsigned) - { - if(x == m_last_x+1) - { - m_spans.last().len += coord_type(len); - } - else - { - m_spans.add(span(coord_type(x), coord_type(len))); - } - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void add_cells(int x, unsigned len, const void*) - { - add_span(x, len, 0); - } - - //-------------------------------------------------------------------- - void finalize(int y) - { - m_y = y; - } - - //-------------------------------------------------------------------- - void reset_spans() - { - m_last_x = 0x7FFFFFF0; - m_spans.remove_all(); - } - - //-------------------------------------------------------------------- - int y() const { return m_y; } - unsigned num_spans() const { return m_spans.size(); } - const_iterator begin() const { return const_iterator(m_spans); } - - private: - scanline32_bin(const scanline32_bin&); - const scanline32_bin operator = (const scanline32_bin&); - - unsigned m_max_len; - int m_last_x; - int m_y; - span_array_type m_spans; - }; - - - - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_scanline_boolean_algebra.h corsix-th-0.62/agg/include/agg_scanline_boolean_algebra.h --- corsix-th-0.30/agg/include/agg_scanline_boolean_algebra.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_scanline_boolean_algebra.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1567 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED -#define AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED - -#include -#include -#include "agg_basics.h" - - -namespace agg -{ - - //-----------------------------------------------sbool_combine_spans_bin - // Functor. - // Combine two binary encoded spans, i.e., when we don't have any - // anti-aliasing information, but only X and Length. The function - // is compatible with any type of scanlines. - //---------------- - template - struct sbool_combine_spans_bin - { - void operator () (const typename Scanline1::const_iterator&, - const typename Scanline2::const_iterator&, - int x, unsigned len, - Scanline& sl) const - { - sl.add_span(x, len, cover_full); - } - }; - - - - //---------------------------------------------sbool_combine_spans_empty - // Functor. - // Combine two spans as empty ones. The functor does nothing - // and is used to XOR binary spans. - //---------------- - template - struct sbool_combine_spans_empty - { - void operator () (const typename Scanline1::const_iterator&, - const typename Scanline2::const_iterator&, - int, unsigned, - Scanline&) const - {} - }; - - - - //--------------------------------------------------sbool_add_span_empty - // Functor. - // Add nothing. Used in conbine_shapes_sub - //---------------- - template - struct sbool_add_span_empty - { - void operator () (const typename Scanline1::const_iterator&, - int, unsigned, - Scanline&) const - {} - }; - - - //----------------------------------------------------sbool_add_span_bin - // Functor. - // Add a binary span - //---------------- - template - struct sbool_add_span_bin - { - void operator () (const typename Scanline1::const_iterator&, - int x, unsigned len, - Scanline& sl) const - { - sl.add_span(x, len, cover_full); - } - }; - - - - - //-----------------------------------------------------sbool_add_span_aa - // Functor. - // Add an anti-aliased span - // anti-aliasing information, but only X and Length. The function - // is compatible with any type of scanlines. - //---------------- - template - struct sbool_add_span_aa - { - void operator () (const typename Scanline1::const_iterator& span, - int x, unsigned len, - Scanline& sl) const - { - if(span->len < 0) - { - sl.add_span(x, len, *span->covers); - } - else - if(span->len > 0) - { - const typename Scanline1::cover_type* covers = span->covers; - if(span->x < x) covers += x - span->x; - sl.add_cells(x, len, covers); - } - } - }; - - - - - //----------------------------------------------sbool_intersect_spans_aa - // Functor. - // Intersect two spans preserving the anti-aliasing information. - // The result is added to the "sl" scanline. - //------------------ - template - struct sbool_intersect_spans_aa - { - enum cover_scale_e - { - cover_shift = CoverShift, - cover_size = 1 << cover_shift, - cover_mask = cover_size - 1, - cover_full = cover_mask - }; - - - void operator () (const typename Scanline1::const_iterator& span1, - const typename Scanline2::const_iterator& span2, - int x, unsigned len, - Scanline& sl) const - { - unsigned cover; - const typename Scanline1::cover_type* covers1; - const typename Scanline2::cover_type* covers2; - - // Calculate the operation code and choose the - // proper combination algorithm. - // 0 = Both spans are of AA type - // 1 = span1 is solid, span2 is AA - // 2 = span1 is AA, span2 is solid - // 3 = Both spans are of solid type - //----------------- - switch((span1->len < 0) | ((span2->len < 0) << 1)) - { - case 0: // Both are AA spans - covers1 = span1->covers; - covers2 = span2->covers; - if(span1->x < x) covers1 += x - span1->x; - if(span2->x < x) covers2 += x - span2->x; - do - { - cover = *covers1++ * *covers2++; - sl.add_cell(x++, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - while(--len); - break; - - case 1: // span1 is solid, span2 is AA - covers2 = span2->covers; - if(span2->x < x) covers2 += x - span2->x; - if(*(span1->covers) == cover_full) - { - sl.add_cells(x, len, covers2); - } - else - { - do - { - cover = *(span1->covers) * *covers2++; - sl.add_cell(x++, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - while(--len); - } - break; - - case 2: // span1 is AA, span2 is solid - covers1 = span1->covers; - if(span1->x < x) covers1 += x - span1->x; - if(*(span2->covers) == cover_full) - { - sl.add_cells(x, len, covers1); - } - else - { - do - { - cover = *covers1++ * *(span2->covers); - sl.add_cell(x++, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - while(--len); - } - break; - - case 3: // Both are solid spans - cover = *(span1->covers) * *(span2->covers); - sl.add_span(x, len, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - break; - } - } - }; - - - - - - - //--------------------------------------------------sbool_unite_spans_aa - // Functor. - // Unite two spans preserving the anti-aliasing information. - // The result is added to the "sl" scanline. - //------------------ - template - struct sbool_unite_spans_aa - { - enum cover_scale_e - { - cover_shift = CoverShift, - cover_size = 1 << cover_shift, - cover_mask = cover_size - 1, - cover_full = cover_mask - }; - - - void operator () (const typename Scanline1::const_iterator& span1, - const typename Scanline2::const_iterator& span2, - int x, unsigned len, - Scanline& sl) const - { - unsigned cover; - const typename Scanline1::cover_type* covers1; - const typename Scanline2::cover_type* covers2; - - // Calculate the operation code and choose the - // proper combination algorithm. - // 0 = Both spans are of AA type - // 1 = span1 is solid, span2 is AA - // 2 = span1 is AA, span2 is solid - // 3 = Both spans are of solid type - //----------------- - switch((span1->len < 0) | ((span2->len < 0) << 1)) - { - case 0: // Both are AA spans - covers1 = span1->covers; - covers2 = span2->covers; - if(span1->x < x) covers1 += x - span1->x; - if(span2->x < x) covers2 += x - span2->x; - do - { - cover = cover_mask * cover_mask - - (cover_mask - *covers1++) * - (cover_mask - *covers2++); - sl.add_cell(x++, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - while(--len); - break; - - case 1: // span1 is solid, span2 is AA - covers2 = span2->covers; - if(span2->x < x) covers2 += x - span2->x; - if(*(span1->covers) == cover_full) - { - sl.add_span(x, len, cover_full); - } - else - { - do - { - cover = cover_mask * cover_mask - - (cover_mask - *(span1->covers)) * - (cover_mask - *covers2++); - sl.add_cell(x++, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - while(--len); - } - break; - - case 2: // span1 is AA, span2 is solid - covers1 = span1->covers; - if(span1->x < x) covers1 += x - span1->x; - if(*(span2->covers) == cover_full) - { - sl.add_span(x, len, cover_full); - } - else - { - do - { - cover = cover_mask * cover_mask - - (cover_mask - *covers1++) * - (cover_mask - *(span2->covers)); - sl.add_cell(x++, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - while(--len); - } - break; - - case 3: // Both are solid spans - cover = cover_mask * cover_mask - - (cover_mask - *(span1->covers)) * - (cover_mask - *(span2->covers)); - sl.add_span(x, len, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - break; - } - } - }; - - - //---------------------------------------------sbool_xor_formula_linear - template - struct sbool_xor_formula_linear - { - enum cover_scale_e - { - cover_shift = CoverShift, - cover_size = 1 << cover_shift, - cover_mask = cover_size - 1 - }; - - static AGG_INLINE unsigned calculate(unsigned a, unsigned b) - { - unsigned cover = a + b; - if(cover > cover_mask) cover = cover_mask + cover_mask - cover; - return cover; - } - }; - - - //---------------------------------------------sbool_xor_formula_saddle - template - struct sbool_xor_formula_saddle - { - enum cover_scale_e - { - cover_shift = CoverShift, - cover_size = 1 << cover_shift, - cover_mask = cover_size - 1 - }; - - static AGG_INLINE unsigned calculate(unsigned a, unsigned b) - { - unsigned k = a * b; - if(k == cover_mask * cover_mask) return 0; - - a = (cover_mask * cover_mask - (a << cover_shift) + k) >> cover_shift; - b = (cover_mask * cover_mask - (b << cover_shift) + k) >> cover_shift; - return cover_mask - ((a * b) >> cover_shift); - } - }; - - - //-------------------------------------------sbool_xor_formula_abs_diff - struct sbool_xor_formula_abs_diff - { - static AGG_INLINE unsigned calculate(unsigned a, unsigned b) - { - return unsigned(abs(int(a) - int(b))); - } - }; - - - - //----------------------------------------------------sbool_xor_spans_aa - // Functor. - // XOR two spans preserving the anti-aliasing information. - // The result is added to the "sl" scanline. - //------------------ - template - struct sbool_xor_spans_aa - { - enum cover_scale_e - { - cover_shift = CoverShift, - cover_size = 1 << cover_shift, - cover_mask = cover_size - 1, - cover_full = cover_mask - }; - - - void operator () (const typename Scanline1::const_iterator& span1, - const typename Scanline2::const_iterator& span2, - int x, unsigned len, - Scanline& sl) const - { - unsigned cover; - const typename Scanline1::cover_type* covers1; - const typename Scanline2::cover_type* covers2; - - // Calculate the operation code and choose the - // proper combination algorithm. - // 0 = Both spans are of AA type - // 1 = span1 is solid, span2 is AA - // 2 = span1 is AA, span2 is solid - // 3 = Both spans are of solid type - //----------------- - switch((span1->len < 0) | ((span2->len < 0) << 1)) - { - case 0: // Both are AA spans - covers1 = span1->covers; - covers2 = span2->covers; - if(span1->x < x) covers1 += x - span1->x; - if(span2->x < x) covers2 += x - span2->x; - do - { - cover = XorFormula::calculate(*covers1++, *covers2++); - if(cover) sl.add_cell(x, cover); - ++x; - } - while(--len); - break; - - case 1: // span1 is solid, span2 is AA - covers2 = span2->covers; - if(span2->x < x) covers2 += x - span2->x; - do - { - cover = XorFormula::calculate(*(span1->covers), *covers2++); - if(cover) sl.add_cell(x, cover); - ++x; - } - while(--len); - break; - - case 2: // span1 is AA, span2 is solid - covers1 = span1->covers; - if(span1->x < x) covers1 += x - span1->x; - do - { - cover = XorFormula::calculate(*covers1++, *(span2->covers)); - if(cover) sl.add_cell(x, cover); - ++x; - } - while(--len); - break; - - case 3: // Both are solid spans - cover = XorFormula::calculate(*(span1->covers), *(span2->covers)); - if(cover) sl.add_span(x, len, cover); - break; - - } - } - }; - - - - - - //-----------------------------------------------sbool_subtract_spans_aa - // Functor. - // Unite two spans preserving the anti-aliasing information. - // The result is added to the "sl" scanline. - //------------------ - template - struct sbool_subtract_spans_aa - { - enum cover_scale_e - { - cover_shift = CoverShift, - cover_size = 1 << cover_shift, - cover_mask = cover_size - 1, - cover_full = cover_mask - }; - - - void operator () (const typename Scanline1::const_iterator& span1, - const typename Scanline2::const_iterator& span2, - int x, unsigned len, - Scanline& sl) const - { - unsigned cover; - const typename Scanline1::cover_type* covers1; - const typename Scanline2::cover_type* covers2; - - // Calculate the operation code and choose the - // proper combination algorithm. - // 0 = Both spans are of AA type - // 1 = span1 is solid, span2 is AA - // 2 = span1 is AA, span2 is solid - // 3 = Both spans are of solid type - //----------------- - switch((span1->len < 0) | ((span2->len < 0) << 1)) - { - case 0: // Both are AA spans - covers1 = span1->covers; - covers2 = span2->covers; - if(span1->x < x) covers1 += x - span1->x; - if(span2->x < x) covers2 += x - span2->x; - do - { - cover = *covers1++ * (cover_mask - *covers2++); - if(cover) - { - sl.add_cell(x, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - ++x; - } - while(--len); - break; - - case 1: // span1 is solid, span2 is AA - covers2 = span2->covers; - if(span2->x < x) covers2 += x - span2->x; - do - { - cover = *(span1->covers) * (cover_mask - *covers2++); - if(cover) - { - sl.add_cell(x, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - ++x; - } - while(--len); - break; - - case 2: // span1 is AA, span2 is solid - covers1 = span1->covers; - if(span1->x < x) covers1 += x - span1->x; - if(*(span2->covers) != cover_full) - { - do - { - cover = *covers1++ * (cover_mask - *(span2->covers)); - if(cover) - { - sl.add_cell(x, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - ++x; - } - while(--len); - } - break; - - case 3: // Both are solid spans - cover = *(span1->covers) * (cover_mask - *(span2->covers)); - if(cover) - { - sl.add_span(x, len, - (cover == cover_full * cover_full) ? - cover_full : - (cover >> cover_shift)); - } - break; - } - } - }; - - - - - - - //--------------------------------------------sbool_add_spans_and_render - template - void sbool_add_spans_and_render(const Scanline1& sl1, - Scanline& sl, - Renderer& ren, - AddSpanFunctor add_span) - { - sl.reset_spans(); - typename Scanline1::const_iterator span = sl1.begin(); - unsigned num_spans = sl1.num_spans(); - for(;;) - { - add_span(span, span->x, abs((int)span->len), sl); - if(--num_spans == 0) break; - ++span; - } - sl.finalize(sl1.y()); - ren.render(sl); - } - - - - - - - - //---------------------------------------------sbool_intersect_scanlines - // Intersect two scanlines, "sl1" and "sl2" and generate a new "sl" one. - // The combine_spans functor can be of type sbool_combine_spans_bin or - // sbool_intersect_spans_aa. First is a general functor to combine - // two spans without Anti-Aliasing, the second preserves the AA - // information, but works slower - // - template - void sbool_intersect_scanlines(const Scanline1& sl1, - const Scanline2& sl2, - Scanline& sl, - CombineSpansFunctor combine_spans) - { - sl.reset_spans(); - - unsigned num1 = sl1.num_spans(); - if(num1 == 0) return; - - unsigned num2 = sl2.num_spans(); - if(num2 == 0) return; - - typename Scanline1::const_iterator span1 = sl1.begin(); - typename Scanline2::const_iterator span2 = sl2.begin(); - - while(num1 && num2) - { - int xb1 = span1->x; - int xb2 = span2->x; - int xe1 = xb1 + abs((int)span1->len) - 1; - int xe2 = xb2 + abs((int)span2->len) - 1; - - // Determine what spans we should advance in the next step - // The span with the least ending X should be advanced - // advance_both is just an optimization when we ending - // coordinates are the same and we can advance both - //-------------- - bool advance_span1 = xe1 < xe2; - bool advance_both = xe1 == xe2; - - // Find the intersection of the spans - // and check if they intersect - //-------------- - if(xb1 < xb2) xb1 = xb2; - if(xe1 > xe2) xe1 = xe2; - if(xb1 <= xe1) - { - combine_spans(span1, span2, xb1, xe1 - xb1 + 1, sl); - } - - // Advance the spans - //-------------- - if(advance_both) - { - --num1; - --num2; - if(num1) ++span1; - if(num2) ++span2; - } - else - { - if(advance_span1) - { - --num1; - if(num1) ++span1; - } - else - { - --num2; - if(num2) ++span2; - } - } - } - } - - - - - - - - - //------------------------------------------------sbool_intersect_shapes - // Intersect the scanline shapes. Here the "Scanline Generator" - // abstraction is used. ScanlineGen1 and ScanlineGen2 are - // the generators, and can be of type rasterizer_scanline_aa<>. - // There function requires three scanline containers that can be of - // different types. - // "sl1" and "sl2" are used to retrieve scanlines from the generators, - // "sl" is ised as the resulting scanline to render it. - // The external "sl1" and "sl2" are used only for the sake of - // optimization and reusing of the scanline objects. - // the function calls sbool_intersect_scanlines with CombineSpansFunctor - // as the last argument. See sbool_intersect_scanlines for details. - //---------- - template - void sbool_intersect_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren, - CombineSpansFunctor combine_spans) - { - // Prepare the scanline generators. - // If anyone of them doesn't contain - // any scanlines, then return. - //----------------- - if(!sg1.rewind_scanlines()) return; - if(!sg2.rewind_scanlines()) return; - - // Get the bounding boxes - //---------------- - rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y()); - rect_i r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y()); - - // Calculate the intersection of the bounding - // boxes and return if they don't intersect. - //----------------- - rect_i ir = intersect_rectangles(r1, r2); - if(!ir.is_valid()) return; - - // Reset the scanlines and get two first ones - //----------------- - sl.reset(ir.x1, ir.x2); - sl1.reset(sg1.min_x(), sg1.max_x()); - sl2.reset(sg2.min_x(), sg2.max_x()); - if(!sg1.sweep_scanline(sl1)) return; - if(!sg2.sweep_scanline(sl2)) return; - - ren.prepare(); - - // The main loop - // Here we synchronize the scanlines with - // the same Y coordinate, ignoring all other ones. - // Only scanlines having the same Y-coordinate - // are to be combined. - //----------------- - for(;;) - { - while(sl1.y() < sl2.y()) - { - if(!sg1.sweep_scanline(sl1)) return; - } - while(sl2.y() < sl1.y()) - { - if(!sg2.sweep_scanline(sl2)) return; - } - - if(sl1.y() == sl2.y()) - { - // The Y coordinates are the same. - // Combine the scanlines, render if they contain any spans, - // and advance both generators to the next scanlines - //---------------------- - sbool_intersect_scanlines(sl1, sl2, sl, combine_spans); - if(sl.num_spans()) - { - sl.finalize(sl1.y()); - ren.render(sl); - } - if(!sg1.sweep_scanline(sl1)) return; - if(!sg2.sweep_scanline(sl2)) return; - } - } - } - - - - - - - - //-------------------------------------------------sbool_unite_scanlines - // Unite two scanlines, "sl1" and "sl2" and generate a new "sl" one. - // The combine_spans functor can be of type sbool_combine_spans_bin or - // sbool_intersect_spans_aa. First is a general functor to combine - // two spans without Anti-Aliasing, the second preserves the AA - // information, but works slower - // - template - void sbool_unite_scanlines(const Scanline1& sl1, - const Scanline2& sl2, - Scanline& sl, - AddSpanFunctor1 add_span1, - AddSpanFunctor2 add_span2, - CombineSpansFunctor combine_spans) - { - sl.reset_spans(); - - unsigned num1 = sl1.num_spans(); - unsigned num2 = sl2.num_spans(); - - typename Scanline1::const_iterator span1;// = sl1.begin(); - typename Scanline2::const_iterator span2;// = sl2.begin(); - - enum invalidation_e - { - invalid_b = 0xFFFFFFF, - invalid_e = invalid_b - 1 - }; - - // Initialize the spans as invalid - //--------------- - int xb1 = invalid_b; - int xb2 = invalid_b; - int xe1 = invalid_e; - int xe2 = invalid_e; - - // Initialize span1 if there are spans - //--------------- - if(num1) - { - span1 = sl1.begin(); - xb1 = span1->x; - xe1 = xb1 + abs((int)span1->len) - 1; - --num1; - } - - // Initialize span2 if there are spans - //--------------- - if(num2) - { - span2 = sl2.begin(); - xb2 = span2->x; - xe2 = xb2 + abs((int)span2->len) - 1; - --num2; - } - - - for(;;) - { - // Retrieve a new span1 if it's invalid - //---------------- - if(num1 && xb1 > xe1) - { - --num1; - ++span1; - xb1 = span1->x; - xe1 = xb1 + abs((int)span1->len) - 1; - } - - // Retrieve a new span2 if it's invalid - //---------------- - if(num2 && xb2 > xe2) - { - --num2; - ++span2; - xb2 = span2->x; - xe2 = xb2 + abs((int)span2->len) - 1; - } - - if(xb1 > xe1 && xb2 > xe2) break; - - // Calculate the intersection - //---------------- - int xb = xb1; - int xe = xe1; - if(xb < xb2) xb = xb2; - if(xe > xe2) xe = xe2; - int len = xe - xb + 1; // The length of the intersection - if(len > 0) - { - // The spans intersect, - // add the beginning of the span - //---------------- - if(xb1 < xb2) - { - add_span1(span1, xb1, xb2 - xb1, sl); - xb1 = xb2; - } - else - if(xb2 < xb1) - { - add_span2(span2, xb2, xb1 - xb2, sl); - xb2 = xb1; - } - - // Add the combination part of the spans - //---------------- - combine_spans(span1, span2, xb, len, sl); - - - // Invalidate the fully processed span or both - //---------------- - if(xe1 < xe2) - { - // Invalidate span1 and eat - // the processed part of span2 - //-------------- - xb1 = invalid_b; - xe1 = invalid_e; - xb2 += len; - } - else - if(xe2 < xe1) - { - // Invalidate span2 and eat - // the processed part of span1 - //-------------- - xb2 = invalid_b; - xe2 = invalid_e; - xb1 += len; - } - else - { - xb1 = invalid_b; // Invalidate both - xb2 = invalid_b; - xe1 = invalid_e; - xe2 = invalid_e; - } - } - else - { - // The spans do not intersect - //-------------- - if(xb1 < xb2) - { - // Advance span1 - //--------------- - if(xb1 <= xe1) - { - add_span1(span1, xb1, xe1 - xb1 + 1, sl); - } - xb1 = invalid_b; // Invalidate - xe1 = invalid_e; - } - else - { - // Advance span2 - //--------------- - if(xb2 <= xe2) - { - add_span2(span2, xb2, xe2 - xb2 + 1, sl); - } - xb2 = invalid_b; // Invalidate - xe2 = invalid_e; - } - } - } - } - - - - - //----------------------------------------------------sbool_unite_shapes - // Unite the scanline shapes. Here the "Scanline Generator" - // abstraction is used. ScanlineGen1 and ScanlineGen2 are - // the generators, and can be of type rasterizer_scanline_aa<>. - // There function requires three scanline containers that can be - // of different type. - // "sl1" and "sl2" are used to retrieve scanlines from the generators, - // "sl" is ised as the resulting scanline to render it. - // The external "sl1" and "sl2" are used only for the sake of - // optimization and reusing of the scanline objects. - // the function calls sbool_unite_scanlines with CombineSpansFunctor - // as the last argument. See sbool_unite_scanlines for details. - //---------- - template - void sbool_unite_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren, - AddSpanFunctor1 add_span1, - AddSpanFunctor2 add_span2, - CombineSpansFunctor combine_spans) - { - // Prepare the scanline generators. - // If anyone of them doesn't contain - // any scanlines, then return. - //----------------- - bool flag1 = sg1.rewind_scanlines(); - bool flag2 = sg2.rewind_scanlines(); - if(!flag1 && !flag2) return; - - // Get the bounding boxes - //---------------- - rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y()); - rect_i r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y()); - - // Calculate the union of the bounding boxes - //----------------- - rect_i ur(1,1,0,0); - if(flag1 && flag2) ur = unite_rectangles(r1, r2); - else if(flag1) ur = r1; - else if(flag2) ur = r2; - - if(!ur.is_valid()) return; - - ren.prepare(); - - // Reset the scanlines and get two first ones - //----------------- - sl.reset(ur.x1, ur.x2); - if(flag1) - { - sl1.reset(sg1.min_x(), sg1.max_x()); - flag1 = sg1.sweep_scanline(sl1); - } - - if(flag2) - { - sl2.reset(sg2.min_x(), sg2.max_x()); - flag2 = sg2.sweep_scanline(sl2); - } - - // The main loop - // Here we synchronize the scanlines with - // the same Y coordinate. - //----------------- - while(flag1 || flag2) - { - if(flag1 && flag2) - { - if(sl1.y() == sl2.y()) - { - // The Y coordinates are the same. - // Combine the scanlines, render if they contain any spans, - // and advance both generators to the next scanlines - //---------------------- - sbool_unite_scanlines(sl1, sl2, sl, - add_span1, add_span2, combine_spans); - if(sl.num_spans()) - { - sl.finalize(sl1.y()); - ren.render(sl); - } - flag1 = sg1.sweep_scanline(sl1); - flag2 = sg2.sweep_scanline(sl2); - } - else - { - if(sl1.y() < sl2.y()) - { - sbool_add_spans_and_render(sl1, sl, ren, add_span1); - flag1 = sg1.sweep_scanline(sl1); - } - else - { - sbool_add_spans_and_render(sl2, sl, ren, add_span2); - flag2 = sg2.sweep_scanline(sl2); - } - } - } - else - { - if(flag1) - { - sbool_add_spans_and_render(sl1, sl, ren, add_span1); - flag1 = sg1.sweep_scanline(sl1); - } - if(flag2) - { - sbool_add_spans_and_render(sl2, sl, ren, add_span2); - flag2 = sg2.sweep_scanline(sl2); - } - } - } - } - - - - - - - - - //-------------------------------------------------sbool_subtract_shapes - // Subtract the scanline shapes, "sg1-sg2". Here the "Scanline Generator" - // abstraction is used. ScanlineGen1 and ScanlineGen2 are - // the generators, and can be of type rasterizer_scanline_aa<>. - // There function requires three scanline containers that can be of - // different types. - // "sl1" and "sl2" are used to retrieve scanlines from the generators, - // "sl" is ised as the resulting scanline to render it. - // The external "sl1" and "sl2" are used only for the sake of - // optimization and reusing of the scanline objects. - // the function calls sbool_intersect_scanlines with CombineSpansFunctor - // as the last argument. See combine_scanlines_sub for details. - //---------- - template - void sbool_subtract_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren, - AddSpanFunctor1 add_span1, - CombineSpansFunctor combine_spans) - { - // Prepare the scanline generators. - // Here "sg1" is master, "sg2" is slave. - //----------------- - if(!sg1.rewind_scanlines()) return; - bool flag2 = sg2.rewind_scanlines(); - - // Get the bounding box - //---------------- - rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y()); - - // Reset the scanlines and get two first ones - //----------------- - sl.reset(sg1.min_x(), sg1.max_x()); - sl1.reset(sg1.min_x(), sg1.max_x()); - sl2.reset(sg2.min_x(), sg2.max_x()); - if(!sg1.sweep_scanline(sl1)) return; - - if(flag2) flag2 = sg2.sweep_scanline(sl2); - - ren.prepare(); - - // A fake span2 processor - sbool_add_span_empty add_span2; - - // The main loop - // Here we synchronize the scanlines with - // the same Y coordinate, ignoring all other ones. - // Only scanlines having the same Y-coordinate - // are to be combined. - //----------------- - bool flag1 = true; - do - { - // Synchronize "slave" with "master" - //----------------- - while(flag2 && sl2.y() < sl1.y()) - { - flag2 = sg2.sweep_scanline(sl2); - } - - - if(flag2 && sl2.y() == sl1.y()) - { - // The Y coordinates are the same. - // Combine the scanlines and render if they contain any spans. - //---------------------- - sbool_unite_scanlines(sl1, sl2, sl, add_span1, add_span2, combine_spans); - if(sl.num_spans()) - { - sl.finalize(sl1.y()); - ren.render(sl); - } - } - else - { - sbool_add_spans_and_render(sl1, sl, ren, add_span1); - } - - // Advance the "master" - flag1 = sg1.sweep_scanline(sl1); - } - while(flag1); - } - - - - - - - - //---------------------------------------------sbool_intersect_shapes_aa - // Intersect two anti-aliased scanline shapes. - // Here the "Scanline Generator" abstraction is used. - // ScanlineGen1 and ScanlineGen2 are the generators, and can be of - // type rasterizer_scanline_aa<>. There function requires three - // scanline containers that can be of different types. - // "sl1" and "sl2" are used to retrieve scanlines from the generators, - // "sl" is ised as the resulting scanline to render it. - // The external "sl1" and "sl2" are used only for the sake of - // optimization and reusing of the scanline objects. - //---------- - template - void sbool_intersect_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_intersect_spans_aa combine_functor; - sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor); - } - - - - - - //--------------------------------------------sbool_intersect_shapes_bin - // Intersect two binary scanline shapes (without anti-aliasing). - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_intersect_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_combine_spans_bin combine_functor; - sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor); - } - - - - - - //-------------------------------------------------sbool_unite_shapes_aa - // Unite two anti-aliased scanline shapes - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_unite_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_add_span_aa add_functor1; - sbool_add_span_aa add_functor2; - sbool_unite_spans_aa combine_functor; - sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, - add_functor1, add_functor2, combine_functor); - } - - - - - - //------------------------------------------------sbool_unite_shapes_bin - // Unite two binary scanline shapes (without anti-aliasing). - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_unite_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_add_span_bin add_functor1; - sbool_add_span_bin add_functor2; - sbool_combine_spans_bin combine_functor; - sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, - add_functor1, add_functor2, combine_functor); - } - - - - - - - - - - //---------------------------------------------------sbool_xor_shapes_aa - // Apply eXclusive OR to two anti-aliased scanline shapes. There's - // a modified "Linear" XOR used instead of classical "Saddle" one. - // The reason is to have the result absolutely conststent with what - // the scanline rasterizer produces. - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_xor_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_add_span_aa add_functor1; - sbool_add_span_aa add_functor2; - sbool_xor_spans_aa > combine_functor; - sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, - add_functor1, add_functor2, combine_functor); - } - - - - //------------------------------------------sbool_xor_shapes_saddle_aa - // Apply eXclusive OR to two anti-aliased scanline shapes. - // There's the classical "Saddle" used to calculate the - // Anti-Aliasing values, that is: - // a XOR b : 1-((1-a+a*b)*(1-b+a*b)) - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_xor_shapes_saddle_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_add_span_aa add_functor1; - sbool_add_span_aa add_functor2; - sbool_xor_spans_aa > combine_functor; - sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, - add_functor1, add_functor2, combine_functor); - } - - - //--------------------------------------sbool_xor_shapes_abs_diff_aa - // Apply eXclusive OR to two anti-aliased scanline shapes. - // There's the absolute difference used to calculate - // Anti-Aliasing values, that is: - // a XOR b : abs(a-b) - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_xor_shapes_abs_diff_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_add_span_aa add_functor1; - sbool_add_span_aa add_functor2; - sbool_xor_spans_aa combine_functor; - sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, - add_functor1, add_functor2, combine_functor); - } - - - - //--------------------------------------------------sbool_xor_shapes_bin - // Apply eXclusive OR to two binary scanline shapes (without anti-aliasing). - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_xor_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_add_span_bin add_functor1; - sbool_add_span_bin add_functor2; - sbool_combine_spans_empty combine_functor; - sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, - add_functor1, add_functor2, combine_functor); - } - - - - - - - //----------------------------------------------sbool_subtract_shapes_aa - // Subtract shapes "sg1-sg2" with anti-aliasing - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_subtract_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_add_span_aa add_functor; - sbool_subtract_spans_aa combine_functor; - sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren, - add_functor, combine_functor); - } - - - - - - //---------------------------------------------sbool_subtract_shapes_bin - // Subtract binary shapes "sg1-sg2" without anti-aliasing - // See intersect_shapes_aa for more comments - //---------- - template - void sbool_subtract_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - sbool_add_span_bin add_functor; - sbool_combine_spans_empty combine_functor; - sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren, - add_functor, combine_functor); - } - - - - - - - //------------------------------------------------------------sbool_op_e - enum sbool_op_e - { - sbool_or, //----sbool_or - sbool_and, //----sbool_and - sbool_xor, //----sbool_xor - sbool_xor_saddle, //----sbool_xor_saddle - sbool_xor_abs_diff, //----sbool_xor_abs_diff - sbool_a_minus_b, //----sbool_a_minus_b - sbool_b_minus_a //----sbool_b_minus_a - }; - - - - - - - //----------------------------------------------sbool_combine_shapes_bin - template - void sbool_combine_shapes_bin(sbool_op_e op, - ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - switch(op) - { - case sbool_or : sbool_unite_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_and : sbool_intersect_shapes_bin(sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_xor : - case sbool_xor_saddle : - case sbool_xor_abs_diff: sbool_xor_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_a_minus_b : sbool_subtract_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_b_minus_a : sbool_subtract_shapes_bin (sg2, sg1, sl2, sl1, sl, ren); break; - } - } - - - - - //-----------------------------------------------sbool_combine_shapes_aa - template - void sbool_combine_shapes_aa(sbool_op_e op, - ScanlineGen1& sg1, ScanlineGen2& sg2, - Scanline1& sl1, Scanline2& sl2, - Scanline& sl, Renderer& ren) - { - switch(op) - { - case sbool_or : sbool_unite_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_and : sbool_intersect_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_xor : sbool_xor_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_xor_saddle : sbool_xor_shapes_saddle_aa (sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_xor_abs_diff: sbool_xor_shapes_abs_diff_aa(sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_a_minus_b : sbool_subtract_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break; - case sbool_b_minus_a : sbool_subtract_shapes_aa (sg2, sg1, sl2, sl1, sl, ren); break; - } - } - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_scanline_p.h corsix-th-0.62/agg/include/agg_scanline_p.h --- corsix-th-0.30/agg/include/agg_scanline_p.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_scanline_p.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,329 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Class scanline_p - a general purpose scanline container with packed spans. -// -//---------------------------------------------------------------------------- -// -// Adaptation for 32-bit screen coordinates (scanline32_p) has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -#ifndef AGG_SCANLINE_P_INCLUDED -#define AGG_SCANLINE_P_INCLUDED - -#include "agg_array.h" - -namespace agg -{ - - //=============================================================scanline_p8 - // - // This is a general purpose scaline container which supports the interface - // used in the rasterizer::render(). See description of scanline_u8 - // for details. - // - //------------------------------------------------------------------------ - class scanline_p8 - { - public: - typedef scanline_p8 self_type; - typedef int8u cover_type; - typedef int16 coord_type; - - //-------------------------------------------------------------------- - struct span - { - coord_type x; - coord_type len; // If negative, it's a solid span, covers is valid - const cover_type* covers; - }; - - typedef span* iterator; - typedef const span* const_iterator; - - scanline_p8() : - m_last_x(0x7FFFFFF0), - m_covers(), - m_cover_ptr(0), - m_spans(), - m_cur_span(0) - { - } - - //-------------------------------------------------------------------- - void reset(int min_x, int max_x) - { - unsigned max_len = max_x - min_x + 3; - if(max_len > m_spans.size()) - { - m_spans.resize(max_len); - m_covers.resize(max_len); - } - m_last_x = 0x7FFFFFF0; - m_cover_ptr = &m_covers[0]; - m_cur_span = &m_spans[0]; - m_cur_span->len = 0; - } - - //-------------------------------------------------------------------- - void add_cell(int x, unsigned cover) - { - *m_cover_ptr = (cover_type)cover; - if(x == m_last_x+1 && m_cur_span->len > 0) - { - m_cur_span->len++; - } - else - { - m_cur_span++; - m_cur_span->covers = m_cover_ptr; - m_cur_span->x = (int16)x; - m_cur_span->len = 1; - } - m_last_x = x; - m_cover_ptr++; - } - - //-------------------------------------------------------------------- - void add_cells(int x, unsigned len, const cover_type* covers) - { - memcpy(m_cover_ptr, covers, len * sizeof(cover_type)); - if(x == m_last_x+1 && m_cur_span->len > 0) - { - m_cur_span->len += (int16)len; - } - else - { - m_cur_span++; - m_cur_span->covers = m_cover_ptr; - m_cur_span->x = (int16)x; - m_cur_span->len = (int16)len; - } - m_cover_ptr += len; - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void add_span(int x, unsigned len, unsigned cover) - { - if(x == m_last_x+1 && - m_cur_span->len < 0 && - cover == *m_cur_span->covers) - { - m_cur_span->len -= (int16)len; - } - else - { - *m_cover_ptr = (cover_type)cover; - m_cur_span++; - m_cur_span->covers = m_cover_ptr++; - m_cur_span->x = (int16)x; - m_cur_span->len = (int16)(-int(len)); - } - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void finalize(int y) - { - m_y = y; - } - - //-------------------------------------------------------------------- - void reset_spans() - { - m_last_x = 0x7FFFFFF0; - m_cover_ptr = &m_covers[0]; - m_cur_span = &m_spans[0]; - m_cur_span->len = 0; - } - - //-------------------------------------------------------------------- - int y() const { return m_y; } - unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } - const_iterator begin() const { return &m_spans[1]; } - - private: - scanline_p8(const self_type&); - const self_type& operator = (const self_type&); - - int m_last_x; - int m_y; - pod_array m_covers; - cover_type* m_cover_ptr; - pod_array m_spans; - span* m_cur_span; - }; - - - - - - - - - //==========================================================scanline32_p8 - class scanline32_p8 - { - public: - typedef scanline32_p8 self_type; - typedef int8u cover_type; - typedef int32 coord_type; - - struct span - { - span() {} - span(coord_type x_, coord_type len_, const cover_type* covers_) : - x(x_), len(len_), covers(covers_) {} - - coord_type x; - coord_type len; // If negative, it's a solid span, covers is valid - const cover_type* covers; - }; - typedef pod_bvector span_array_type; - - - //-------------------------------------------------------------------- - class const_iterator - { - public: - const_iterator(const span_array_type& spans) : - m_spans(spans), - m_span_idx(0) - {} - - const span& operator*() const { return m_spans[m_span_idx]; } - const span* operator->() const { return &m_spans[m_span_idx]; } - - void operator ++ () { ++m_span_idx; } - - private: - const span_array_type& m_spans; - unsigned m_span_idx; - }; - - //-------------------------------------------------------------------- - scanline32_p8() : - m_max_len(0), - m_last_x(0x7FFFFFF0), - m_covers(), - m_cover_ptr(0) - { - } - - //-------------------------------------------------------------------- - void reset(int min_x, int max_x) - { - unsigned max_len = max_x - min_x + 3; - if(max_len > m_covers.size()) - { - m_covers.resize(max_len); - } - m_last_x = 0x7FFFFFF0; - m_cover_ptr = &m_covers[0]; - m_spans.remove_all(); - } - - //-------------------------------------------------------------------- - void add_cell(int x, unsigned cover) - { - *m_cover_ptr = cover_type(cover); - if(x == m_last_x+1 && m_spans.size() && m_spans.last().len > 0) - { - m_spans.last().len++; - } - else - { - m_spans.add(span(coord_type(x), 1, m_cover_ptr)); - } - m_last_x = x; - m_cover_ptr++; - } - - //-------------------------------------------------------------------- - void add_cells(int x, unsigned len, const cover_type* covers) - { - memcpy(m_cover_ptr, covers, len * sizeof(cover_type)); - if(x == m_last_x+1 && m_spans.size() && m_spans.last().len > 0) - { - m_spans.last().len += coord_type(len); - } - else - { - m_spans.add(span(coord_type(x), coord_type(len), m_cover_ptr)); - } - m_cover_ptr += len; - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void add_span(int x, unsigned len, unsigned cover) - { - if(x == m_last_x+1 && - m_spans.size() && - m_spans.last().len < 0 && - cover == *m_spans.last().covers) - { - m_spans.last().len -= coord_type(len); - } - else - { - *m_cover_ptr = cover_type(cover); - m_spans.add(span(coord_type(x), -coord_type(len), m_cover_ptr++)); - } - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void finalize(int y) - { - m_y = y; - } - - //-------------------------------------------------------------------- - void reset_spans() - { - m_last_x = 0x7FFFFFF0; - m_cover_ptr = &m_covers[0]; - m_spans.remove_all(); - } - - //-------------------------------------------------------------------- - int y() const { return m_y; } - unsigned num_spans() const { return m_spans.size(); } - const_iterator begin() const { return const_iterator(m_spans); } - - private: - scanline32_p8(const self_type&); - const self_type& operator = (const self_type&); - - unsigned m_max_len; - int m_last_x; - int m_y; - pod_array m_covers; - cover_type* m_cover_ptr; - span_array_type m_spans; - }; - - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_scanline_storage_aa.h corsix-th-0.62/agg/include/agg_scanline_storage_aa.h --- corsix-th-0.30/agg/include/agg_scanline_storage_aa.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_scanline_storage_aa.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,815 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for 32-bit screen coordinates has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_SCANLINE_STORAGE_AA_INCLUDED -#define AGG_SCANLINE_STORAGE_AA_INCLUDED - -#include -#include -#include -#include "agg_array.h" - - -namespace agg -{ - - //----------------------------------------------scanline_cell_storage - template class scanline_cell_storage - { - struct extra_span - { - unsigned len; - T* ptr; - }; - - public: - typedef T value_type; - - //--------------------------------------------------------------- - ~scanline_cell_storage() - { - remove_all(); - } - - //--------------------------------------------------------------- - scanline_cell_storage() : - m_cells(128-2), - m_extra_storage() - {} - - - // Copying - //--------------------------------------------------------------- - scanline_cell_storage(const scanline_cell_storage& v) : - m_cells(v.m_cells), - m_extra_storage() - { - copy_extra_storage(v); - } - - //--------------------------------------------------------------- - const scanline_cell_storage& - operator = (const scanline_cell_storage& v) - { - remove_all(); - m_cells = v.m_cells; - copy_extra_storage(v); - return *this; - } - - //--------------------------------------------------------------- - void remove_all() - { - int i; - for(i = m_extra_storage.size()-1; i >= 0; --i) - { - pod_allocator::deallocate(m_extra_storage[i].ptr, - m_extra_storage[i].len); - } - m_extra_storage.remove_all(); - m_cells.remove_all(); - } - - //--------------------------------------------------------------- - int add_cells(const T* cells, unsigned num_cells) - { - int idx = m_cells.allocate_continuous_block(num_cells); - if(idx >= 0) - { - T* ptr = &m_cells[idx]; - memcpy(ptr, cells, sizeof(T) * num_cells); - return idx; - } - extra_span s; - s.len = num_cells; - s.ptr = pod_allocator::allocate(num_cells); - memcpy(s.ptr, cells, sizeof(T) * num_cells); - m_extra_storage.add(s); - return -int(m_extra_storage.size()); - } - - //--------------------------------------------------------------- - const T* operator [] (int idx) const - { - if(idx >= 0) - { - if((unsigned)idx >= m_cells.size()) return 0; - return &m_cells[(unsigned)idx]; - } - unsigned i = unsigned(-idx - 1); - if(i >= m_extra_storage.size()) return 0; - return m_extra_storage[i].ptr; - } - - //--------------------------------------------------------------- - T* operator [] (int idx) - { - if(idx >= 0) - { - if((unsigned)idx >= m_cells.size()) return 0; - return &m_cells[(unsigned)idx]; - } - unsigned i = unsigned(-idx - 1); - if(i >= m_extra_storage.size()) return 0; - return m_extra_storage[i].ptr; - } - - private: - void copy_extra_storage(const scanline_cell_storage& v) - { - unsigned i; - for(i = 0; i < v.m_extra_storage.size(); ++i) - { - const extra_span& src = v.m_extra_storage[i]; - extra_span dst; - dst.len = src.len; - dst.ptr = pod_allocator::allocate(dst.len); - memcpy(dst.ptr, src.ptr, dst.len * sizeof(T)); - m_extra_storage.add(dst); - } - } - - pod_bvector m_cells; - pod_bvector m_extra_storage; - }; - - - - - - - //-----------------------------------------------scanline_storage_aa - template class scanline_storage_aa - { - public: - typedef T cover_type; - - //--------------------------------------------------------------- - struct span_data - { - int32 x; - int32 len; // If negative, it's a solid span, covers is valid - int covers_id; // The index of the cells in the scanline_cell_storage - }; - - //--------------------------------------------------------------- - struct scanline_data - { - int y; - unsigned num_spans; - unsigned start_span; - }; - - - //--------------------------------------------------------------- - class embedded_scanline - { - public: - - //----------------------------------------------------------- - class const_iterator - { - public: - struct span - { - int32 x; - int32 len; // If negative, it's a solid span, covers is valid - const T* covers; - }; - - const_iterator() : m_storage(0) {} - const_iterator(const embedded_scanline& sl) : - m_storage(sl.m_storage), - m_span_idx(sl.m_scanline.start_span) - { - init_span(); - } - - const span& operator*() const { return m_span; } - const span* operator->() const { return &m_span; } - - void operator ++ () - { - ++m_span_idx; - init_span(); - } - - private: - void init_span() - { - const span_data& s = m_storage->span_by_index(m_span_idx); - m_span.x = s.x; - m_span.len = s.len; - m_span.covers = m_storage->covers_by_index(s.covers_id); - } - - const scanline_storage_aa* m_storage; - unsigned m_span_idx; - span m_span; - }; - - friend class const_iterator; - - - //----------------------------------------------------------- - embedded_scanline(const scanline_storage_aa& storage) : - m_storage(&storage) - { - init(0); - } - - //----------------------------------------------------------- - void reset(int, int) {} - unsigned num_spans() const { return m_scanline.num_spans; } - int y() const { return m_scanline.y; } - const_iterator begin() const { return const_iterator(*this); } - - //----------------------------------------------------------- - void init(unsigned scanline_idx) - { - m_scanline_idx = scanline_idx; - m_scanline = m_storage->scanline_by_index(m_scanline_idx); - } - - private: - const scanline_storage_aa* m_storage; - scanline_data m_scanline; - unsigned m_scanline_idx; - }; - - - //--------------------------------------------------------------- - scanline_storage_aa() : - m_covers(), - m_spans(256-2), // Block increment size - m_scanlines(), - m_min_x( 0x7FFFFFFF), - m_min_y( 0x7FFFFFFF), - m_max_x(-0x7FFFFFFF), - m_max_y(-0x7FFFFFFF), - m_cur_scanline(0) - { - m_fake_scanline.y = 0; - m_fake_scanline.num_spans = 0; - m_fake_scanline.start_span = 0; - m_fake_span.x = 0; - m_fake_span.len = 0; - m_fake_span.covers_id = 0; - } - - // Renderer Interface - //--------------------------------------------------------------- - void prepare() - { - m_covers.remove_all(); - m_scanlines.remove_all(); - m_spans.remove_all(); - m_min_x = 0x7FFFFFFF; - m_min_y = 0x7FFFFFFF; - m_max_x = -0x7FFFFFFF; - m_max_y = -0x7FFFFFFF; - m_cur_scanline = 0; - } - - //--------------------------------------------------------------- - template void render(const Scanline& sl) - { - scanline_data sl_this; - - int y = sl.y(); - if(y < m_min_y) m_min_y = y; - if(y > m_max_y) m_max_y = y; - - sl_this.y = y; - sl_this.num_spans = sl.num_spans(); - sl_this.start_span = m_spans.size(); - typename Scanline::const_iterator span_iterator = sl.begin(); - - unsigned num_spans = sl_this.num_spans; - for(;;) - { - span_data sp; - - sp.x = span_iterator->x; - sp.len = span_iterator->len; - int len = abs(int(sp.len)); - sp.covers_id = - m_covers.add_cells(span_iterator->covers, - unsigned(len)); - m_spans.add(sp); - int x1 = sp.x; - int x2 = sp.x + len - 1; - if(x1 < m_min_x) m_min_x = x1; - if(x2 > m_max_x) m_max_x = x2; - if(--num_spans == 0) break; - ++span_iterator; - } - m_scanlines.add(sl_this); - } - - - //--------------------------------------------------------------- - // Iterate scanlines interface - int min_x() const { return m_min_x; } - int min_y() const { return m_min_y; } - int max_x() const { return m_max_x; } - int max_y() const { return m_max_y; } - - //--------------------------------------------------------------- - bool rewind_scanlines() - { - m_cur_scanline = 0; - return m_scanlines.size() > 0; - } - - - //--------------------------------------------------------------- - template bool sweep_scanline(Scanline& sl) - { - sl.reset_spans(); - for(;;) - { - if(m_cur_scanline >= m_scanlines.size()) return false; - const scanline_data& sl_this = m_scanlines[m_cur_scanline]; - - unsigned num_spans = sl_this.num_spans; - unsigned span_idx = sl_this.start_span; - do - { - const span_data& sp = m_spans[span_idx++]; - const T* covers = covers_by_index(sp.covers_id); - if(sp.len < 0) - { - sl.add_span(sp.x, unsigned(-sp.len), *covers); - } - else - { - sl.add_cells(sp.x, sp.len, covers); - } - } - while(--num_spans); - ++m_cur_scanline; - if(sl.num_spans()) - { - sl.finalize(sl_this.y); - break; - } - } - return true; - } - - - //--------------------------------------------------------------- - // Specialization for embedded_scanline - bool sweep_scanline(embedded_scanline& sl) - { - do - { - if(m_cur_scanline >= m_scanlines.size()) return false; - sl.init(m_cur_scanline); - ++m_cur_scanline; - } - while(sl.num_spans() == 0); - return true; - } - - //--------------------------------------------------------------- - unsigned byte_size() const - { - unsigned i; - unsigned size = sizeof(int32) * 4; // min_x, min_y, max_x, max_y - - for(i = 0; i < m_scanlines.size(); ++i) - { - size += sizeof(int32) * 3; // scanline size in bytes, Y, num_spans - - const scanline_data& sl_this = m_scanlines[i]; - - unsigned num_spans = sl_this.num_spans; - unsigned span_idx = sl_this.start_span; - do - { - const span_data& sp = m_spans[span_idx++]; - - size += sizeof(int32) * 2; // X, span_len - if(sp.len < 0) - { - size += sizeof(T); // cover - } - else - { - size += sizeof(T) * unsigned(sp.len); // covers - } - } - while(--num_spans); - } - return size; - } - - - //--------------------------------------------------------------- - static void write_int32(int8u* dst, int32 val) - { - dst[0] = ((const int8u*)&val)[0]; - dst[1] = ((const int8u*)&val)[1]; - dst[2] = ((const int8u*)&val)[2]; - dst[3] = ((const int8u*)&val)[3]; - } - - - //--------------------------------------------------------------- - void serialize(int8u* data) const - { - unsigned i; - - write_int32(data, min_x()); // min_x - data += sizeof(int32); - write_int32(data, min_y()); // min_y - data += sizeof(int32); - write_int32(data, max_x()); // max_x - data += sizeof(int32); - write_int32(data, max_y()); // max_y - data += sizeof(int32); - - for(i = 0; i < m_scanlines.size(); ++i) - { - const scanline_data& sl_this = m_scanlines[i]; - - int8u* size_ptr = data; - data += sizeof(int32); // Reserve space for scanline size in bytes - - write_int32(data, sl_this.y); // Y - data += sizeof(int32); - - write_int32(data, sl_this.num_spans); // num_spans - data += sizeof(int32); - - unsigned num_spans = sl_this.num_spans; - unsigned span_idx = sl_this.start_span; - do - { - const span_data& sp = m_spans[span_idx++]; - const T* covers = covers_by_index(sp.covers_id); - - write_int32(data, sp.x); // X - data += sizeof(int32); - - write_int32(data, sp.len); // span_len - data += sizeof(int32); - - if(sp.len < 0) - { - memcpy(data, covers, sizeof(T)); - data += sizeof(T); - } - else - { - memcpy(data, covers, unsigned(sp.len) * sizeof(T)); - data += sizeof(T) * unsigned(sp.len); - } - } - while(--num_spans); - write_int32(size_ptr, int32(unsigned(data - size_ptr))); - } - } - - - //--------------------------------------------------------------- - const scanline_data& scanline_by_index(unsigned i) const - { - return (i < m_scanlines.size()) ? m_scanlines[i] : m_fake_scanline; - } - - //--------------------------------------------------------------- - const span_data& span_by_index(unsigned i) const - { - return (i < m_spans.size()) ? m_spans[i] : m_fake_span; - } - - //--------------------------------------------------------------- - const T* covers_by_index(int i) const - { - return m_covers[i]; - } - - private: - scanline_cell_storage m_covers; - pod_bvector m_spans; - pod_bvector m_scanlines; - span_data m_fake_span; - scanline_data m_fake_scanline; - int m_min_x; - int m_min_y; - int m_max_x; - int m_max_y; - unsigned m_cur_scanline; - }; - - - typedef scanline_storage_aa scanline_storage_aa8; //--------scanline_storage_aa8 - typedef scanline_storage_aa scanline_storage_aa16; //--------scanline_storage_aa16 - typedef scanline_storage_aa scanline_storage_aa32; //--------scanline_storage_aa32 - - - - - //------------------------------------------serialized_scanlines_adaptor_aa - template class serialized_scanlines_adaptor_aa - { - public: - typedef T cover_type; - - //--------------------------------------------------------------------- - class embedded_scanline - { - public: - typedef T cover_type; - - //----------------------------------------------------------------- - class const_iterator - { - public: - struct span - { - int32 x; - int32 len; // If negative, it's a solid span, "covers" is valid - const T* covers; - }; - - const_iterator() : m_ptr(0) {} - const_iterator(const embedded_scanline& sl) : - m_ptr(sl.m_ptr), - m_dx(sl.m_dx) - { - init_span(); - } - - const span& operator*() const { return m_span; } - const span* operator->() const { return &m_span; } - - void operator ++ () - { - if(m_span.len < 0) - { - m_ptr += sizeof(T); - } - else - { - m_ptr += m_span.len * sizeof(T); - } - init_span(); - } - - private: - int read_int32() - { - int32 val; - ((int8u*)&val)[0] = *m_ptr++; - ((int8u*)&val)[1] = *m_ptr++; - ((int8u*)&val)[2] = *m_ptr++; - ((int8u*)&val)[3] = *m_ptr++; - return val; - } - - void init_span() - { - m_span.x = read_int32() + m_dx; - m_span.len = read_int32(); - m_span.covers = m_ptr; - } - - const int8u* m_ptr; - span m_span; - int m_dx; - }; - - friend class const_iterator; - - - //----------------------------------------------------------------- - embedded_scanline() : m_ptr(0), m_y(0), m_num_spans(0) {} - - //----------------------------------------------------------------- - void reset(int, int) {} - unsigned num_spans() const { return m_num_spans; } - int y() const { return m_y; } - const_iterator begin() const { return const_iterator(*this); } - - - private: - //----------------------------------------------------------------- - int read_int32() - { - int32 val; - ((int8u*)&val)[0] = *m_ptr++; - ((int8u*)&val)[1] = *m_ptr++; - ((int8u*)&val)[2] = *m_ptr++; - ((int8u*)&val)[3] = *m_ptr++; - return val; - } - - public: - //----------------------------------------------------------------- - void init(const int8u* ptr, int dx, int dy) - { - m_ptr = ptr; - m_y = read_int32() + dy; - m_num_spans = unsigned(read_int32()); - m_dx = dx; - } - - private: - const int8u* m_ptr; - int m_y; - unsigned m_num_spans; - int m_dx; - }; - - - - public: - //-------------------------------------------------------------------- - serialized_scanlines_adaptor_aa() : - m_data(0), - m_end(0), - m_ptr(0), - m_dx(0), - m_dy(0), - m_min_x(0x7FFFFFFF), - m_min_y(0x7FFFFFFF), - m_max_x(-0x7FFFFFFF), - m_max_y(-0x7FFFFFFF) - {} - - //-------------------------------------------------------------------- - serialized_scanlines_adaptor_aa(const int8u* data, unsigned size, - double dx, double dy) : - m_data(data), - m_end(data + size), - m_ptr(data), - m_dx(iround(dx)), - m_dy(iround(dy)), - m_min_x(0x7FFFFFFF), - m_min_y(0x7FFFFFFF), - m_max_x(-0x7FFFFFFF), - m_max_y(-0x7FFFFFFF) - {} - - //-------------------------------------------------------------------- - void init(const int8u* data, unsigned size, double dx, double dy) - { - m_data = data; - m_end = data + size; - m_ptr = data; - m_dx = iround(dx); - m_dy = iround(dy); - m_min_x = 0x7FFFFFFF; - m_min_y = 0x7FFFFFFF; - m_max_x = -0x7FFFFFFF; - m_max_y = -0x7FFFFFFF; - } - - private: - //-------------------------------------------------------------------- - int read_int32() - { - int32 val; - ((int8u*)&val)[0] = *m_ptr++; - ((int8u*)&val)[1] = *m_ptr++; - ((int8u*)&val)[2] = *m_ptr++; - ((int8u*)&val)[3] = *m_ptr++; - return val; - } - - //-------------------------------------------------------------------- - unsigned read_int32u() - { - int32u val; - ((int8u*)&val)[0] = *m_ptr++; - ((int8u*)&val)[1] = *m_ptr++; - ((int8u*)&val)[2] = *m_ptr++; - ((int8u*)&val)[3] = *m_ptr++; - return val; - } - - public: - // Iterate scanlines interface - //-------------------------------------------------------------------- - bool rewind_scanlines() - { - m_ptr = m_data; - if(m_ptr < m_end) - { - m_min_x = read_int32() + m_dx; - m_min_y = read_int32() + m_dy; - m_max_x = read_int32() + m_dx; - m_max_y = read_int32() + m_dy; - } - return m_ptr < m_end; - } - - //-------------------------------------------------------------------- - int min_x() const { return m_min_x; } - int min_y() const { return m_min_y; } - int max_x() const { return m_max_x; } - int max_y() const { return m_max_y; } - - //-------------------------------------------------------------------- - template bool sweep_scanline(Scanline& sl) - { - sl.reset_spans(); - for(;;) - { - if(m_ptr >= m_end) return false; - - read_int32(); // Skip scanline size in bytes - int y = read_int32() + m_dy; - unsigned num_spans = read_int32(); - - do - { - int x = read_int32() + m_dx; - int len = read_int32(); - - if(len < 0) - { - sl.add_span(x, unsigned(-len), *m_ptr); - m_ptr += sizeof(T); - } - else - { - sl.add_cells(x, len, m_ptr); - m_ptr += len * sizeof(T); - } - } - while(--num_spans); - - if(sl.num_spans()) - { - sl.finalize(y); - break; - } - } - return true; - } - - - //-------------------------------------------------------------------- - // Specialization for embedded_scanline - bool sweep_scanline(embedded_scanline& sl) - { - do - { - if(m_ptr >= m_end) return false; - - unsigned byte_size = read_int32u(); - sl.init(m_ptr, m_dx, m_dy); - m_ptr += byte_size - sizeof(int32); - } - while(sl.num_spans() == 0); - return true; - } - - private: - const int8u* m_data; - const int8u* m_end; - const int8u* m_ptr; - int m_dx; - int m_dy; - int m_min_x; - int m_min_y; - int m_max_x; - int m_max_y; - }; - - - - typedef serialized_scanlines_adaptor_aa serialized_scanlines_adaptor_aa8; //----serialized_scanlines_adaptor_aa8 - typedef serialized_scanlines_adaptor_aa serialized_scanlines_adaptor_aa16; //----serialized_scanlines_adaptor_aa16 - typedef serialized_scanlines_adaptor_aa serialized_scanlines_adaptor_aa32; //----serialized_scanlines_adaptor_aa32 - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_scanline_storage_bin.h corsix-th-0.62/agg/include/agg_scanline_storage_bin.h --- corsix-th-0.30/agg/include/agg_scanline_storage_bin.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_scanline_storage_bin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,586 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for 32-bit screen coordinates has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - - -#ifndef AGG_SCANLINE_STORAGE_BIN_INCLUDED -#define AGG_SCANLINE_STORAGE_BIN_INCLUDED - -#include -#include -#include -#include "agg_array.h" - - -namespace agg -{ - - //-----------------------------------------------scanline_storage_bin - class scanline_storage_bin - { - public: - //--------------------------------------------------------------- - struct span_data - { - int32 x; - int32 len; - }; - - //--------------------------------------------------------------- - struct scanline_data - { - int y; - unsigned num_spans; - unsigned start_span; - }; - - - //--------------------------------------------------------------- - class embedded_scanline - { - public: - - //----------------------------------------------------------- - class const_iterator - { - public: - const_iterator() : m_storage(0) {} - const_iterator(const embedded_scanline& sl) : - m_storage(sl.m_storage), - m_span_idx(sl.m_scanline.start_span) - { - m_span = m_storage->span_by_index(m_span_idx); - } - - const span_data& operator*() const { return m_span; } - const span_data* operator->() const { return &m_span; } - - void operator ++ () - { - ++m_span_idx; - m_span = m_storage->span_by_index(m_span_idx); - } - - private: - const scanline_storage_bin* m_storage; - unsigned m_span_idx; - span_data m_span; - }; - - friend class const_iterator; - - - //----------------------------------------------------------- - embedded_scanline(const scanline_storage_bin& storage) : - m_storage(&storage) - { - setup(0); - } - - //----------------------------------------------------------- - void reset(int, int) {} - unsigned num_spans() const { return m_scanline.num_spans; } - int y() const { return m_scanline.y; } - const_iterator begin() const { return const_iterator(*this); } - - //----------------------------------------------------------- - void setup(unsigned scanline_idx) - { - m_scanline_idx = scanline_idx; - m_scanline = m_storage->scanline_by_index(m_scanline_idx); - } - - private: - const scanline_storage_bin* m_storage; - scanline_data m_scanline; - unsigned m_scanline_idx; - }; - - - //--------------------------------------------------------------- - scanline_storage_bin() : - m_spans(256-2), // Block increment size - m_scanlines(), - m_min_x( 0x7FFFFFFF), - m_min_y( 0x7FFFFFFF), - m_max_x(-0x7FFFFFFF), - m_max_y(-0x7FFFFFFF), - m_cur_scanline(0) - { - m_fake_scanline.y = 0; - m_fake_scanline.num_spans = 0; - m_fake_scanline.start_span = 0; - m_fake_span.x = 0; - m_fake_span.len = 0; - } - - // Renderer Interface - //--------------------------------------------------------------- - void prepare() - { - m_scanlines.remove_all(); - m_spans.remove_all(); - m_min_x = 0x7FFFFFFF; - m_min_y = 0x7FFFFFFF; - m_max_x = -0x7FFFFFFF; - m_max_y = -0x7FFFFFFF; - m_cur_scanline = 0; - } - - //--------------------------------------------------------------- - template void render(const Scanline& sl) - { - scanline_data sl_this; - - int y = sl.y(); - if(y < m_min_y) m_min_y = y; - if(y > m_max_y) m_max_y = y; - - sl_this.y = y; - sl_this.num_spans = sl.num_spans(); - sl_this.start_span = m_spans.size(); - typename Scanline::const_iterator span_iterator = sl.begin(); - - unsigned num_spans = sl_this.num_spans; - for(;;) - { - span_data sp; - sp.x = span_iterator->x; - sp.len = (int32)abs((int)(span_iterator->len)); - m_spans.add(sp); - int x1 = sp.x; - int x2 = sp.x + sp.len - 1; - if(x1 < m_min_x) m_min_x = x1; - if(x2 > m_max_x) m_max_x = x2; - if(--num_spans == 0) break; - ++span_iterator; - } - m_scanlines.add(sl_this); - } - - - //--------------------------------------------------------------- - // Iterate scanlines interface - int min_x() const { return m_min_x; } - int min_y() const { return m_min_y; } - int max_x() const { return m_max_x; } - int max_y() const { return m_max_y; } - - //--------------------------------------------------------------- - bool rewind_scanlines() - { - m_cur_scanline = 0; - return m_scanlines.size() > 0; - } - - - //--------------------------------------------------------------- - template bool sweep_scanline(Scanline& sl) - { - sl.reset_spans(); - for(;;) - { - if(m_cur_scanline >= m_scanlines.size()) return false; - const scanline_data& sl_this = m_scanlines[m_cur_scanline]; - - unsigned num_spans = sl_this.num_spans; - unsigned span_idx = sl_this.start_span; - do - { - const span_data& sp = m_spans[span_idx++]; - sl.add_span(sp.x, sp.len, cover_full); - } - while(--num_spans); - - ++m_cur_scanline; - if(sl.num_spans()) - { - sl.finalize(sl_this.y); - break; - } - } - return true; - } - - - //--------------------------------------------------------------- - // Specialization for embedded_scanline - bool sweep_scanline(embedded_scanline& sl) - { - do - { - if(m_cur_scanline >= m_scanlines.size()) return false; - sl.setup(m_cur_scanline); - ++m_cur_scanline; - } - while(sl.num_spans() == 0); - return true; - } - - - //--------------------------------------------------------------- - unsigned byte_size() const - { - unsigned i; - unsigned size = sizeof(int32) * 4; // min_x, min_y, max_x, max_y - - for(i = 0; i < m_scanlines.size(); ++i) - { - size += sizeof(int32) * 2 + // Y, num_spans - unsigned(m_scanlines[i].num_spans) * sizeof(int32) * 2; // X, span_len - } - return size; - } - - - //--------------------------------------------------------------- - static void write_int32(int8u* dst, int32 val) - { - dst[0] = ((const int8u*)&val)[0]; - dst[1] = ((const int8u*)&val)[1]; - dst[2] = ((const int8u*)&val)[2]; - dst[3] = ((const int8u*)&val)[3]; - } - - - //--------------------------------------------------------------- - void serialize(int8u* data) const - { - unsigned i; - - write_int32(data, min_x()); // min_x - data += sizeof(int32); - write_int32(data, min_y()); // min_y - data += sizeof(int32); - write_int32(data, max_x()); // max_x - data += sizeof(int32); - write_int32(data, max_y()); // max_y - data += sizeof(int32); - - for(i = 0; i < m_scanlines.size(); ++i) - { - const scanline_data& sl_this = m_scanlines[i]; - - write_int32(data, sl_this.y); // Y - data += sizeof(int32); - - write_int32(data, sl_this.num_spans); // num_spans - data += sizeof(int32); - - unsigned num_spans = sl_this.num_spans; - unsigned span_idx = sl_this.start_span; - do - { - const span_data& sp = m_spans[span_idx++]; - - write_int32(data, sp.x); // X - data += sizeof(int32); - - write_int32(data, sp.len); // len - data += sizeof(int32); - } - while(--num_spans); - } - } - - - //--------------------------------------------------------------- - const scanline_data& scanline_by_index(unsigned i) const - { - return (i < m_scanlines.size()) ? m_scanlines[i] : m_fake_scanline; - } - - //--------------------------------------------------------------- - const span_data& span_by_index(unsigned i) const - { - return (i < m_spans.size()) ? m_spans[i] : m_fake_span; - } - - - private: - pod_bvector m_spans; - pod_bvector m_scanlines; - span_data m_fake_span; - scanline_data m_fake_scanline; - int m_min_x; - int m_min_y; - int m_max_x; - int m_max_y; - unsigned m_cur_scanline; - }; - - - - - - - - - - - - - - //---------------------------------------serialized_scanlines_adaptor_bin - class serialized_scanlines_adaptor_bin - { - public: - typedef bool cover_type; - - //-------------------------------------------------------------------- - class embedded_scanline - { - public: - - //---------------------------------------------------------------- - class const_iterator - { - public: - struct span - { - int32 x; - int32 len; - }; - - const_iterator() : m_ptr(0) {} - const_iterator(const embedded_scanline& sl) : - m_ptr(sl.m_ptr), - m_dx(sl.m_dx) - { - m_span.x = read_int32() + m_dx; - m_span.len = read_int32(); - } - - const span& operator*() const { return m_span; } - const span* operator->() const { return &m_span; } - - void operator ++ () - { - m_span.x = read_int32() + m_dx; - m_span.len = read_int32(); - } - - private: - int read_int32() - { - int32 val; - ((int8u*)&val)[0] = *m_ptr++; - ((int8u*)&val)[1] = *m_ptr++; - ((int8u*)&val)[2] = *m_ptr++; - ((int8u*)&val)[3] = *m_ptr++; - return val; - } - - const int8u* m_ptr; - span m_span; - int m_dx; - }; - - friend class const_iterator; - - - //---------------------------------------------------------------- - embedded_scanline() : m_ptr(0), m_y(0), m_num_spans(0) {} - - //---------------------------------------------------------------- - void reset(int, int) {} - unsigned num_spans() const { return m_num_spans; } - int y() const { return m_y; } - const_iterator begin() const { return const_iterator(*this); } - - - private: - //---------------------------------------------------------------- - int read_int32() - { - int32 val; - ((int8u*)&val)[0] = *m_ptr++; - ((int8u*)&val)[1] = *m_ptr++; - ((int8u*)&val)[2] = *m_ptr++; - ((int8u*)&val)[3] = *m_ptr++; - return val; - } - - public: - //---------------------------------------------------------------- - void init(const int8u* ptr, int dx, int dy) - { - m_ptr = ptr; - m_y = read_int32() + dy; - m_num_spans = unsigned(read_int32()); - m_dx = dx; - } - - private: - const int8u* m_ptr; - int m_y; - unsigned m_num_spans; - int m_dx; - }; - - - - public: - //-------------------------------------------------------------------- - serialized_scanlines_adaptor_bin() : - m_data(0), - m_end(0), - m_ptr(0), - m_dx(0), - m_dy(0), - m_min_x(0x7FFFFFFF), - m_min_y(0x7FFFFFFF), - m_max_x(-0x7FFFFFFF), - m_max_y(-0x7FFFFFFF) - {} - - //-------------------------------------------------------------------- - serialized_scanlines_adaptor_bin(const int8u* data, unsigned size, - double dx, double dy) : - m_data(data), - m_end(data + size), - m_ptr(data), - m_dx(iround(dx)), - m_dy(iround(dy)), - m_min_x(0x7FFFFFFF), - m_min_y(0x7FFFFFFF), - m_max_x(-0x7FFFFFFF), - m_max_y(-0x7FFFFFFF) - {} - - //-------------------------------------------------------------------- - void init(const int8u* data, unsigned size, double dx, double dy) - { - m_data = data; - m_end = data + size; - m_ptr = data; - m_dx = iround(dx); - m_dy = iround(dy); - m_min_x = 0x7FFFFFFF; - m_min_y = 0x7FFFFFFF; - m_max_x = -0x7FFFFFFF; - m_max_y = -0x7FFFFFFF; - } - - private: - //-------------------------------------------------------------------- - int read_int32() - { - int32 val; - ((int8u*)&val)[0] = *m_ptr++; - ((int8u*)&val)[1] = *m_ptr++; - ((int8u*)&val)[2] = *m_ptr++; - ((int8u*)&val)[3] = *m_ptr++; - return val; - } - - public: - // Iterate scanlines interface - //-------------------------------------------------------------------- - bool rewind_scanlines() - { - m_ptr = m_data; - if(m_ptr < m_end) - { - m_min_x = read_int32() + m_dx; - m_min_y = read_int32() + m_dy; - m_max_x = read_int32() + m_dx; - m_max_y = read_int32() + m_dy; - } - return m_ptr < m_end; - } - - //-------------------------------------------------------------------- - int min_x() const { return m_min_x; } - int min_y() const { return m_min_y; } - int max_x() const { return m_max_x; } - int max_y() const { return m_max_y; } - - //-------------------------------------------------------------------- - template bool sweep_scanline(Scanline& sl) - { - sl.reset_spans(); - for(;;) - { - if(m_ptr >= m_end) return false; - - int y = read_int32() + m_dy; - unsigned num_spans = read_int32(); - - do - { - int x = read_int32() + m_dx; - int len = read_int32(); - - if(len < 0) len = -len; - sl.add_span(x, unsigned(len), cover_full); - } - while(--num_spans); - - if(sl.num_spans()) - { - sl.finalize(y); - break; - } - } - return true; - } - - - //-------------------------------------------------------------------- - // Specialization for embedded_scanline - bool sweep_scanline(embedded_scanline& sl) - { - do - { - if(m_ptr >= m_end) return false; - - sl.init(m_ptr, m_dx, m_dy); - - // Jump to the next scanline - //-------------------------- - read_int32(); // Y - int num_spans = read_int32(); // num_spans - m_ptr += num_spans * sizeof(int32) * 2; - } - while(sl.num_spans() == 0); - return true; - } - - private: - const int8u* m_data; - const int8u* m_end; - const int8u* m_ptr; - int m_dx; - int m_dy; - int m_min_x; - int m_min_y; - int m_max_x; - int m_max_y; - }; - - - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_scanline_u.h corsix-th-0.62/agg/include/agg_scanline_u.h --- corsix-th-0.30/agg/include/agg_scanline_u.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_scanline_u.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,499 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for 32-bit screen coordinates (scanline32_u) has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_SCANLINE_U_INCLUDED -#define AGG_SCANLINE_U_INCLUDED - -#include "agg_array.h" - -namespace agg -{ - //=============================================================scanline_u8 - // - // Unpacked scanline container class - // - // This class is used to transfer data from a scanline rasterizer - // to the rendering buffer. It's organized very simple. The class stores - // information of horizontal spans to render it into a pixel-map buffer. - // Each span has staring X, length, and an array of bytes that determine the - // cover-values for each pixel. - // Before using this class you should know the minimal and maximal pixel - // coordinates of your scanline. The protocol of using is: - // 1. reset(min_x, max_x) - // 2. add_cell() / add_span() - accumulate scanline. - // When forming one scanline the next X coordinate must be always greater - // than the last stored one, i.e. it works only with ordered coordinates. - // 3. Call finalize(y) and render the scanline. - // 3. Call reset_spans() to prepare for the new scanline. - // - // 4. Rendering: - // - // Scanline provides an iterator class that allows you to extract - // the spans and the cover values for each pixel. Be aware that clipping - // has not been done yet, so you should perform it yourself. - // Use scanline_u8::iterator to render spans: - //------------------------------------------------------------------------- - // - // int y = sl.y(); // Y-coordinate of the scanline - // - // ************************************ - // ...Perform vertical clipping here... - // ************************************ - // - // scanline_u8::const_iterator span = sl.begin(); - // - // unsigned char* row = m_rbuf->row(y); // The the address of the beginning - // // of the current row - // - // unsigned num_spans = sl.num_spans(); // Number of spans. It's guaranteed that - // // num_spans is always greater than 0. - // - // do - // { - // const scanline_u8::cover_type* covers = - // span->covers; // The array of the cover values - // - // int num_pix = span->len; // Number of pixels of the span. - // // Always greater than 0, still it's - // // better to use "int" instead of - // // "unsigned" because it's more - // // convenient for clipping - // int x = span->x; - // - // ************************************** - // ...Perform horizontal clipping here... - // ...you have x, covers, and pix_count.. - // ************************************** - // - // unsigned char* dst = row + x; // Calculate the start address of the row. - // // In this case we assume a simple - // // grayscale image 1-byte per pixel. - // do - // { - // *dst++ = *covers++; // Hypotetical rendering. - // } - // while(--num_pix); - // - // ++span; - // } - // while(--num_spans); // num_spans cannot be 0, so this loop is quite safe - //------------------------------------------------------------------------ - // - // The question is: why should we accumulate the whole scanline when we - // could render just separate spans when they're ready? - // That's because using the scanline is generally faster. When is consists - // of more than one span the conditions for the processor cash system - // are better, because switching between two different areas of memory - // (that can be very large) occurs less frequently. - //------------------------------------------------------------------------ - class scanline_u8 - { - public: - typedef scanline_u8 self_type; - typedef int8u cover_type; - typedef int16 coord_type; - - //-------------------------------------------------------------------- - struct span - { - coord_type x; - coord_type len; - cover_type* covers; - }; - - typedef span* iterator; - typedef const span* const_iterator; - - //-------------------------------------------------------------------- - scanline_u8() : - m_min_x(0), - m_last_x(0x7FFFFFF0), - m_cur_span(0) - {} - - //-------------------------------------------------------------------- - void reset(int min_x, int max_x) - { - unsigned max_len = max_x - min_x + 2; - if(max_len > m_spans.size()) - { - m_spans.resize(max_len); - m_covers.resize(max_len); - } - m_last_x = 0x7FFFFFF0; - m_min_x = min_x; - m_cur_span = &m_spans[0]; - } - - //-------------------------------------------------------------------- - void add_cell(int x, unsigned cover) - { - x -= m_min_x; - m_covers[x] = (cover_type)cover; - if(x == m_last_x+1) - { - m_cur_span->len++; - } - else - { - m_cur_span++; - m_cur_span->x = (coord_type)(x + m_min_x); - m_cur_span->len = 1; - m_cur_span->covers = &m_covers[x]; - } - m_last_x = x; - } - - //-------------------------------------------------------------------- - void add_cells(int x, unsigned len, const cover_type* covers) - { - x -= m_min_x; - memcpy(&m_covers[x], covers, len * sizeof(cover_type)); - if(x == m_last_x+1) - { - m_cur_span->len += (coord_type)len; - } - else - { - m_cur_span++; - m_cur_span->x = (coord_type)(x + m_min_x); - m_cur_span->len = (coord_type)len; - m_cur_span->covers = &m_covers[x]; - } - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void add_span(int x, unsigned len, unsigned cover) - { - x -= m_min_x; - memset(&m_covers[x], cover, len); - if(x == m_last_x+1) - { - m_cur_span->len += (coord_type)len; - } - else - { - m_cur_span++; - m_cur_span->x = (coord_type)(x + m_min_x); - m_cur_span->len = (coord_type)len; - m_cur_span->covers = &m_covers[x]; - } - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void finalize(int y) - { - m_y = y; - } - - //-------------------------------------------------------------------- - void reset_spans() - { - m_last_x = 0x7FFFFFF0; - m_cur_span = &m_spans[0]; - } - - //-------------------------------------------------------------------- - int y() const { return m_y; } - unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } - const_iterator begin() const { return &m_spans[1]; } - iterator begin() { return &m_spans[1]; } - - private: - scanline_u8(const self_type&); - const self_type& operator = (const self_type&); - - private: - int m_min_x; - int m_last_x; - int m_y; - pod_array m_covers; - pod_array m_spans; - span* m_cur_span; - }; - - - - - //==========================================================scanline_u8_am - // - // The scanline container with alpha-masking - // - //------------------------------------------------------------------------ - template - class scanline_u8_am : public scanline_u8 - { - public: - typedef scanline_u8 base_type; - typedef AlphaMask alpha_mask_type; - typedef base_type::cover_type cover_type; - typedef base_type::coord_type coord_type; - - scanline_u8_am() : base_type(), m_alpha_mask(0) {} - scanline_u8_am(const AlphaMask& am) : base_type(), m_alpha_mask(&am) {} - - //-------------------------------------------------------------------- - void finalize(int span_y) - { - base_type::finalize(span_y); - if(m_alpha_mask) - { - typename base_type::iterator span = base_type::begin(); - unsigned count = base_type::num_spans(); - do - { - m_alpha_mask->combine_hspan(span->x, - base_type::y(), - span->covers, - span->len); - ++span; - } - while(--count); - } - } - - private: - const AlphaMask* m_alpha_mask; - }; - - - - - //===========================================================scanline32_u8 - class scanline32_u8 - { - public: - typedef scanline32_u8 self_type; - typedef int8u cover_type; - typedef int32 coord_type; - - //-------------------------------------------------------------------- - struct span - { - span() {} - span(coord_type x_, coord_type len_, cover_type* covers_) : - x(x_), len(len_), covers(covers_) {} - - coord_type x; - coord_type len; - cover_type* covers; - }; - - typedef pod_bvector span_array_type; - - //-------------------------------------------------------------------- - class const_iterator - { - public: - const_iterator(const span_array_type& spans) : - m_spans(spans), - m_span_idx(0) - {} - - const span& operator*() const { return m_spans[m_span_idx]; } - const span* operator->() const { return &m_spans[m_span_idx]; } - - void operator ++ () { ++m_span_idx; } - - private: - const span_array_type& m_spans; - unsigned m_span_idx; - }; - - //-------------------------------------------------------------------- - class iterator - { - public: - iterator(span_array_type& spans) : - m_spans(spans), - m_span_idx(0) - {} - - span& operator*() { return m_spans[m_span_idx]; } - span* operator->() { return &m_spans[m_span_idx]; } - - void operator ++ () { ++m_span_idx; } - - private: - span_array_type& m_spans; - unsigned m_span_idx; - }; - - - - //-------------------------------------------------------------------- - scanline32_u8() : - m_min_x(0), - m_last_x(0x7FFFFFF0), - m_covers() - {} - - //-------------------------------------------------------------------- - void reset(int min_x, int max_x) - { - unsigned max_len = max_x - min_x + 2; - if(max_len > m_covers.size()) - { - m_covers.resize(max_len); - } - m_last_x = 0x7FFFFFF0; - m_min_x = min_x; - m_spans.remove_all(); - } - - //-------------------------------------------------------------------- - void add_cell(int x, unsigned cover) - { - x -= m_min_x; - m_covers[x] = cover_type(cover); - if(x == m_last_x+1) - { - m_spans.last().len++; - } - else - { - m_spans.add(span(coord_type(x + m_min_x), 1, &m_covers[x])); - } - m_last_x = x; - } - - //-------------------------------------------------------------------- - void add_cells(int x, unsigned len, const cover_type* covers) - { - x -= m_min_x; - memcpy(&m_covers[x], covers, len * sizeof(cover_type)); - if(x == m_last_x+1) - { - m_spans.last().len += coord_type(len); - } - else - { - m_spans.add(span(coord_type(x + m_min_x), - coord_type(len), - &m_covers[x])); - } - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void add_span(int x, unsigned len, unsigned cover) - { - x -= m_min_x; - memset(&m_covers[x], cover, len); - if(x == m_last_x+1) - { - m_spans.last().len += coord_type(len); - } - else - { - m_spans.add(span(coord_type(x + m_min_x), - coord_type(len), - &m_covers[x])); - } - m_last_x = x + len - 1; - } - - //-------------------------------------------------------------------- - void finalize(int y) - { - m_y = y; - } - - //-------------------------------------------------------------------- - void reset_spans() - { - m_last_x = 0x7FFFFFF0; - m_spans.remove_all(); - } - - //-------------------------------------------------------------------- - int y() const { return m_y; } - unsigned num_spans() const { return m_spans.size(); } - const_iterator begin() const { return const_iterator(m_spans); } - iterator begin() { return iterator(m_spans); } - - private: - scanline32_u8(const self_type&); - const self_type& operator = (const self_type&); - - private: - int m_min_x; - int m_last_x; - int m_y; - pod_array m_covers; - span_array_type m_spans; - }; - - - - - //========================================================scanline32_u8_am - // - // The scanline container with alpha-masking - // - //------------------------------------------------------------------------ - template - class scanline32_u8_am : public scanline32_u8 - { - public: - typedef scanline_u8 base_type; - typedef AlphaMask alpha_mask_type; - typedef base_type::cover_type cover_type; - typedef base_type::coord_type coord_type; - - - scanline32_u8_am() : base_type(), m_alpha_mask(0) {} - scanline32_u8_am(const AlphaMask& am) : base_type(), m_alpha_mask(&am) {} - - //-------------------------------------------------------------------- - void finalize(int span_y) - { - base_type::finalize(span_y); - if(m_alpha_mask) - { - typename base_type::iterator span = base_type::begin(); - unsigned count = base_type::num_spans(); - do - { - m_alpha_mask->combine_hspan(span->x, - base_type::y(), - span->covers, - span->len); - ++span; - } - while(--count); - } - } - - private: - const AlphaMask* m_alpha_mask; - }; - - - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_shorten_path.h corsix-th-0.62/agg/include/agg_shorten_path.h --- corsix-th-0.30/agg/include/agg_shorten_path.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_shorten_path.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SHORTEN_PATH_INCLUDED -#define AGG_SHORTEN_PATH_INCLUDED - -#include "agg_basics.h" -#include "agg_vertex_sequence.h" - -namespace agg -{ - - //===========================================================shorten_path - template - void shorten_path(VertexSequence& vs, double s, unsigned closed = 0) - { - typedef typename VertexSequence::value_type vertex_type; - - if(s > 0.0 && vs.size() > 1) - { - double d; - int n = int(vs.size() - 2); - while(n) - { - d = vs[n].dist; - if(d > s) break; - vs.remove_last(); - s -= d; - --n; - } - if(vs.size() < 2) - { - vs.remove_all(); - } - else - { - n = vs.size() - 1; - vertex_type& prev = vs[n-1]; - vertex_type& last = vs[n]; - d = (prev.dist - s) / prev.dist; - double x = prev.x + (last.x - prev.x) * d; - double y = prev.y + (last.y - prev.y) * d; - last.x = x; - last.y = y; - if(!prev(last)) vs.remove_last(); - vs.close(closed != 0); - } - } - } - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_simul_eq.h corsix-th-0.62/agg/include/agg_simul_eq.h --- corsix-th-0.30/agg/include/agg_simul_eq.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_simul_eq.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Solving simultaneous equations -// -//---------------------------------------------------------------------------- -#ifndef AGG_SIMUL_EQ_INCLUDED -#define AGG_SIMUL_EQ_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - - //=============================================================swap_arrays - template void swap_arrays(T* a1, T* a2, unsigned n) - { - unsigned i; - for(i = 0; i < n; i++) - { - T tmp = *a1; - *a1++ = *a2; - *a2++ = tmp; - } - } - - - //============================================================matrix_pivot - template - struct matrix_pivot - { - static int pivot(double m[Rows][Cols], unsigned row) - { - int k = int(row); - double max_val, tmp; - - max_val = -1.0; - unsigned i; - for(i = row; i < Rows; i++) - { - if((tmp = fabs(m[i][row])) > max_val && tmp != 0.0) - { - max_val = tmp; - k = i; - } - } - - if(m[k][row] == 0.0) - { - return -1; - } - - if(k != int(row)) - { - swap_arrays(m[k], m[row], Cols); - return k; - } - return 0; - } - }; - - - - //===============================================================simul_eq - template - struct simul_eq - { - static bool solve(const double left[Size][Size], - const double right[Size][RightCols], - double result[Size][RightCols]) - { - unsigned i, j, k; - double a1; - - double tmp[Size][Size + RightCols]; - - for(i = 0; i < Size; i++) - { - for(j = 0; j < Size; j++) - { - tmp[i][j] = left[i][j]; - } - for(j = 0; j < RightCols; j++) - { - tmp[i][Size + j] = right[i][j]; - } - } - - for(k = 0; k < Size; k++) - { - if(matrix_pivot::pivot(tmp, k) < 0) - { - return false; // Singularity.... - } - - a1 = tmp[k][k]; - - for(j = k; j < Size + RightCols; j++) - { - tmp[k][j] /= a1; - } - - for(i = k + 1; i < Size; i++) - { - a1 = tmp[i][k]; - for (j = k; j < Size + RightCols; j++) - { - tmp[i][j] -= a1 * tmp[k][j]; - } - } - } - - - for(k = 0; k < RightCols; k++) - { - int m; - for(m = int(Size - 1); m >= 0; m--) - { - result[m][k] = tmp[m][Size + k]; - for(j = m + 1; j < Size; j++) - { - result[m][k] -= tmp[m][j] * result[j][k]; - } - } - } - return true; - } - - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_allocator.h corsix-th-0.62/agg/include/agg_span_allocator.h --- corsix-th-0.30/agg/include/agg_span_allocator.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_allocator.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_ALLOCATOR_INCLUDED -#define AGG_SPAN_ALLOCATOR_INCLUDED - -#include "agg_array.h" - -namespace agg -{ - //----------------------------------------------------------span_allocator - template class span_allocator - { - public: - typedef ColorT color_type; - - //-------------------------------------------------------------------- - AGG_INLINE color_type* allocate(unsigned span_len) - { - if(span_len > m_span.size()) - { - // To reduce the number of reallocs we align the - // span_len to 256 color elements. - // Well, I just like this number and it looks reasonable. - //----------------------- - m_span.resize(((span_len + 255) >> 8) << 8); - } - return &m_span[0]; - } - - AGG_INLINE color_type* span() { return &m_span[0]; } - AGG_INLINE unsigned max_span_len() const { return m_span.size(); } - - private: - pod_array m_span; - }; -} - - -#endif - - diff -Nru corsix-th-0.30/agg/include/agg_span_converter.h corsix-th-0.62/agg/include/agg_span_converter.h --- corsix-th-0.30/agg/include/agg_span_converter.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_converter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_CONVERTER_INCLUDED -#define AGG_SPAN_CONVERTER_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - //----------------------------------------------------------span_converter - template class span_converter - { - public: - typedef typename SpanGenerator::color_type color_type; - - span_converter(SpanGenerator& span_gen, SpanConverter& span_cnv) : - m_span_gen(&span_gen), m_span_cnv(&span_cnv) {} - - void attach_generator(SpanGenerator& span_gen) { m_span_gen = &span_gen; } - void attach_converter(SpanConverter& span_cnv) { m_span_cnv = &span_cnv; } - - //-------------------------------------------------------------------- - void prepare() - { - m_span_gen->prepare(); - m_span_cnv->prepare(); - } - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - m_span_gen->generate(span, x, y, len); - m_span_cnv->generate(span, x, y, len); - } - - private: - SpanGenerator* m_span_gen; - SpanConverter* m_span_cnv; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_gouraud_gray.h corsix-th-0.62/agg/include/agg_span_gouraud_gray.h --- corsix-th-0.30/agg/include/agg_span_gouraud_gray.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_gouraud_gray.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,241 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_GOURAUD_GRAY_INCLUDED -#define AGG_SPAN_GOURAUD_GRAY_INCLUDED - -#include "agg_basics.h" -#include "agg_color_gray.h" -#include "agg_dda_line.h" -#include "agg_span_gouraud.h" - -namespace agg -{ - - //=======================================================span_gouraud_gray - template class span_gouraud_gray : public span_gouraud - { - public: - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - typedef span_gouraud base_type; - typedef typename base_type::coord_type coord_type; - enum subpixel_scale_e - { - subpixel_shift = 4, - subpixel_scale = 1 << subpixel_shift - }; - - private: - //-------------------------------------------------------------------- - struct gray_calc - { - void init(const coord_type& c1, const coord_type& c2) - { - m_x1 = c1.x - 0.5; - m_y1 = c1.y - 0.5; - m_dx = c2.x - c1.x; - double dy = c2.y - c1.y; - m_1dy = (fabs(dy) < 1e-10) ? 1e10 : 1.0 / dy; - m_v1 = c1.color.v; - m_a1 = c1.color.a; - m_dv = c2.color.v - m_v1; - m_da = c2.color.a - m_a1; - } - - void calc(double y) - { - double k = (y - m_y1) * m_1dy; - if(k < 0.0) k = 0.0; - if(k > 1.0) k = 1.0; - m_v = m_v1 + iround(m_dv * k); - m_a = m_a1 + iround(m_da * k); - m_x = iround((m_x1 + m_dx * k) * subpixel_scale); - } - - double m_x1; - double m_y1; - double m_dx; - double m_1dy; - int m_v1; - int m_a1; - int m_dv; - int m_da; - int m_v; - int m_a; - int m_x; - }; - - - public: - //-------------------------------------------------------------------- - span_gouraud_gray() {} - span_gouraud_gray(const color_type& c1, - const color_type& c2, - const color_type& c3, - double x1, double y1, - double x2, double y2, - double x3, double y3, - double d = 0) : - base_type(c1, c2, c3, x1, y1, x2, y2, x3, y3, d) - {} - - //-------------------------------------------------------------------- - void prepare() - { - coord_type coord[3]; - base_type::arrange_vertices(coord); - - m_y2 = int(coord[1].y); - - m_swap = cross_product(coord[0].x, coord[0].y, - coord[2].x, coord[2].y, - coord[1].x, coord[1].y) < 0.0; - - m_c1.init(coord[0], coord[2]); - m_c2.init(coord[0], coord[1]); - m_c3.init(coord[1], coord[2]); - } - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - m_c1.calc(y); - const gray_calc* pc1 = &m_c1; - const gray_calc* pc2 = &m_c2; - - if(y < m_y2) - { - // Bottom part of the triangle (first subtriangle) - //------------------------- - m_c2.calc(y + m_c2.m_1dy); - } - else - { - // Upper part (second subtriangle) - //------------------------- - m_c3.calc(y - m_c3.m_1dy); - pc2 = &m_c3; - } - - if(m_swap) - { - // It means that the triangle is oriented clockwise, - // so that we need to swap the controlling structures - //------------------------- - const gray_calc* t = pc2; - pc2 = pc1; - pc1 = t; - } - - // Get the horizontal length with subpixel accuracy - // and protect it from division by zero - //------------------------- - int nlen = abs(pc2->m_x - pc1->m_x); - if(nlen <= 0) nlen = 1; - - dda_line_interpolator<14> v(pc1->m_v, pc2->m_v, nlen); - dda_line_interpolator<14> a(pc1->m_a, pc2->m_a, nlen); - - // Calculate the starting point of the gradient with subpixel - // accuracy and correct (roll back) the interpolators. - // This operation will also clip the beginning of the span - // if necessary. - //------------------------- - int start = pc1->m_x - (x << subpixel_shift); - v -= start; - a -= start; - nlen += start; - - int vv, va; - enum lim_e { lim = color_type::base_mask }; - - // Beginning part of the span. Since we rolled back the - // interpolators, the color values may have overflow. - // So that, we render the beginning part with checking - // for overflow. It lasts until "start" is positive; - // typically it's 1-2 pixels, but may be more in some cases. - //------------------------- - while(len && start > 0) - { - vv = v.y(); - va = a.y(); - if(vv < 0) vv = 0; if(vv > lim) vv = lim; - if(va < 0) va = 0; if(va > lim) va = lim; - span->v = (value_type)vv; - span->a = (value_type)va; - v += subpixel_scale; - a += subpixel_scale; - nlen -= subpixel_scale; - start -= subpixel_scale; - ++span; - --len; - } - - // Middle part, no checking for overflow. - // Actual spans can be longer than the calculated length - // because of anti-aliasing, thus, the interpolators can - // overflow. But while "nlen" is positive we are safe. - //------------------------- - while(len && nlen > 0) - { - span->v = (value_type)v.y(); - span->a = (value_type)a.y(); - v += subpixel_scale; - a += subpixel_scale; - nlen -= subpixel_scale; - ++span; - --len; - } - - // Ending part; checking for overflow. - // Typically it's 1-2 pixels, but may be more in some cases. - //------------------------- - while(len) - { - vv = v.y(); - va = a.y(); - if(vv < 0) vv = 0; if(vv > lim) vv = lim; - if(va < 0) va = 0; if(va > lim) va = lim; - span->v = (value_type)vv; - span->a = (value_type)va; - v += subpixel_scale; - a += subpixel_scale; - ++span; - --len; - } - } - - - private: - bool m_swap; - int m_y2; - gray_calc m_c1; - gray_calc m_c2; - gray_calc m_c3; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_gouraud.h corsix-th-0.62/agg/include/agg_span_gouraud.h --- corsix-th-0.30/agg/include/agg_span_gouraud.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_gouraud.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,172 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_GOURAUD_INCLUDED -#define AGG_SPAN_GOURAUD_INCLUDED - -#include "agg_basics.h" -#include "agg_math.h" - -namespace agg -{ - - //============================================================span_gouraud - template class span_gouraud - { - public: - typedef ColorT color_type; - - struct coord_type - { - double x; - double y; - color_type color; - }; - - //-------------------------------------------------------------------- - span_gouraud() : - m_vertex(0) - { - m_cmd[0] = path_cmd_stop; - } - - //-------------------------------------------------------------------- - span_gouraud(const color_type& c1, - const color_type& c2, - const color_type& c3, - double x1, double y1, - double x2, double y2, - double x3, double y3, - double d) : - m_vertex(0) - { - colors(c1, c2, c3); - triangle(x1, y1, x2, y2, x3, y3, d); - } - - //-------------------------------------------------------------------- - void colors(ColorT c1, ColorT c2, ColorT c3) - { - m_coord[0].color = c1; - m_coord[1].color = c2; - m_coord[2].color = c3; - } - - //-------------------------------------------------------------------- - // Sets the triangle and dilates it if needed. - // The trick here is to calculate beveled joins in the vertices of the - // triangle and render it as a 6-vertex polygon. - // It's necessary to achieve numerical stability. - // However, the coordinates to interpolate colors are calculated - // as miter joins (calc_intersection). - void triangle(double x1, double y1, - double x2, double y2, - double x3, double y3, - double d) - { - m_coord[0].x = m_x[0] = x1; - m_coord[0].y = m_y[0] = y1; - m_coord[1].x = m_x[1] = x2; - m_coord[1].y = m_y[1] = y2; - m_coord[2].x = m_x[2] = x3; - m_coord[2].y = m_y[2] = y3; - m_cmd[0] = path_cmd_move_to; - m_cmd[1] = path_cmd_line_to; - m_cmd[2] = path_cmd_line_to; - m_cmd[3] = path_cmd_stop; - - if(d != 0.0) - { - dilate_triangle(m_coord[0].x, m_coord[0].y, - m_coord[1].x, m_coord[1].y, - m_coord[2].x, m_coord[2].y, - m_x, m_y, d); - - calc_intersection(m_x[4], m_y[4], m_x[5], m_y[5], - m_x[0], m_y[0], m_x[1], m_y[1], - &m_coord[0].x, &m_coord[0].y); - - calc_intersection(m_x[0], m_y[0], m_x[1], m_y[1], - m_x[2], m_y[2], m_x[3], m_y[3], - &m_coord[1].x, &m_coord[1].y); - - calc_intersection(m_x[2], m_y[2], m_x[3], m_y[3], - m_x[4], m_y[4], m_x[5], m_y[5], - &m_coord[2].x, &m_coord[2].y); - m_cmd[3] = path_cmd_line_to; - m_cmd[4] = path_cmd_line_to; - m_cmd[5] = path_cmd_line_to; - m_cmd[6] = path_cmd_stop; - } - } - - //-------------------------------------------------------------------- - // Vertex Source Interface to feed the coordinates to the rasterizer - void rewind(unsigned) - { - m_vertex = 0; - } - - //-------------------------------------------------------------------- - unsigned vertex(double* x, double* y) - { - *x = m_x[m_vertex]; - *y = m_y[m_vertex]; - return m_cmd[m_vertex++]; - } - - protected: - //-------------------------------------------------------------------- - void arrange_vertices(coord_type* coord) const - { - coord[0] = m_coord[0]; - coord[1] = m_coord[1]; - coord[2] = m_coord[2]; - - if(m_coord[0].y > m_coord[2].y) - { - coord[0] = m_coord[2]; - coord[2] = m_coord[0]; - } - - coord_type tmp; - if(coord[0].y > coord[1].y) - { - tmp = coord[1]; - coord[1] = coord[0]; - coord[0] = tmp; - } - - if(coord[1].y > coord[2].y) - { - tmp = coord[2]; - coord[2] = coord[1]; - coord[1] = tmp; - } - } - - private: - //-------------------------------------------------------------------- - coord_type m_coord[3]; - double m_x[8]; - double m_y[8]; - unsigned m_cmd[8]; - unsigned m_vertex; - }; - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_span_gouraud_rgba.h corsix-th-0.62/agg/include/agg_span_gouraud_rgba.h --- corsix-th-0.30/agg/include/agg_span_gouraud_rgba.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_gouraud_rgba.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,277 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_GOURAUD_RGBA_INCLUDED -#define AGG_SPAN_GOURAUD_RGBA_INCLUDED - -#include "agg_basics.h" -#include "agg_color_rgba.h" -#include "agg_dda_line.h" -#include "agg_span_gouraud.h" - -namespace agg -{ - - //=======================================================span_gouraud_rgba - template class span_gouraud_rgba : public span_gouraud - { - public: - typedef ColorT color_type; - typedef typename ColorT::value_type value_type; - typedef span_gouraud base_type; - typedef typename base_type::coord_type coord_type; - enum subpixel_scale_e - { - subpixel_shift = 4, - subpixel_scale = 1 << subpixel_shift - }; - - private: - //-------------------------------------------------------------------- - struct rgba_calc - { - void init(const coord_type& c1, const coord_type& c2) - { - m_x1 = c1.x - 0.5; - m_y1 = c1.y - 0.5; - m_dx = c2.x - c1.x; - double dy = c2.y - c1.y; - m_1dy = (dy < 1e-5) ? 1e5 : 1.0 / dy; - m_r1 = c1.color.r; - m_g1 = c1.color.g; - m_b1 = c1.color.b; - m_a1 = c1.color.a; - m_dr = c2.color.r - m_r1; - m_dg = c2.color.g - m_g1; - m_db = c2.color.b - m_b1; - m_da = c2.color.a - m_a1; - } - - void calc(double y) - { - double k = (y - m_y1) * m_1dy; - if(k < 0.0) k = 0.0; - if(k > 1.0) k = 1.0; - m_r = m_r1 + iround(m_dr * k); - m_g = m_g1 + iround(m_dg * k); - m_b = m_b1 + iround(m_db * k); - m_a = m_a1 + iround(m_da * k); - m_x = iround((m_x1 + m_dx * k) * subpixel_scale); - } - - double m_x1; - double m_y1; - double m_dx; - double m_1dy; - int m_r1; - int m_g1; - int m_b1; - int m_a1; - int m_dr; - int m_dg; - int m_db; - int m_da; - int m_r; - int m_g; - int m_b; - int m_a; - int m_x; - }; - - public: - - //-------------------------------------------------------------------- - span_gouraud_rgba() {} - span_gouraud_rgba(const color_type& c1, - const color_type& c2, - const color_type& c3, - double x1, double y1, - double x2, double y2, - double x3, double y3, - double d = 0) : - base_type(c1, c2, c3, x1, y1, x2, y2, x3, y3, d) - {} - - //-------------------------------------------------------------------- - void prepare() - { - coord_type coord[3]; - base_type::arrange_vertices(coord); - - m_y2 = int(coord[1].y); - - m_swap = cross_product(coord[0].x, coord[0].y, - coord[2].x, coord[2].y, - coord[1].x, coord[1].y) < 0.0; - - m_rgba1.init(coord[0], coord[2]); - m_rgba2.init(coord[0], coord[1]); - m_rgba3.init(coord[1], coord[2]); - } - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - m_rgba1.calc(y);//(m_rgba1.m_1dy > 2) ? m_rgba1.m_y1 : y); - const rgba_calc* pc1 = &m_rgba1; - const rgba_calc* pc2 = &m_rgba2; - - if(y <= m_y2) - { - // Bottom part of the triangle (first subtriangle) - //------------------------- - m_rgba2.calc(y + m_rgba2.m_1dy); - } - else - { - // Upper part (second subtriangle) - m_rgba3.calc(y - m_rgba3.m_1dy); - //------------------------- - pc2 = &m_rgba3; - } - - if(m_swap) - { - // It means that the triangle is oriented clockwise, - // so that we need to swap the controlling structures - //------------------------- - const rgba_calc* t = pc2; - pc2 = pc1; - pc1 = t; - } - - // Get the horizontal length with subpixel accuracy - // and protect it from division by zero - //------------------------- - int nlen = abs(pc2->m_x - pc1->m_x); - if(nlen <= 0) nlen = 1; - - dda_line_interpolator<14> r(pc1->m_r, pc2->m_r, nlen); - dda_line_interpolator<14> g(pc1->m_g, pc2->m_g, nlen); - dda_line_interpolator<14> b(pc1->m_b, pc2->m_b, nlen); - dda_line_interpolator<14> a(pc1->m_a, pc2->m_a, nlen); - - // Calculate the starting point of the gradient with subpixel - // accuracy and correct (roll back) the interpolators. - // This operation will also clip the beginning of the span - // if necessary. - //------------------------- - int start = pc1->m_x - (x << subpixel_shift); - r -= start; - g -= start; - b -= start; - a -= start; - nlen += start; - - int vr, vg, vb, va; - enum lim_e { lim = color_type::base_mask }; - - // Beginning part of the span. Since we rolled back the - // interpolators, the color values may have overflow. - // So that, we render the beginning part with checking - // for overflow. It lasts until "start" is positive; - // typically it's 1-2 pixels, but may be more in some cases. - //------------------------- - while(len && start > 0) - { - vr = r.y(); - vg = g.y(); - vb = b.y(); - va = a.y(); - if(vr < 0) vr = 0; if(vr > lim) vr = lim; - if(vg < 0) vg = 0; if(vg > lim) vg = lim; - if(vb < 0) vb = 0; if(vb > lim) vb = lim; - if(va < 0) va = 0; if(va > lim) va = lim; - span->r = (value_type)vr; - span->g = (value_type)vg; - span->b = (value_type)vb; - span->a = (value_type)va; - r += subpixel_scale; - g += subpixel_scale; - b += subpixel_scale; - a += subpixel_scale; - nlen -= subpixel_scale; - start -= subpixel_scale; - ++span; - --len; - } - - // Middle part, no checking for overflow. - // Actual spans can be longer than the calculated length - // because of anti-aliasing, thus, the interpolators can - // overflow. But while "nlen" is positive we are safe. - //------------------------- - while(len && nlen > 0) - { - span->r = (value_type)r.y(); - span->g = (value_type)g.y(); - span->b = (value_type)b.y(); - span->a = (value_type)a.y(); - r += subpixel_scale; - g += subpixel_scale; - b += subpixel_scale; - a += subpixel_scale; - nlen -= subpixel_scale; - ++span; - --len; - } - - // Ending part; checking for overflow. - // Typically it's 1-2 pixels, but may be more in some cases. - //------------------------- - while(len) - { - vr = r.y(); - vg = g.y(); - vb = b.y(); - va = a.y(); - if(vr < 0) vr = 0; if(vr > lim) vr = lim; - if(vg < 0) vg = 0; if(vg > lim) vg = lim; - if(vb < 0) vb = 0; if(vb > lim) vb = lim; - if(va < 0) va = 0; if(va > lim) va = lim; - span->r = (value_type)vr; - span->g = (value_type)vg; - span->b = (value_type)vb; - span->a = (value_type)va; - r += subpixel_scale; - g += subpixel_scale; - b += subpixel_scale; - a += subpixel_scale; - ++span; - --len; - } - } - - private: - bool m_swap; - int m_y2; - rgba_calc m_rgba1; - rgba_calc m_rgba2; - rgba_calc m_rgba3; - }; - - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_gradient_alpha.h corsix-th-0.62/agg/include/agg_span_gradient_alpha.h --- corsix-th-0.30/agg/include/agg_span_gradient_alpha.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_gradient_alpha.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_GRADIENT_ALPHA_INCLUDED -#define AGG_SPAN_GRADIENT_ALPHA_INCLUDED - -#include "agg_span_gradient.h" - -namespace agg -{ - //======================================================span_gradient_alpha - template - class span_gradient_alpha - { - public: - typedef Interpolator interpolator_type; - typedef ColorT color_type; - typedef typename color_type::value_type alpha_type; - - enum downscale_shift_e - { - downscale_shift = interpolator_type::subpixel_shift - gradient_subpixel_shift - }; - - - //-------------------------------------------------------------------- - span_gradient_alpha() {} - - //-------------------------------------------------------------------- - span_gradient_alpha(interpolator_type& inter, - const GradientF& gradient_function, - const AlphaF& alpha_function, - double d1, double d2) : - m_interpolator(&inter), - m_gradient_function(&gradient_function), - m_alpha_function(&alpha_function), - m_d1(iround(d1 * gradient_subpixel_scale)), - m_d2(iround(d2 * gradient_subpixel_scale)) - {} - - //-------------------------------------------------------------------- - interpolator_type& interpolator() { return *m_interpolator; } - const GradientF& gradient_function() const { return *m_gradient_function; } - const AlphaF& alpha_function() const { return *m_alpha_function; } - double d1() const { return double(m_d1) / gradient_subpixel_scale; } - double d2() const { return double(m_d2) / gradient_subpixel_scale; } - - //-------------------------------------------------------------------- - void interpolator(interpolator_type& i) { m_interpolator = &i; } - void gradient_function(const GradientF& gf) { m_gradient_function = &gf; } - void alpha_function(const AlphaF& af) { m_alpha_function = ⁡ } - void d1(double v) { m_d1 = iround(v * gradient_subpixel_scale); } - void d2(double v) { m_d2 = iround(v * gradient_subpixel_scale); } - - //-------------------------------------------------------------------- - void prepare() {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - int dd = m_d2 - m_d1; - if(dd < 1) dd = 1; - m_interpolator->begin(x+0.5, y+0.5, len); - do - { - m_interpolator->coordinates(&x, &y); - int d = m_gradient_function->calculate(x >> downscale_shift, - y >> downscale_shift, m_d2); - d = ((d - m_d1) * (int)m_alpha_function->size()) / dd; - if(d < 0) d = 0; - if(d >= (int)m_alpha_function->size()) d = m_alpha_function->size() - 1; - span->a = (*m_alpha_function)[d]; - ++span; - ++(*m_interpolator); - } - while(--len); - } - - private: - interpolator_type* m_interpolator; - const GradientF* m_gradient_function; - const AlphaF* m_alpha_function; - int m_d1; - int m_d2; - }; - - - //=======================================================gradient_alpha_x - template struct gradient_alpha_x - { - typedef typename ColorT::value_type alpha_type; - alpha_type operator [] (alpha_type x) const { return x; } - }; - - //====================================================gradient_alpha_x_u8 - struct gradient_alpha_x_u8 - { - typedef int8u alpha_type; - alpha_type operator [] (alpha_type x) const { return x; } - }; - - //==========================================gradient_alpha_one_munus_x_u8 - struct gradient_alpha_one_munus_x_u8 - { - typedef int8u alpha_type; - alpha_type operator [] (alpha_type x) const { return 255-x; } - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_gradient.h corsix-th-0.62/agg/include/agg_span_gradient.h --- corsix-th-0.30/agg/include/agg_span_gradient.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_gradient.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,364 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_GRADIENT_INCLUDED -#define AGG_SPAN_GRADIENT_INCLUDED - -#include -#include -#include -#include "agg_basics.h" -#include "agg_math.h" -#include "agg_array.h" - - -namespace agg -{ - - enum gradient_subpixel_scale_e - { - gradient_subpixel_shift = 4, //-----gradient_subpixel_shift - gradient_subpixel_scale = 1 << gradient_subpixel_shift, //-----gradient_subpixel_scale - gradient_subpixel_mask = gradient_subpixel_scale - 1 //-----gradient_subpixel_mask - }; - - - - //==========================================================span_gradient - template - class span_gradient - { - public: - typedef Interpolator interpolator_type; - typedef ColorT color_type; - - enum downscale_shift_e - { - downscale_shift = interpolator_type::subpixel_shift - - gradient_subpixel_shift - }; - - //-------------------------------------------------------------------- - span_gradient() {} - - //-------------------------------------------------------------------- - span_gradient(interpolator_type& inter, - const GradientF& gradient_function, - const ColorF& color_function, - double d1, double d2) : - m_interpolator(&inter), - m_gradient_function(&gradient_function), - m_color_function(&color_function), - m_d1(iround(d1 * gradient_subpixel_scale)), - m_d2(iround(d2 * gradient_subpixel_scale)) - {} - - //-------------------------------------------------------------------- - interpolator_type& interpolator() { return *m_interpolator; } - const GradientF& gradient_function() const { return *m_gradient_function; } - const ColorF& color_function() const { return *m_color_function; } - double d1() const { return double(m_d1) / gradient_subpixel_scale; } - double d2() const { return double(m_d2) / gradient_subpixel_scale; } - - //-------------------------------------------------------------------- - void interpolator(interpolator_type& i) { m_interpolator = &i; } - void gradient_function(const GradientF& gf) { m_gradient_function = &gf; } - void color_function(const ColorF& cf) { m_color_function = &cf; } - void d1(double v) { m_d1 = iround(v * gradient_subpixel_scale); } - void d2(double v) { m_d2 = iround(v * gradient_subpixel_scale); } - - //-------------------------------------------------------------------- - void prepare() {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - int dd = m_d2 - m_d1; - if(dd < 1) dd = 1; - m_interpolator->begin(x+0.5, y+0.5, len); - do - { - m_interpolator->coordinates(&x, &y); - int d = m_gradient_function->calculate(x >> downscale_shift, - y >> downscale_shift, m_d2); - d = ((d - m_d1) * (int)m_color_function->size()) / dd; - if(d < 0) d = 0; - if(d >= (int)m_color_function->size()) d = m_color_function->size() - 1; - *span++ = (*m_color_function)[d]; - ++(*m_interpolator); - } - while(--len); - } - - private: - interpolator_type* m_interpolator; - const GradientF* m_gradient_function; - const ColorF* m_color_function; - int m_d1; - int m_d2; - }; - - - - - //=====================================================gradient_linear_color - template - struct gradient_linear_color - { - typedef ColorT color_type; - - gradient_linear_color() {} - gradient_linear_color(const color_type& c1, const color_type& c2, - unsigned size = 256) : - m_c1(c1), m_c2(c2), m_size(size) {} - - unsigned size() const { return m_size; } - color_type operator [] (unsigned v) const - { - return m_c1.gradient(m_c2, double(v) / double(m_size - 1)); - } - - void colors(const color_type& c1, const color_type& c2, unsigned size = 256) - { - m_c1 = c1; - m_c2 = c2; - m_size = size; - } - - color_type m_c1; - color_type m_c2; - unsigned m_size; - }; - - - - - - - //==========================================================gradient_circle - class gradient_circle - { - // Actually the same as radial. Just for compatibility - public: - static AGG_INLINE int calculate(int x, int y, int) - { - return int(fast_sqrt(x*x + y*y)); - } - }; - - - //==========================================================gradient_radial - class gradient_radial - { - public: - static AGG_INLINE int calculate(int x, int y, int) - { - return int(fast_sqrt(x*x + y*y)); - } - }; - - //========================================================gradient_radial_d - class gradient_radial_d - { - public: - static AGG_INLINE int calculate(int x, int y, int) - { - return uround(sqrt(double(x)*double(x) + double(y)*double(y))); - } - }; - - //====================================================gradient_radial_focus - class gradient_radial_focus - { - public: - //--------------------------------------------------------------------- - gradient_radial_focus() : - m_r(100 * gradient_subpixel_scale), - m_fx(0), - m_fy(0) - { - update_values(); - } - - //--------------------------------------------------------------------- - gradient_radial_focus(double r, double fx, double fy) : - m_r (iround(r * gradient_subpixel_scale)), - m_fx(iround(fx * gradient_subpixel_scale)), - m_fy(iround(fy * gradient_subpixel_scale)) - { - update_values(); - } - - //--------------------------------------------------------------------- - void init(double r, double fx, double fy) - { - m_r = iround(r * gradient_subpixel_scale); - m_fx = iround(fx * gradient_subpixel_scale); - m_fy = iround(fy * gradient_subpixel_scale); - update_values(); - } - - //--------------------------------------------------------------------- - double radius() const { return double(m_r) / gradient_subpixel_scale; } - double focus_x() const { return double(m_fx) / gradient_subpixel_scale; } - double focus_y() const { return double(m_fy) / gradient_subpixel_scale; } - - //--------------------------------------------------------------------- - int calculate(int x, int y, int) const - { - double dx = x - m_fx; - double dy = y - m_fy; - double d2 = dx * m_fy - dy * m_fx; - double d3 = m_r2 * (dx * dx + dy * dy) - d2 * d2; - return iround((dx * m_fx + dy * m_fy + sqrt(fabs(d3))) * m_mul); - } - - private: - //--------------------------------------------------------------------- - void update_values() - { - // Calculate the invariant values. In case the focal center - // lies exactly on the gradient circle the divisor degenerates - // into zero. In this case we just move the focal center by - // one subpixel unit possibly in the direction to the origin (0,0) - // and calculate the values again. - //------------------------- - m_r2 = double(m_r) * double(m_r); - m_fx2 = double(m_fx) * double(m_fx); - m_fy2 = double(m_fy) * double(m_fy); - double d = (m_r2 - (m_fx2 + m_fy2)); - if(d == 0) - { - if(m_fx) { if(m_fx < 0) ++m_fx; else --m_fx; } - if(m_fy) { if(m_fy < 0) ++m_fy; else --m_fy; } - m_fx2 = double(m_fx) * double(m_fx); - m_fy2 = double(m_fy) * double(m_fy); - d = (m_r2 - (m_fx2 + m_fy2)); - } - m_mul = m_r / d; - } - - int m_r; - int m_fx; - int m_fy; - double m_r2; - double m_fx2; - double m_fy2; - double m_mul; - }; - - - //==============================================================gradient_x - class gradient_x - { - public: - static int calculate(int x, int, int) { return x; } - }; - - - //==============================================================gradient_y - class gradient_y - { - public: - static int calculate(int, int y, int) { return y; } - }; - - //========================================================gradient_diamond - class gradient_diamond - { - public: - static AGG_INLINE int calculate(int x, int y, int) - { - int ax = abs(x); - int ay = abs(y); - return ax > ay ? ax : ay; - } - }; - - //=============================================================gradient_xy - class gradient_xy - { - public: - static AGG_INLINE int calculate(int x, int y, int d) - { - return abs(x) * abs(y) / d; - } - }; - - //========================================================gradient_sqrt_xy - class gradient_sqrt_xy - { - public: - static AGG_INLINE int calculate(int x, int y, int) - { - return fast_sqrt(abs(x) * abs(y)); - } - }; - - //==========================================================gradient_conic - class gradient_conic - { - public: - static AGG_INLINE int calculate(int x, int y, int d) - { - return uround(fabs(atan2(double(y), double(x))) * double(d) / pi); - } - }; - - //=================================================gradient_repeat_adaptor - template class gradient_repeat_adaptor - { - public: - gradient_repeat_adaptor(const GradientF& gradient) : - m_gradient(&gradient) {} - - AGG_INLINE int calculate(int x, int y, int d) const - { - int ret = m_gradient->calculate(x, y, d) % d; - if(ret < 0) ret += d; - return ret; - } - - private: - const GradientF* m_gradient; - }; - - //================================================gradient_reflect_adaptor - template class gradient_reflect_adaptor - { - public: - gradient_reflect_adaptor(const GradientF& gradient) : - m_gradient(&gradient) {} - - AGG_INLINE int calculate(int x, int y, int d) const - { - int d2 = d << 1; - int ret = m_gradient->calculate(x, y, d) % d2; - if(ret < 0) ret += d2; - if(ret >= d) ret = d2 - ret; - return ret; - } - - private: - const GradientF* m_gradient; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_image_filter_gray.h corsix-th-0.62/agg/include/agg_span_image_filter_gray.h --- corsix-th-0.30/agg/include/agg_span_image_filter_gray.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_image_filter_gray.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,748 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -#ifndef AGG_SPAN_IMAGE_FILTER_GRAY_INCLUDED -#define AGG_SPAN_IMAGE_FILTER_GRAY_INCLUDED - -#include "agg_basics.h" -#include "agg_color_gray.h" -#include "agg_span_image_filter.h" - - -namespace agg -{ - - //==============================================span_image_filter_gray_nn - template - class span_image_filter_gray_nn : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_gray_nn() {} - span_image_filter_gray_nn(source_type& src, - interpolator_type& inter) : - base_type(src, inter, 0) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - do - { - base_type::interpolator().coordinates(&x, &y); - span->v = *(const value_type*) - base_type::source().span(x >> image_subpixel_shift, - y >> image_subpixel_shift, - 1); - span->a = base_mask; - ++span; - ++base_type::interpolator(); - } while(--len); - } - }; - - - - //=========================================span_image_filter_gray_bilinear - template - class span_image_filter_gray_bilinear : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_gray_bilinear() {} - span_image_filter_gray_bilinear(source_type& src, - interpolator_type& inter) : - base_type(src, inter, 0) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - calc_type fg; - const value_type *fg_ptr; - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - fg = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); - fg += *fg_ptr * (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); - - fg_ptr = (const value_type*)base_type::source().next_x(); - fg += *fg_ptr * x_hr * (image_subpixel_scale - y_hr); - - fg_ptr = (const value_type*)base_type::source().next_y(); - fg += *fg_ptr * (image_subpixel_scale - x_hr) * y_hr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - fg += *fg_ptr * x_hr * y_hr; - - span->v = value_type(fg >> (image_subpixel_shift * 2)); - span->a = base_mask; - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - //====================================span_image_filter_gray_bilinear_clip - template - class span_image_filter_gray_bilinear_clip : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_gray_bilinear_clip() {} - span_image_filter_gray_bilinear_clip(source_type& src, - const color_type& back_color, - interpolator_type& inter) : - base_type(src, inter, 0), - m_back_color(back_color) - {} - const color_type& background_color() const { return m_back_color; } - void background_color(const color_type& v) { m_back_color = v; } - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - calc_type fg; - calc_type src_alpha; - value_type back_v = m_back_color.v; - value_type back_a = m_back_color.a; - - const value_type *fg_ptr; - - int maxx = base_type::source().width() - 1; - int maxy = base_type::source().height() - 1; - - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - if(x_lr >= 0 && y_lr >= 0 && - x_lr < maxx && y_lr < maxy) - { - fg = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - fg_ptr = (const value_type*)base_type::source().row_ptr(y_lr) + x_lr; - - fg += *fg_ptr++ * (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); - fg += *fg_ptr++ * (image_subpixel_scale - y_hr) * x_hr; - - ++y_lr; - fg_ptr = (const value_type*)base_type::source().row_ptr(y_lr) + x_lr; - - fg += *fg_ptr++ * (image_subpixel_scale - x_hr) * y_hr; - fg += *fg_ptr++ * x_hr * y_hr; - - fg >>= image_subpixel_shift * 2; - src_alpha = base_mask; - } - else - { - unsigned weight; - if(x_lr < -1 || y_lr < -1 || - x_lr > maxx || y_lr > maxy) - { - fg = back_v; - src_alpha = back_a; - } - else - { - fg = - src_alpha = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - weight = (image_subpixel_scale - x_hr) * - (image_subpixel_scale - y_hr); - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg += weight * - *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); - src_alpha += weight * base_mask; - } - else - { - fg += back_v * weight; - src_alpha += back_a * weight; - } - - x_lr++; - - weight = x_hr * (image_subpixel_scale - y_hr); - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg += weight * - *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); - src_alpha += weight * base_mask; - } - else - { - fg += back_v * weight; - src_alpha += back_a * weight; - } - - x_lr--; - y_lr++; - - weight = (image_subpixel_scale - x_hr) * y_hr; - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg += weight * - *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); - src_alpha += weight * base_mask; - } - else - { - fg += back_v * weight; - src_alpha += back_a * weight; - } - - x_lr++; - - weight = x_hr * y_hr; - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg += weight * - *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); - src_alpha += weight * base_mask; - } - else - { - fg += back_v * weight; - src_alpha += back_a * weight; - } - - fg >>= image_subpixel_shift * 2; - src_alpha >>= image_subpixel_shift * 2; - } - } - - span->v = (value_type)fg; - span->a = (value_type)src_alpha; - ++span; - ++base_type::interpolator(); - - } while(--len); - } - private: - color_type m_back_color; - }; - - - - //==============================================span_image_filter_gray_2x2 - template - class span_image_filter_gray_2x2 : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_gray_2x2() {} - span_image_filter_gray_2x2(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, &filter) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - calc_type fg; - - const value_type *fg_ptr; - const int16* weight_array = base_type::filter().weight_array() + - ((base_type::filter().diameter()/2 - 1) << - image_subpixel_shift); - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - unsigned weight; - fg = image_filter_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); - weight = (weight_array[x_hr + image_subpixel_scale] * - weight_array[y_hr + image_subpixel_scale] + - image_filter_scale / 2) >> - image_filter_shift; - fg += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = (weight_array[x_hr] * - weight_array[y_hr + image_subpixel_scale] + - image_filter_scale / 2) >> - image_filter_shift; - fg += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_y(); - weight = (weight_array[x_hr + image_subpixel_scale] * - weight_array[y_hr] + - image_filter_scale / 2) >> - image_filter_shift; - fg += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = (weight_array[x_hr] * - weight_array[y_hr] + - image_filter_scale / 2) >> - image_filter_shift; - fg += weight * *fg_ptr; - - fg >>= image_filter_shift; - if(fg > base_mask) fg = base_mask; - - span->v = (value_type)fg; - span->a = base_mask; - ++span; - ++base_type::interpolator(); - } while(--len); - } - }; - - - - //==================================================span_image_filter_gray - template - class span_image_filter_gray : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_gray() {} - span_image_filter_gray(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, &filter) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - int fg; - const value_type *fg_ptr; - - unsigned diameter = base_type::filter().diameter(); - int start = base_type::filter().start(); - const int16* weight_array = base_type::filter().weight_array(); - - int x_count; - int weight_y; - - do - { - base_type::interpolator().coordinates(&x, &y); - - x -= base_type::filter_dx_int(); - y -= base_type::filter_dy_int(); - - int x_hr = x; - int y_hr = y; - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - fg = image_filter_scale / 2; - - int x_fract = x_hr & image_subpixel_mask; - unsigned y_count = diameter; - - y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask); - fg_ptr = (const value_type*)base_type::source().span(x_lr + start, - y_lr + start, - diameter); - for(;;) - { - x_count = diameter; - weight_y = weight_array[y_hr]; - x_hr = image_subpixel_mask - x_fract; - for(;;) - { - fg += *fg_ptr * - ((weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - image_filter_shift); - if(--x_count == 0) break; - x_hr += image_subpixel_scale; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - - if(--y_count == 0) break; - y_hr += image_subpixel_scale; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg >>= image_filter_shift; - if(fg < 0) fg = 0; - if(fg > base_mask) fg = base_mask; - span->v = (value_type)fg; - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - - //=========================================span_image_resample_gray_affine - template - class span_image_resample_gray_affine : - public span_image_resample_affine - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef span_image_resample_affine base_type; - typedef typename base_type::interpolator_type interpolator_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, - downscale_shift = image_filter_shift - }; - - //-------------------------------------------------------------------- - span_image_resample_gray_affine() {} - span_image_resample_gray_affine(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, filter) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - long_type fg; - - int diameter = base_type::filter().diameter(); - int filter_scale = diameter << image_subpixel_shift; - int radius_x = (diameter * base_type::m_rx) >> 1; - int radius_y = (diameter * base_type::m_ry) >> 1; - int len_x_lr = - (diameter * base_type::m_rx + image_subpixel_mask) >> - image_subpixel_shift; - - const int16* weight_array = base_type::filter().weight_array(); - - do - { - base_type::interpolator().coordinates(&x, &y); - - x += base_type::filter_dx_int() - radius_x; - y += base_type::filter_dy_int() - radius_y; - - fg = image_filter_scale / 2; - - int y_lr = y >> image_subpixel_shift; - int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * - base_type::m_ry_inv) >> - image_subpixel_shift; - int total_weight = 0; - int x_lr = x >> image_subpixel_shift; - int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * - base_type::m_rx_inv) >> - image_subpixel_shift; - - int x_hr2 = x_hr; - const value_type* fg_ptr = - (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); - for(;;) - { - int weight_y = weight_array[y_hr]; - x_hr = x_hr2; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - downscale_shift; - - fg += *fg_ptr * weight; - total_weight += weight; - x_hr += base_type::m_rx_inv; - if(x_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - y_hr += base_type::m_ry_inv; - if(y_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg /= total_weight; - if(fg < 0) fg = 0; - if(fg > base_mask) fg = base_mask; - - span->v = (value_type)fg; - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - } while(--len); - } - }; - - - - //================================================span_image_resample_gray - template - class span_image_resample_gray : - public span_image_resample - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef Interpolator interpolator_type; - typedef span_image_resample base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, - downscale_shift = image_filter_shift - }; - - //-------------------------------------------------------------------- - span_image_resample_gray() {} - span_image_resample_gray(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, filter) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - long_type fg; - - int diameter = base_type::filter().diameter(); - int filter_scale = diameter << image_subpixel_shift; - - const int16* weight_array = base_type::filter().weight_array(); - do - { - int rx; - int ry; - int rx_inv = image_subpixel_scale; - int ry_inv = image_subpixel_scale; - base_type::interpolator().coordinates(&x, &y); - base_type::interpolator().local_scale(&rx, &ry); - base_type::adjust_scale(&rx, &ry); - - rx_inv = image_subpixel_scale * image_subpixel_scale / rx; - ry_inv = image_subpixel_scale * image_subpixel_scale / ry; - - int radius_x = (diameter * rx) >> 1; - int radius_y = (diameter * ry) >> 1; - int len_x_lr = - (diameter * rx + image_subpixel_mask) >> - image_subpixel_shift; - - x += base_type::filter_dx_int() - radius_x; - y += base_type::filter_dy_int() - radius_y; - - fg = image_filter_scale / 2; - - int y_lr = y >> image_subpixel_shift; - int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * - ry_inv) >> - image_subpixel_shift; - int total_weight = 0; - int x_lr = x >> image_subpixel_shift; - int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * - rx_inv) >> - image_subpixel_shift; - int x_hr2 = x_hr; - const value_type* fg_ptr = - (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); - - for(;;) - { - int weight_y = weight_array[y_hr]; - x_hr = x_hr2; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - downscale_shift; - fg += *fg_ptr * weight; - total_weight += weight; - x_hr += rx_inv; - if(x_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - y_hr += ry_inv; - if(y_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg /= total_weight; - if(fg < 0) fg = 0; - if(fg > base_mask) fg = base_mask; - - span->v = (value_type)fg; - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - } while(--len); - } - }; - - -} - - -#endif - - - diff -Nru corsix-th-0.30/agg/include/agg_span_image_filter.h corsix-th-0.62/agg/include/agg_span_image_filter.h --- corsix-th-0.30/agg/include/agg_span_image_filter.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_image_filter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,246 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Image transformations with filtering. Span generator base class -// -//---------------------------------------------------------------------------- -#ifndef AGG_SPAN_IMAGE_FILTER_INCLUDED -#define AGG_SPAN_IMAGE_FILTER_INCLUDED - -#include "agg_basics.h" -#include "agg_image_filters.h" -#include "agg_span_interpolator_linear.h" - -namespace agg -{ - - //-------------------------------------------------------span_image_filter - template class span_image_filter - { - public: - typedef Source source_type; - typedef Interpolator interpolator_type; - - //-------------------------------------------------------------------- - span_image_filter() {} - span_image_filter(source_type& src, - interpolator_type& interpolator, - const image_filter_lut* filter) : - m_src(&src), - m_interpolator(&interpolator), - m_filter(filter), - m_dx_dbl(0.5), - m_dy_dbl(0.5), - m_dx_int(image_subpixel_scale / 2), - m_dy_int(image_subpixel_scale / 2) - {} - void attach(source_type& v) { m_src = &v; } - - //-------------------------------------------------------------------- - source_type& source() { return *m_src; } - const source_type& source() const { return *m_src; } - const image_filter_lut& filter() const { return *m_filter; } - int filter_dx_int() const { return m_dx_int; } - int filter_dy_int() const { return m_dy_int; } - double filter_dx_dbl() const { return m_dx_dbl; } - double filter_dy_dbl() const { return m_dy_dbl; } - - //-------------------------------------------------------------------- - void interpolator(interpolator_type& v) { m_interpolator = &v; } - void filter(const image_filter_lut& v) { m_filter = &v; } - void filter_offset(double dx, double dy) - { - m_dx_dbl = dx; - m_dy_dbl = dy; - m_dx_int = iround(dx * image_subpixel_scale); - m_dy_int = iround(dy * image_subpixel_scale); - } - void filter_offset(double d) { filter_offset(d, d); } - - //-------------------------------------------------------------------- - interpolator_type& interpolator() { return *m_interpolator; } - - //-------------------------------------------------------------------- - void prepare() {} - - //-------------------------------------------------------------------- - private: - source_type* m_src; - interpolator_type* m_interpolator; - const image_filter_lut* m_filter; - double m_dx_dbl; - double m_dy_dbl; - unsigned m_dx_int; - unsigned m_dy_int; - }; - - - - - //==============================================span_image_resample_affine - template - class span_image_resample_affine : - public span_image_filter > - { - public: - typedef Source source_type; - typedef span_interpolator_linear interpolator_type; - typedef span_image_filter base_type; - - //-------------------------------------------------------------------- - span_image_resample_affine() : - m_scale_limit(200.0), - m_blur_x(1.0), - m_blur_y(1.0) - {} - - //-------------------------------------------------------------------- - span_image_resample_affine(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, &filter), - m_scale_limit(200.0), - m_blur_x(1.0), - m_blur_y(1.0) - {} - - - //-------------------------------------------------------------------- - int scale_limit() const { return uround(m_scale_limit); } - void scale_limit(int v) { m_scale_limit = v; } - - //-------------------------------------------------------------------- - double blur_x() const { return m_blur_x; } - double blur_y() const { return m_blur_y; } - void blur_x(double v) { m_blur_x = v; } - void blur_y(double v) { m_blur_y = v; } - void blur(double v) { m_blur_x = m_blur_y = v; } - - //-------------------------------------------------------------------- - void prepare() - { - double scale_x; - double scale_y; - - base_type::interpolator().transformer().scaling_abs(&scale_x, &scale_y); - - if(scale_x * scale_y > m_scale_limit) - { - scale_x = scale_x * m_scale_limit / (scale_x * scale_y); - scale_y = scale_y * m_scale_limit / (scale_x * scale_y); - } - - if(scale_x < 1) scale_x = 1; - if(scale_y < 1) scale_y = 1; - - if(scale_x > m_scale_limit) scale_x = m_scale_limit; - if(scale_y > m_scale_limit) scale_y = m_scale_limit; - - scale_x *= m_blur_x; - scale_y *= m_blur_y; - - if(scale_x < 1) scale_x = 1; - if(scale_y < 1) scale_y = 1; - - m_rx = uround( scale_x * double(image_subpixel_scale)); - m_rx_inv = uround(1.0/scale_x * double(image_subpixel_scale)); - - m_ry = uround( scale_y * double(image_subpixel_scale)); - m_ry_inv = uround(1.0/scale_y * double(image_subpixel_scale)); - } - - protected: - int m_rx; - int m_ry; - int m_rx_inv; - int m_ry_inv; - - private: - double m_scale_limit; - double m_blur_x; - double m_blur_y; - }; - - - - //=====================================================span_image_resample - template - class span_image_resample : - public span_image_filter - { - public: - typedef Source source_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - - //-------------------------------------------------------------------- - span_image_resample() : - m_scale_limit(20), - m_blur_x(image_subpixel_scale), - m_blur_y(image_subpixel_scale) - {} - - //-------------------------------------------------------------------- - span_image_resample(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, &filter), - m_scale_limit(20), - m_blur_x(image_subpixel_scale), - m_blur_y(image_subpixel_scale) - {} - - //-------------------------------------------------------------------- - int scale_limit() const { return m_scale_limit; } - void scale_limit(int v) { m_scale_limit = v; } - - //-------------------------------------------------------------------- - double blur_x() const { return double(m_blur_x) / double(image_subpixel_scale); } - double blur_y() const { return double(m_blur_y) / double(image_subpixel_scale); } - void blur_x(double v) { m_blur_x = uround(v * double(image_subpixel_scale)); } - void blur_y(double v) { m_blur_y = uround(v * double(image_subpixel_scale)); } - void blur(double v) { m_blur_x = - m_blur_y = uround(v * double(image_subpixel_scale)); } - - protected: - AGG_INLINE void adjust_scale(int* rx, int* ry) - { - if(*rx < image_subpixel_scale) *rx = image_subpixel_scale; - if(*ry < image_subpixel_scale) *ry = image_subpixel_scale; - if(*rx > image_subpixel_scale * m_scale_limit) - { - *rx = image_subpixel_scale * m_scale_limit; - } - if(*ry > image_subpixel_scale * m_scale_limit) - { - *ry = image_subpixel_scale * m_scale_limit; - } - *rx = (*rx * m_blur_x) >> image_subpixel_shift; - *ry = (*ry * m_blur_y) >> image_subpixel_shift; - if(*rx < image_subpixel_scale) *rx = image_subpixel_scale; - if(*ry < image_subpixel_scale) *ry = image_subpixel_scale; - } - - int m_scale_limit; - int m_blur_x; - int m_blur_y; - }; - - - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_image_filter_rgba.h corsix-th-0.62/agg/include/agg_span_image_filter_rgba.h --- corsix-th-0.30/agg/include/agg_span_image_filter_rgba.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_image_filter_rgba.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,920 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -#ifndef AGG_SPAN_IMAGE_FILTER_RGBA_INCLUDED -#define AGG_SPAN_IMAGE_FILTER_RGBA_INCLUDED - -#include "agg_basics.h" -#include "agg_color_rgba.h" -#include "agg_span_image_filter.h" - - -namespace agg -{ - - //==============================================span_image_filter_rgba_nn - template - class span_image_filter_rgba_nn : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgba_nn() {} - span_image_filter_rgba_nn(source_type& src, - interpolator_type& inter) : - base_type(src, inter, 0) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - do - { - base_type::interpolator().coordinates(&x, &y); - const value_type* fg_ptr = (const value_type*) - base_type::source().span(x >> image_subpixel_shift, - y >> image_subpixel_shift, - 1); - span->r = fg_ptr[order_type::R]; - span->g = fg_ptr[order_type::G]; - span->b = fg_ptr[order_type::B]; - span->a = fg_ptr[order_type::A]; - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - - //=========================================span_image_filter_rgba_bilinear - template - class span_image_filter_rgba_bilinear : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgba_bilinear() {} - span_image_filter_rgba_bilinear(source_type& src, - interpolator_type& inter) : - base_type(src, inter, 0) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - calc_type fg[4]; - const value_type *fg_ptr; - - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - unsigned weight; - - fg[0] = - fg[1] = - fg[2] = - fg[3] = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); - weight = (image_subpixel_scale - x_hr) * - (image_subpixel_scale - y_hr); - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = x_hr * (image_subpixel_scale - y_hr); - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_y(); - weight = (image_subpixel_scale - x_hr) * y_hr; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = x_hr * y_hr; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - span->r = value_type(fg[order_type::R] >> (image_subpixel_shift * 2)); - span->g = value_type(fg[order_type::G] >> (image_subpixel_shift * 2)); - span->b = value_type(fg[order_type::B] >> (image_subpixel_shift * 2)); - span->a = value_type(fg[order_type::A] >> (image_subpixel_shift * 2)); - - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - //====================================span_image_filter_rgba_bilinear_clip - template - class span_image_filter_rgba_bilinear_clip : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgba_bilinear_clip() {} - span_image_filter_rgba_bilinear_clip(source_type& src, - const color_type& back_color, - interpolator_type& inter) : - base_type(src, inter, 0), - m_back_color(back_color) - {} - const color_type& background_color() const { return m_back_color; } - void background_color(const color_type& v) { m_back_color = v; } - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - calc_type fg[4]; - value_type back_r = m_back_color.r; - value_type back_g = m_back_color.g; - value_type back_b = m_back_color.b; - value_type back_a = m_back_color.a; - - const value_type *fg_ptr; - int maxx = base_type::source().width() - 1; - int maxy = base_type::source().height() - 1; - - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - unsigned weight; - - if(x_lr >= 0 && y_lr >= 0 && - x_lr < maxx && y_lr < maxy) - { - fg[0] = - fg[1] = - fg[2] = - fg[3] = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + (x_lr << 2); - - weight = (image_subpixel_scale - x_hr) * - (image_subpixel_scale - y_hr); - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr++; - - weight = x_hr * (image_subpixel_scale - y_hr); - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr++; - - ++y_lr; - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + (x_lr << 2); - - weight = (image_subpixel_scale - x_hr) * y_hr; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr++; - - weight = x_hr * y_hr; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr++; - - fg[0] >>= image_subpixel_shift * 2; - fg[1] >>= image_subpixel_shift * 2; - fg[2] >>= image_subpixel_shift * 2; - fg[3] >>= image_subpixel_shift * 2; - } - else - { - if(x_lr < -1 || y_lr < -1 || - x_lr > maxx || y_lr > maxy) - { - fg[order_type::R] = back_r; - fg[order_type::G] = back_g; - fg[order_type::B] = back_b; - fg[order_type::A] = back_a; - } - else - { - fg[0] = - fg[1] = - fg[2] = - fg[3] = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - weight = (image_subpixel_scale - x_hr) * - (image_subpixel_scale - y_hr); - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + (x_lr << 2); - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr++; - } - else - { - fg[order_type::R] += back_r * weight; - fg[order_type::G] += back_g * weight; - fg[order_type::B] += back_b * weight; - fg[order_type::A] += back_a * weight; - } - - x_lr++; - - weight = x_hr * (image_subpixel_scale - y_hr); - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + (x_lr << 2); - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr++; - } - else - { - fg[order_type::R] += back_r * weight; - fg[order_type::G] += back_g * weight; - fg[order_type::B] += back_b * weight; - fg[order_type::A] += back_a * weight; - } - - x_lr--; - y_lr++; - - weight = (image_subpixel_scale - x_hr) * y_hr; - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + (x_lr << 2); - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr++; - } - else - { - fg[order_type::R] += back_r * weight; - fg[order_type::G] += back_g * weight; - fg[order_type::B] += back_b * weight; - fg[order_type::A] += back_a * weight; - } - - x_lr++; - - weight = x_hr * y_hr; - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + (x_lr << 2); - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr++; - } - else - { - fg[order_type::R] += back_r * weight; - fg[order_type::G] += back_g * weight; - fg[order_type::B] += back_b * weight; - fg[order_type::A] += back_a * weight; - } - - fg[0] >>= image_subpixel_shift * 2; - fg[1] >>= image_subpixel_shift * 2; - fg[2] >>= image_subpixel_shift * 2; - fg[3] >>= image_subpixel_shift * 2; - } - } - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = (value_type)fg[order_type::A]; - ++span; - ++base_type::interpolator(); - - } while(--len); - } - private: - color_type m_back_color; - }; - - - //==============================================span_image_filter_rgba_2x2 - template - class span_image_filter_rgba_2x2 : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgba_2x2() {} - span_image_filter_rgba_2x2(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, &filter) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - calc_type fg[4]; - - const value_type *fg_ptr; - const int16* weight_array = base_type::filter().weight_array() + - ((base_type::filter().diameter()/2 - 1) << - image_subpixel_shift); - - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - unsigned weight; - fg[0] = fg[1] = fg[2] = fg[3] = image_filter_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); - weight = (weight_array[x_hr + image_subpixel_scale] * - weight_array[y_hr + image_subpixel_scale] + - image_filter_scale / 2) >> - image_filter_shift; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = (weight_array[x_hr] * - weight_array[y_hr + image_subpixel_scale] + - image_filter_scale / 2) >> - image_filter_shift; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_y(); - weight = (weight_array[x_hr + image_subpixel_scale] * - weight_array[y_hr] + - image_filter_scale / 2) >> - image_filter_shift; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = (weight_array[x_hr] * - weight_array[y_hr] + - image_filter_scale / 2) >> - image_filter_shift; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - fg[0] >>= image_filter_shift; - fg[1] >>= image_filter_shift; - fg[2] >>= image_filter_shift; - fg[3] >>= image_filter_shift; - - if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; - if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; - if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; - if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = (value_type)fg[order_type::A]; - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - - //==================================================span_image_filter_rgba - template - class span_image_filter_rgba : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgba() {} - span_image_filter_rgba(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, &filter) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - int fg[4]; - const value_type *fg_ptr; - - unsigned diameter = base_type::filter().diameter(); - int start = base_type::filter().start(); - const int16* weight_array = base_type::filter().weight_array(); - - int x_count; - int weight_y; - - do - { - base_type::interpolator().coordinates(&x, &y); - - x -= base_type::filter_dx_int(); - y -= base_type::filter_dy_int(); - - int x_hr = x; - int y_hr = y; - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - fg[0] = fg[1] = fg[2] = fg[3] = image_filter_scale / 2; - - int x_fract = x_hr & image_subpixel_mask; - unsigned y_count = diameter; - - y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask); - fg_ptr = (const value_type*)base_type::source().span(x_lr + start, - y_lr + start, - diameter); - for(;;) - { - x_count = diameter; - weight_y = weight_array[y_hr]; - x_hr = image_subpixel_mask - x_fract; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - image_filter_shift; - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - fg[3] += weight * *fg_ptr; - - if(--x_count == 0) break; - x_hr += image_subpixel_scale; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - - if(--y_count == 0) break; - y_hr += image_subpixel_scale; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg[0] >>= image_filter_shift; - fg[1] >>= image_filter_shift; - fg[2] >>= image_filter_shift; - fg[3] >>= image_filter_shift; - - if(fg[0] < 0) fg[0] = 0; - if(fg[1] < 0) fg[1] = 0; - if(fg[2] < 0) fg[2] = 0; - if(fg[3] < 0) fg[3] = 0; - - if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; - if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; - if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; - if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = (value_type)fg[order_type::A]; - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - - //========================================span_image_resample_rgba_affine - template - class span_image_resample_rgba_affine : - public span_image_resample_affine - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef span_image_resample_affine base_type; - typedef typename base_type::interpolator_type interpolator_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, - downscale_shift = image_filter_shift - }; - - //-------------------------------------------------------------------- - span_image_resample_rgba_affine() {} - span_image_resample_rgba_affine(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, filter) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - long_type fg[4]; - - int diameter = base_type::filter().diameter(); - int filter_scale = diameter << image_subpixel_shift; - int radius_x = (diameter * base_type::m_rx) >> 1; - int radius_y = (diameter * base_type::m_ry) >> 1; - int len_x_lr = - (diameter * base_type::m_rx + image_subpixel_mask) >> - image_subpixel_shift; - - const int16* weight_array = base_type::filter().weight_array(); - - do - { - base_type::interpolator().coordinates(&x, &y); - - x += base_type::filter_dx_int() - radius_x; - y += base_type::filter_dy_int() - radius_y; - - fg[0] = fg[1] = fg[2] = fg[3] = image_filter_scale / 2; - - int y_lr = y >> image_subpixel_shift; - int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * - base_type::m_ry_inv) >> - image_subpixel_shift; - int total_weight = 0; - int x_lr = x >> image_subpixel_shift; - int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * - base_type::m_rx_inv) >> - image_subpixel_shift; - - int x_hr2 = x_hr; - const value_type* fg_ptr = - (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); - for(;;) - { - int weight_y = weight_array[y_hr]; - x_hr = x_hr2; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - downscale_shift; - - fg[0] += *fg_ptr++ * weight; - fg[1] += *fg_ptr++ * weight; - fg[2] += *fg_ptr++ * weight; - fg[3] += *fg_ptr++ * weight; - total_weight += weight; - x_hr += base_type::m_rx_inv; - if(x_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - y_hr += base_type::m_ry_inv; - if(y_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg[0] /= total_weight; - fg[1] /= total_weight; - fg[2] /= total_weight; - fg[3] /= total_weight; - - if(fg[0] < 0) fg[0] = 0; - if(fg[1] < 0) fg[1] = 0; - if(fg[2] < 0) fg[2] = 0; - if(fg[3] < 0) fg[3] = 0; - - if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; - if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; - if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; - if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = (value_type)fg[order_type::A]; - - ++span; - ++base_type::interpolator(); - } while(--len); - } - }; - - - - //==============================================span_image_resample_rgba - template - class span_image_resample_rgba : - public span_image_resample - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_resample base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, - downscale_shift = image_filter_shift - }; - - //-------------------------------------------------------------------- - span_image_resample_rgba() {} - span_image_resample_rgba(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, filter) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - long_type fg[4]; - - int diameter = base_type::filter().diameter(); - int filter_scale = diameter << image_subpixel_shift; - - const int16* weight_array = base_type::filter().weight_array(); - do - { - int rx; - int ry; - int rx_inv = image_subpixel_scale; - int ry_inv = image_subpixel_scale; - base_type::interpolator().coordinates(&x, &y); - base_type::interpolator().local_scale(&rx, &ry); - base_type::adjust_scale(&rx, &ry); - - rx_inv = image_subpixel_scale * image_subpixel_scale / rx; - ry_inv = image_subpixel_scale * image_subpixel_scale / ry; - - int radius_x = (diameter * rx) >> 1; - int radius_y = (diameter * ry) >> 1; - int len_x_lr = - (diameter * rx + image_subpixel_mask) >> - image_subpixel_shift; - - x += base_type::filter_dx_int() - radius_x; - y += base_type::filter_dy_int() - radius_y; - - fg[0] = fg[1] = fg[2] = fg[3] = image_filter_scale / 2; - - int y_lr = y >> image_subpixel_shift; - int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * - ry_inv) >> - image_subpixel_shift; - int total_weight = 0; - int x_lr = x >> image_subpixel_shift; - int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * - rx_inv) >> - image_subpixel_shift; - int x_hr2 = x_hr; - const value_type* fg_ptr = - (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); - - for(;;) - { - int weight_y = weight_array[y_hr]; - x_hr = x_hr2; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - downscale_shift; - fg[0] += *fg_ptr++ * weight; - fg[1] += *fg_ptr++ * weight; - fg[2] += *fg_ptr++ * weight; - fg[3] += *fg_ptr++ * weight; - total_weight += weight; - x_hr += rx_inv; - if(x_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - y_hr += ry_inv; - if(y_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg[0] /= total_weight; - fg[1] /= total_weight; - fg[2] /= total_weight; - fg[3] /= total_weight; - - if(fg[0] < 0) fg[0] = 0; - if(fg[1] < 0) fg[1] = 0; - if(fg[2] < 0) fg[2] = 0; - if(fg[3] < 0) fg[3] = 0; - - if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; - if(fg[order_type::R] > fg[order_type::R]) fg[order_type::R] = fg[order_type::R]; - if(fg[order_type::G] > fg[order_type::G]) fg[order_type::G] = fg[order_type::G]; - if(fg[order_type::B] > fg[order_type::B]) fg[order_type::B] = fg[order_type::B]; - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = (value_type)fg[order_type::A]; - - ++span; - ++base_type::interpolator(); - } while(--len); - } - }; - - -} - - -#endif - - - diff -Nru corsix-th-0.30/agg/include/agg_span_image_filter_rgb.h corsix-th-0.62/agg/include/agg_span_image_filter_rgb.h --- corsix-th-0.30/agg/include/agg_span_image_filter_rgb.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_image_filter_rgb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,892 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -#ifndef AGG_SPAN_IMAGE_FILTER_RGB_INCLUDED -#define AGG_SPAN_IMAGE_FILTER_RGB_INCLUDED - -#include "agg_basics.h" -#include "agg_color_rgba.h" -#include "agg_span_image_filter.h" - - -namespace agg -{ - - //===============================================span_image_filter_rgb_nn - template - class span_image_filter_rgb_nn : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgb_nn() {} - span_image_filter_rgb_nn(source_type& src, - interpolator_type& inter) : - base_type(src, inter, 0) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - do - { - base_type::interpolator().coordinates(&x, &y); - const value_type* fg_ptr = (const value_type*) - base_type::source().span(x >> image_subpixel_shift, - y >> image_subpixel_shift, - 1); - span->r = fg_ptr[order_type::R]; - span->g = fg_ptr[order_type::G]; - span->b = fg_ptr[order_type::B]; - span->a = base_mask; - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - - //==========================================span_image_filter_rgb_bilinear - template - class span_image_filter_rgb_bilinear : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgb_bilinear() {} - span_image_filter_rgb_bilinear(source_type& src, - interpolator_type& inter) : - base_type(src, inter, 0) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - calc_type fg[3]; - const value_type *fg_ptr; - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - unsigned weight; - - fg[0] = - fg[1] = - fg[2] = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); - weight = (image_subpixel_scale - x_hr) * - (image_subpixel_scale - y_hr); - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = x_hr * (image_subpixel_scale - y_hr); - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_y(); - weight = (image_subpixel_scale - x_hr) * y_hr; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = x_hr * y_hr; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - span->r = value_type(fg[order_type::R] >> (image_subpixel_shift * 2)); - span->g = value_type(fg[order_type::G] >> (image_subpixel_shift * 2)); - span->b = value_type(fg[order_type::B] >> (image_subpixel_shift * 2)); - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - - //=====================================span_image_filter_rgb_bilinear_clip - template - class span_image_filter_rgb_bilinear_clip : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgb_bilinear_clip() {} - span_image_filter_rgb_bilinear_clip(source_type& src, - const color_type& back_color, - interpolator_type& inter) : - base_type(src, inter, 0), - m_back_color(back_color) - {} - const color_type& background_color() const { return m_back_color; } - void background_color(const color_type& v) { m_back_color = v; } - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - calc_type fg[3]; - calc_type src_alpha; - value_type back_r = m_back_color.r; - value_type back_g = m_back_color.g; - value_type back_b = m_back_color.b; - value_type back_a = m_back_color.a; - - const value_type *fg_ptr; - - int maxx = base_type::source().width() - 1; - int maxy = base_type::source().height() - 1; - - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - unsigned weight; - - if(x_lr >= 0 && y_lr >= 0 && - x_lr < maxx && y_lr < maxy) - { - fg[0] = - fg[1] = - fg[2] = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; - - weight = (image_subpixel_scale - x_hr) * - (image_subpixel_scale - y_hr); - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - - weight = x_hr * (image_subpixel_scale - y_hr); - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - - ++y_lr; - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; - - weight = (image_subpixel_scale - x_hr) * y_hr; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - - weight = x_hr * y_hr; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - - fg[0] >>= image_subpixel_shift * 2; - fg[1] >>= image_subpixel_shift * 2; - fg[2] >>= image_subpixel_shift * 2; - src_alpha = base_mask; - } - else - { - if(x_lr < -1 || y_lr < -1 || - x_lr > maxx || y_lr > maxy) - { - fg[order_type::R] = back_r; - fg[order_type::G] = back_g; - fg[order_type::B] = back_b; - src_alpha = back_a; - } - else - { - fg[0] = - fg[1] = - fg[2] = - src_alpha = image_subpixel_scale * image_subpixel_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - weight = (image_subpixel_scale - x_hr) * - (image_subpixel_scale - y_hr); - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - src_alpha += weight * base_mask; - } - else - { - fg[order_type::R] += back_r * weight; - fg[order_type::G] += back_g * weight; - fg[order_type::B] += back_b * weight; - src_alpha += back_a * weight; - } - - x_lr++; - - weight = x_hr * (image_subpixel_scale - y_hr); - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - src_alpha += weight * base_mask; - } - else - { - fg[order_type::R] += back_r * weight; - fg[order_type::G] += back_g * weight; - fg[order_type::B] += back_b * weight; - src_alpha += back_a * weight; - } - - x_lr--; - y_lr++; - - weight = (image_subpixel_scale - x_hr) * y_hr; - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - src_alpha += weight * base_mask; - } - else - { - fg[order_type::R] += back_r * weight; - fg[order_type::G] += back_g * weight; - fg[order_type::B] += back_b * weight; - src_alpha += back_a * weight; - } - - x_lr++; - - weight = x_hr * y_hr; - if(x_lr >= 0 && y_lr >= 0 && - x_lr <= maxx && y_lr <= maxy) - { - fg_ptr = (const value_type*) - base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr++; - src_alpha += weight * base_mask; - } - else - { - fg[order_type::R] += back_r * weight; - fg[order_type::G] += back_g * weight; - fg[order_type::B] += back_b * weight; - src_alpha += back_a * weight; - } - - fg[0] >>= image_subpixel_shift * 2; - fg[1] >>= image_subpixel_shift * 2; - fg[2] >>= image_subpixel_shift * 2; - src_alpha >>= image_subpixel_shift * 2; - } - } - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = (value_type)src_alpha; - ++span; - ++base_type::interpolator(); - - } while(--len); - } - private: - color_type m_back_color; - }; - - - - //===============================================span_image_filter_rgb_2x2 - template - class span_image_filter_rgb_2x2 : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgb_2x2() {} - span_image_filter_rgb_2x2(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, &filter) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - calc_type fg[3]; - - const value_type *fg_ptr; - const int16* weight_array = base_type::filter().weight_array() + - ((base_type::filter().diameter()/2 - 1) << - image_subpixel_shift); - do - { - int x_hr; - int y_hr; - - base_type::interpolator().coordinates(&x_hr, &y_hr); - - x_hr -= base_type::filter_dx_int(); - y_hr -= base_type::filter_dy_int(); - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - unsigned weight; - fg[0] = fg[1] = fg[2] = image_filter_scale / 2; - - x_hr &= image_subpixel_mask; - y_hr &= image_subpixel_mask; - - fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); - weight = (weight_array[x_hr + image_subpixel_scale] * - weight_array[y_hr + image_subpixel_scale] + - image_filter_scale / 2) >> - image_filter_shift; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = (weight_array[x_hr] * - weight_array[y_hr + image_subpixel_scale] + - image_filter_scale / 2) >> - image_filter_shift; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_y(); - weight = (weight_array[x_hr + image_subpixel_scale] * - weight_array[y_hr] + - image_filter_scale / 2) >> - image_filter_shift; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - fg_ptr = (const value_type*)base_type::source().next_x(); - weight = (weight_array[x_hr] * - weight_array[y_hr] + - image_filter_scale / 2) >> - image_filter_shift; - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - fg[0] >>= image_filter_shift; - fg[1] >>= image_filter_shift; - fg[2] >>= image_filter_shift; - - if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask; - if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask; - if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask; - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - - //===================================================span_image_filter_rgb - template - class span_image_filter_rgb : - public span_image_filter - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_filter base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask - }; - - //-------------------------------------------------------------------- - span_image_filter_rgb() {} - span_image_filter_rgb(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, &filter) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - int fg[3]; - const value_type *fg_ptr; - - unsigned diameter = base_type::filter().diameter(); - int start = base_type::filter().start(); - const int16* weight_array = base_type::filter().weight_array(); - - int x_count; - int weight_y; - - do - { - base_type::interpolator().coordinates(&x, &y); - - x -= base_type::filter_dx_int(); - y -= base_type::filter_dy_int(); - - int x_hr = x; - int y_hr = y; - - int x_lr = x_hr >> image_subpixel_shift; - int y_lr = y_hr >> image_subpixel_shift; - - fg[0] = fg[1] = fg[2] = image_filter_scale / 2; - - int x_fract = x_hr & image_subpixel_mask; - unsigned y_count = diameter; - - y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask); - fg_ptr = (const value_type*)base_type::source().span(x_lr + start, - y_lr + start, - diameter); - for(;;) - { - x_count = diameter; - weight_y = weight_array[y_hr]; - x_hr = image_subpixel_mask - x_fract; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - image_filter_shift; - - fg[0] += weight * *fg_ptr++; - fg[1] += weight * *fg_ptr++; - fg[2] += weight * *fg_ptr; - - if(--x_count == 0) break; - x_hr += image_subpixel_scale; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - - if(--y_count == 0) break; - y_hr += image_subpixel_scale; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg[0] >>= image_filter_shift; - fg[1] >>= image_filter_shift; - fg[2] >>= image_filter_shift; - - if(fg[0] < 0) fg[0] = 0; - if(fg[1] < 0) fg[1] = 0; - if(fg[2] < 0) fg[2] = 0; - - if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask; - if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask; - if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask; - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - - } while(--len); - } - }; - - - - //==========================================span_image_resample_rgb_affine - template - class span_image_resample_rgb_affine : - public span_image_resample_affine - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef span_image_resample_affine base_type; - typedef typename base_type::interpolator_type interpolator_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, - downscale_shift = image_filter_shift - }; - - //-------------------------------------------------------------------- - span_image_resample_rgb_affine() {} - span_image_resample_rgb_affine(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, filter) - {} - - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - long_type fg[3]; - - int diameter = base_type::filter().diameter(); - int filter_scale = diameter << image_subpixel_shift; - int radius_x = (diameter * base_type::m_rx) >> 1; - int radius_y = (diameter * base_type::m_ry) >> 1; - int len_x_lr = - (diameter * base_type::m_rx + image_subpixel_mask) >> - image_subpixel_shift; - - const int16* weight_array = base_type::filter().weight_array(); - - do - { - base_type::interpolator().coordinates(&x, &y); - - x += base_type::filter_dx_int() - radius_x; - y += base_type::filter_dy_int() - radius_y; - - fg[0] = fg[1] = fg[2] = image_filter_scale / 2; - - int y_lr = y >> image_subpixel_shift; - int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * - base_type::m_ry_inv) >> - image_subpixel_shift; - int total_weight = 0; - int x_lr = x >> image_subpixel_shift; - int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * - base_type::m_rx_inv) >> - image_subpixel_shift; - - int x_hr2 = x_hr; - const value_type* fg_ptr = - (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); - for(;;) - { - int weight_y = weight_array[y_hr]; - x_hr = x_hr2; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - downscale_shift; - - fg[0] += *fg_ptr++ * weight; - fg[1] += *fg_ptr++ * weight; - fg[2] += *fg_ptr * weight; - total_weight += weight; - x_hr += base_type::m_rx_inv; - if(x_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - y_hr += base_type::m_ry_inv; - if(y_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg[0] /= total_weight; - fg[1] /= total_weight; - fg[2] /= total_weight; - - if(fg[0] < 0) fg[0] = 0; - if(fg[1] < 0) fg[1] = 0; - if(fg[2] < 0) fg[2] = 0; - - if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask; - if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask; - if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask; - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - } while(--len); - } - }; - - - - //=================================================span_image_resample_rgb - template - class span_image_resample_rgb : - public span_image_resample - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef Interpolator interpolator_type; - typedef span_image_resample base_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::long_type long_type; - enum base_scale_e - { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, - downscale_shift = image_filter_shift - }; - - //-------------------------------------------------------------------- - span_image_resample_rgb() {} - span_image_resample_rgb(source_type& src, - interpolator_type& inter, - const image_filter_lut& filter) : - base_type(src, inter, filter) - {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - long_type fg[3]; - - int diameter = base_type::filter().diameter(); - int filter_scale = diameter << image_subpixel_shift; - - const int16* weight_array = base_type::filter().weight_array(); - do - { - int rx; - int ry; - int rx_inv = image_subpixel_scale; - int ry_inv = image_subpixel_scale; - base_type::interpolator().coordinates(&x, &y); - base_type::interpolator().local_scale(&rx, &ry); - base_type::adjust_scale(&rx, &ry); - - rx_inv = image_subpixel_scale * image_subpixel_scale / rx; - ry_inv = image_subpixel_scale * image_subpixel_scale / ry; - - int radius_x = (diameter * rx) >> 1; - int radius_y = (diameter * ry) >> 1; - int len_x_lr = - (diameter * rx + image_subpixel_mask) >> - image_subpixel_shift; - - x += base_type::filter_dx_int() - radius_x; - y += base_type::filter_dy_int() - radius_y; - - fg[0] = fg[1] = fg[2] = image_filter_scale / 2; - - int y_lr = y >> image_subpixel_shift; - int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * - ry_inv) >> - image_subpixel_shift; - int total_weight = 0; - int x_lr = x >> image_subpixel_shift; - int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * - rx_inv) >> - image_subpixel_shift; - int x_hr2 = x_hr; - const value_type* fg_ptr = - (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); - - for(;;) - { - int weight_y = weight_array[y_hr]; - x_hr = x_hr2; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - image_filter_scale / 2) >> - downscale_shift; - fg[0] += *fg_ptr++ * weight; - fg[1] += *fg_ptr++ * weight; - fg[2] += *fg_ptr * weight; - total_weight += weight; - x_hr += rx_inv; - if(x_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_x(); - } - y_hr += ry_inv; - if(y_hr >= filter_scale) break; - fg_ptr = (const value_type*)base_type::source().next_y(); - } - - fg[0] /= total_weight; - fg[1] /= total_weight; - fg[2] /= total_weight; - - if(fg[0] < 0) fg[0] = 0; - if(fg[1] < 0) fg[1] = 0; - if(fg[2] < 0) fg[2] = 0; - - if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask; - if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask; - if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask; - - span->r = (value_type)fg[order_type::R]; - span->g = (value_type)fg[order_type::G]; - span->b = (value_type)fg[order_type::B]; - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - } while(--len); - } - }; - - -} - - -#endif - - - diff -Nru corsix-th-0.30/agg/include/agg_span_interpolator_adaptor.h corsix-th-0.62/agg/include/agg_span_interpolator_adaptor.h --- corsix-th-0.30/agg/include/agg_span_interpolator_adaptor.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_interpolator_adaptor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_INTERPOLATOR_ADAPTOR_INCLUDED -#define AGG_SPAN_INTERPOLATOR_ADAPTOR_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //===============================================span_interpolator_adaptor - template - class span_interpolator_adaptor : public Interpolator - { - public: - typedef Interpolator base_type; - typedef typename base_type::trans_type trans_type; - typedef Distortion distortion_type; - - //-------------------------------------------------------------------- - span_interpolator_adaptor() {} - span_interpolator_adaptor(const trans_type& trans, - const distortion_type& dist) : - base_type(trans), - m_distortion(&dist) - { - } - - //-------------------------------------------------------------------- - span_interpolator_adaptor(const trans_type& trans, - const distortion_type& dist, - double x, double y, unsigned len) : - base_type(trans, x, y, len), - m_distortion(&dist) - { - } - - //-------------------------------------------------------------------- - const distortion_type& distortion() const - { - return *m_distortion; - } - - //-------------------------------------------------------------------- - void distortion(const distortion_type& dist) - { - m_distortion = dist; - } - - //-------------------------------------------------------------------- - void coordinates(int* x, int* y) const - { - base_type::coordinates(x, y); - m_distortion->calculate(x, y); - } - - private: - //-------------------------------------------------------------------- - const distortion_type* m_distortion; - }; -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_interpolator_linear.h corsix-th-0.62/agg/include/agg_span_interpolator_linear.h --- corsix-th-0.30/agg/include/agg_span_interpolator_linear.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_interpolator_linear.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,232 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_INTERPOLATOR_LINEAR_INCLUDED -#define AGG_SPAN_INTERPOLATOR_LINEAR_INCLUDED - -#include "agg_basics.h" -#include "agg_dda_line.h" -#include "agg_trans_affine.h" - -namespace agg -{ - - //================================================span_interpolator_linear - template - class span_interpolator_linear - { - public: - typedef Transformer trans_type; - - enum subpixel_scale_e - { - subpixel_shift = SubpixelShift, - subpixel_scale = 1 << subpixel_shift - }; - - //-------------------------------------------------------------------- - span_interpolator_linear() {} - span_interpolator_linear(const trans_type& trans) : m_trans(&trans) {} - span_interpolator_linear(const trans_type& trans, - double x, double y, unsigned len) : - m_trans(&trans) - { - begin(x, y, len); - } - - //---------------------------------------------------------------- - const trans_type& transformer() const { return *m_trans; } - void transformer(const trans_type& trans) { m_trans = &trans; } - - //---------------------------------------------------------------- - void begin(double x, double y, unsigned len) - { - double tx; - double ty; - - tx = x; - ty = y; - m_trans->transform(&tx, &ty); - int x1 = iround(tx * subpixel_scale); - int y1 = iround(ty * subpixel_scale); - - tx = x + len; - ty = y; - m_trans->transform(&tx, &ty); - int x2 = iround(tx * subpixel_scale); - int y2 = iround(ty * subpixel_scale); - - m_li_x = dda2_line_interpolator(x1, x2, len); - m_li_y = dda2_line_interpolator(y1, y2, len); - } - - //---------------------------------------------------------------- - void resynchronize(double xe, double ye, unsigned len) - { - m_trans->transform(&xe, &ye); - m_li_x = dda2_line_interpolator(m_li_x.y(), iround(xe * subpixel_scale), len); - m_li_y = dda2_line_interpolator(m_li_y.y(), iround(ye * subpixel_scale), len); - } - - //---------------------------------------------------------------- - void operator++() - { - ++m_li_x; - ++m_li_y; - } - - //---------------------------------------------------------------- - void coordinates(int* x, int* y) const - { - *x = m_li_x.y(); - *y = m_li_y.y(); - } - - private: - const trans_type* m_trans; - dda2_line_interpolator m_li_x; - dda2_line_interpolator m_li_y; - }; - - - - - - - //=====================================span_interpolator_linear_subdiv - template - class span_interpolator_linear_subdiv - { - public: - typedef Transformer trans_type; - - enum subpixel_scale_e - { - subpixel_shift = SubpixelShift, - subpixel_scale = 1 << subpixel_shift - }; - - - //---------------------------------------------------------------- - span_interpolator_linear_subdiv() : - m_subdiv_shift(4), - m_subdiv_size(1 << m_subdiv_shift), - m_subdiv_mask(m_subdiv_size - 1) {} - - span_interpolator_linear_subdiv(const trans_type& trans, - unsigned subdiv_shift = 4) : - m_subdiv_shift(subdiv_shift), - m_subdiv_size(1 << m_subdiv_shift), - m_subdiv_mask(m_subdiv_size - 1), - m_trans(&trans) {} - - span_interpolator_linear_subdiv(const trans_type& trans, - double x, double y, unsigned len, - unsigned subdiv_shift = 4) : - m_subdiv_shift(subdiv_shift), - m_subdiv_size(1 << m_subdiv_shift), - m_subdiv_mask(m_subdiv_size - 1), - m_trans(&trans) - { - begin(x, y, len); - } - - //---------------------------------------------------------------- - const trans_type& transformer() const { return *m_trans; } - void transformer(const trans_type& trans) { m_trans = &trans; } - - //---------------------------------------------------------------- - unsigned subdiv_shift() const { return m_subdiv_shift; } - void subdiv_shift(unsigned shift) - { - m_subdiv_shift = shift; - m_subdiv_size = 1 << m_subdiv_shift; - m_subdiv_mask = m_subdiv_size - 1; - } - - //---------------------------------------------------------------- - void begin(double x, double y, unsigned len) - { - double tx; - double ty; - m_pos = 1; - m_src_x = iround(x * subpixel_scale) + subpixel_scale; - m_src_y = y; - m_len = len; - - if(len > m_subdiv_size) len = m_subdiv_size; - tx = x; - ty = y; - m_trans->transform(&tx, &ty); - int x1 = iround(tx * subpixel_scale); - int y1 = iround(ty * subpixel_scale); - - tx = x + len; - ty = y; - m_trans->transform(&tx, &ty); - - m_li_x = dda2_line_interpolator(x1, iround(tx * subpixel_scale), len); - m_li_y = dda2_line_interpolator(y1, iround(ty * subpixel_scale), len); - } - - //---------------------------------------------------------------- - void operator++() - { - ++m_li_x; - ++m_li_y; - if(m_pos >= m_subdiv_size) - { - unsigned len = m_len; - if(len > m_subdiv_size) len = m_subdiv_size; - double tx = double(m_src_x) / double(subpixel_scale) + len; - double ty = m_src_y; - m_trans->transform(&tx, &ty); - m_li_x = dda2_line_interpolator(m_li_x.y(), iround(tx * subpixel_scale), len); - m_li_y = dda2_line_interpolator(m_li_y.y(), iround(ty * subpixel_scale), len); - m_pos = 0; - } - m_src_x += subpixel_scale; - ++m_pos; - --m_len; - } - - //---------------------------------------------------------------- - void coordinates(int* x, int* y) const - { - *x = m_li_x.y(); - *y = m_li_y.y(); - } - - private: - unsigned m_subdiv_shift; - unsigned m_subdiv_size; - unsigned m_subdiv_mask; - const trans_type* m_trans; - dda2_line_interpolator m_li_x; - dda2_line_interpolator m_li_y; - int m_src_x; - double m_src_y; - unsigned m_pos; - unsigned m_len; - }; - - -} - - - -#endif - - diff -Nru corsix-th-0.30/agg/include/agg_span_interpolator_persp.h corsix-th-0.62/agg/include/agg_span_interpolator_persp.h --- corsix-th-0.30/agg/include/agg_span_interpolator_persp.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_interpolator_persp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,462 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_SPAN_INTERPOLATOR_PERSP_INCLUDED -#define AGG_SPAN_INTERPOLATOR_PERSP_INCLUDED - -#include "agg_trans_perspective.h" -#include "agg_dda_line.h" - -namespace agg -{ - - - - //===========================================span_interpolator_persp_exact - template - class span_interpolator_persp_exact - { - public: - typedef trans_perspective trans_type; - typedef trans_perspective::iterator_x iterator_type; - enum subpixel_scale_e - { - subpixel_shift = SubpixelShift, - subpixel_scale = 1 << subpixel_shift - }; - - //-------------------------------------------------------------------- - span_interpolator_persp_exact() {} - - //-------------------------------------------------------------------- - // Arbitrary quadrangle transformations - span_interpolator_persp_exact(const double* src, const double* dst) - { - quad_to_quad(src, dst); - } - - //-------------------------------------------------------------------- - // Direct transformations - span_interpolator_persp_exact(double x1, double y1, - double x2, double y2, - const double* quad) - { - rect_to_quad(x1, y1, x2, y2, quad); - } - - //-------------------------------------------------------------------- - // Reverse transformations - span_interpolator_persp_exact(const double* quad, - double x1, double y1, - double x2, double y2) - { - quad_to_rect(quad, x1, y1, x2, y2); - } - - //-------------------------------------------------------------------- - // Set the transformations using two arbitrary quadrangles. - void quad_to_quad(const double* src, const double* dst) - { - m_trans_dir.quad_to_quad(src, dst); - m_trans_inv.quad_to_quad(dst, src); - } - - //-------------------------------------------------------------------- - // Set the direct transformations, i.e., rectangle -> quadrangle - void rect_to_quad(double x1, double y1, double x2, double y2, - const double* quad) - { - double src[8]; - src[0] = src[6] = x1; - src[2] = src[4] = x2; - src[1] = src[3] = y1; - src[5] = src[7] = y2; - quad_to_quad(src, quad); - } - - - //-------------------------------------------------------------------- - // Set the reverse transformations, i.e., quadrangle -> rectangle - void quad_to_rect(const double* quad, - double x1, double y1, double x2, double y2) - { - double dst[8]; - dst[0] = dst[6] = x1; - dst[2] = dst[4] = x2; - dst[1] = dst[3] = y1; - dst[5] = dst[7] = y2; - quad_to_quad(quad, dst); - } - - //-------------------------------------------------------------------- - // Check if the equations were solved successfully - bool is_valid() const { return m_trans_dir.is_valid(); } - - //---------------------------------------------------------------- - void begin(double x, double y, unsigned len) - { - m_iterator = m_trans_dir.begin(x, y, 1.0); - double xt = m_iterator.x; - double yt = m_iterator.y; - - double dx; - double dy; - const double delta = 1/double(subpixel_scale); - dx = xt + delta; - dy = yt; - m_trans_inv.transform(&dx, &dy); - dx -= x; - dy -= y; - int sx1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - dx = xt; - dy = yt + delta; - m_trans_inv.transform(&dx, &dy); - dx -= x; - dy -= y; - int sy1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - x += len; - xt = x; - yt = y; - m_trans_dir.transform(&xt, &yt); - - dx = xt + delta; - dy = yt; - m_trans_inv.transform(&dx, &dy); - dx -= x; - dy -= y; - int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - dx = xt; - dy = yt + delta; - m_trans_inv.transform(&dx, &dy); - dx -= x; - dy -= y; - int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - m_scale_x = dda2_line_interpolator(sx1, sx2, len); - m_scale_y = dda2_line_interpolator(sy1, sy2, len); - } - - - //---------------------------------------------------------------- - void resynchronize(double xe, double ye, unsigned len) - { - // Assume x1,y1 are equal to the ones at the previous end point - int sx1 = m_scale_x.y(); - int sy1 = m_scale_y.y(); - - // Calculate transformed coordinates at x2,y2 - double xt = xe; - double yt = ye; - m_trans_dir.transform(&xt, &yt); - - const double delta = 1/double(subpixel_scale); - double dx; - double dy; - - // Calculate scale by X at x2,y2 - dx = xt + delta; - dy = yt; - m_trans_inv.transform(&dx, &dy); - dx -= xe; - dy -= ye; - int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - // Calculate scale by Y at x2,y2 - dx = xt; - dy = yt + delta; - m_trans_inv.transform(&dx, &dy); - dx -= xe; - dy -= ye; - int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - // Initialize the interpolators - m_scale_x = dda2_line_interpolator(sx1, sx2, len); - m_scale_y = dda2_line_interpolator(sy1, sy2, len); - } - - - - //---------------------------------------------------------------- - void operator++() - { - ++m_iterator; - ++m_scale_x; - ++m_scale_y; - } - - //---------------------------------------------------------------- - void coordinates(int* x, int* y) const - { - *x = iround(m_iterator.x * subpixel_scale); - *y = iround(m_iterator.y * subpixel_scale); - } - - //---------------------------------------------------------------- - void local_scale(int* x, int* y) - { - *x = m_scale_x.y(); - *y = m_scale_y.y(); - } - - //---------------------------------------------------------------- - void transform(double* x, double* y) const - { - m_trans_dir.transform(x, y); - } - - private: - trans_type m_trans_dir; - trans_type m_trans_inv; - iterator_type m_iterator; - dda2_line_interpolator m_scale_x; - dda2_line_interpolator m_scale_y; - }; - - - - - - - - - - - - //============================================span_interpolator_persp_lerp - template - class span_interpolator_persp_lerp - { - public: - typedef trans_perspective trans_type; - enum subpixel_scale_e - { - subpixel_shift = SubpixelShift, - subpixel_scale = 1 << subpixel_shift - }; - - //-------------------------------------------------------------------- - span_interpolator_persp_lerp() {} - - //-------------------------------------------------------------------- - // Arbitrary quadrangle transformations - span_interpolator_persp_lerp(const double* src, const double* dst) - { - quad_to_quad(src, dst); - } - - //-------------------------------------------------------------------- - // Direct transformations - span_interpolator_persp_lerp(double x1, double y1, - double x2, double y2, - const double* quad) - { - rect_to_quad(x1, y1, x2, y2, quad); - } - - //-------------------------------------------------------------------- - // Reverse transformations - span_interpolator_persp_lerp(const double* quad, - double x1, double y1, - double x2, double y2) - { - quad_to_rect(quad, x1, y1, x2, y2); - } - - //-------------------------------------------------------------------- - // Set the transformations using two arbitrary quadrangles. - void quad_to_quad(const double* src, const double* dst) - { - m_trans_dir.quad_to_quad(src, dst); - m_trans_inv.quad_to_quad(dst, src); - } - - //-------------------------------------------------------------------- - // Set the direct transformations, i.e., rectangle -> quadrangle - void rect_to_quad(double x1, double y1, double x2, double y2, - const double* quad) - { - double src[8]; - src[0] = src[6] = x1; - src[2] = src[4] = x2; - src[1] = src[3] = y1; - src[5] = src[7] = y2; - quad_to_quad(src, quad); - } - - - //-------------------------------------------------------------------- - // Set the reverse transformations, i.e., quadrangle -> rectangle - void quad_to_rect(const double* quad, - double x1, double y1, double x2, double y2) - { - double dst[8]; - dst[0] = dst[6] = x1; - dst[2] = dst[4] = x2; - dst[1] = dst[3] = y1; - dst[5] = dst[7] = y2; - quad_to_quad(quad, dst); - } - - //-------------------------------------------------------------------- - // Check if the equations were solved successfully - bool is_valid() const { return m_trans_dir.is_valid(); } - - //---------------------------------------------------------------- - void begin(double x, double y, unsigned len) - { - // Calculate transformed coordinates at x1,y1 - double xt = x; - double yt = y; - m_trans_dir.transform(&xt, &yt); - int x1 = iround(xt * subpixel_scale); - int y1 = iround(yt * subpixel_scale); - - double dx; - double dy; - const double delta = 1/double(subpixel_scale); - - // Calculate scale by X at x1,y1 - dx = xt + delta; - dy = yt; - m_trans_inv.transform(&dx, &dy); - dx -= x; - dy -= y; - int sx1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - // Calculate scale by Y at x1,y1 - dx = xt; - dy = yt + delta; - m_trans_inv.transform(&dx, &dy); - dx -= x; - dy -= y; - int sy1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - // Calculate transformed coordinates at x2,y2 - x += len; - xt = x; - yt = y; - m_trans_dir.transform(&xt, &yt); - int x2 = iround(xt * subpixel_scale); - int y2 = iround(yt * subpixel_scale); - - // Calculate scale by X at x2,y2 - dx = xt + delta; - dy = yt; - m_trans_inv.transform(&dx, &dy); - dx -= x; - dy -= y; - int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - // Calculate scale by Y at x2,y2 - dx = xt; - dy = yt + delta; - m_trans_inv.transform(&dx, &dy); - dx -= x; - dy -= y; - int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - // Initialize the interpolators - m_coord_x = dda2_line_interpolator(x1, x2, len); - m_coord_y = dda2_line_interpolator(y1, y2, len); - m_scale_x = dda2_line_interpolator(sx1, sx2, len); - m_scale_y = dda2_line_interpolator(sy1, sy2, len); - } - - - //---------------------------------------------------------------- - void resynchronize(double xe, double ye, unsigned len) - { - // Assume x1,y1 are equal to the ones at the previous end point - int x1 = m_coord_x.y(); - int y1 = m_coord_y.y(); - int sx1 = m_scale_x.y(); - int sy1 = m_scale_y.y(); - - // Calculate transformed coordinates at x2,y2 - double xt = xe; - double yt = ye; - m_trans_dir.transform(&xt, &yt); - int x2 = iround(xt * subpixel_scale); - int y2 = iround(yt * subpixel_scale); - - const double delta = 1/double(subpixel_scale); - double dx; - double dy; - - // Calculate scale by X at x2,y2 - dx = xt + delta; - dy = yt; - m_trans_inv.transform(&dx, &dy); - dx -= xe; - dy -= ye; - int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - // Calculate scale by Y at x2,y2 - dx = xt; - dy = yt + delta; - m_trans_inv.transform(&dx, &dy); - dx -= xe; - dy -= ye; - int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift; - - // Initialize the interpolators - m_coord_x = dda2_line_interpolator(x1, x2, len); - m_coord_y = dda2_line_interpolator(y1, y2, len); - m_scale_x = dda2_line_interpolator(sx1, sx2, len); - m_scale_y = dda2_line_interpolator(sy1, sy2, len); - } - - - //---------------------------------------------------------------- - void operator++() - { - ++m_coord_x; - ++m_coord_y; - ++m_scale_x; - ++m_scale_y; - } - - //---------------------------------------------------------------- - void coordinates(int* x, int* y) const - { - *x = m_coord_x.y(); - *y = m_coord_y.y(); - } - - //---------------------------------------------------------------- - void local_scale(int* x, int* y) - { - *x = m_scale_x.y(); - *y = m_scale_y.y(); - } - - //---------------------------------------------------------------- - void transform(double* x, double* y) const - { - m_trans_dir.transform(x, y); - } - - private: - trans_type m_trans_dir; - trans_type m_trans_inv; - dda2_line_interpolator m_coord_x; - dda2_line_interpolator m_coord_y; - dda2_line_interpolator m_scale_x; - dda2_line_interpolator m_scale_y; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_interpolator_trans.h corsix-th-0.62/agg/include/agg_span_interpolator_trans.h --- corsix-th-0.30/agg/include/agg_span_interpolator_trans.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_interpolator_trans.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Horizontal span interpolator for use with an arbitrary transformer -// The efficiency highly depends on the operations done in the transformer -// -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_INTERPOLATOR_TRANS_INCLUDED -#define AGG_SPAN_INTERPOLATOR_TRANS_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - //=================================================span_interpolator_trans - template - class span_interpolator_trans - { - public: - typedef Transformer trans_type; - enum subpixel_scale_e - { - subpixel_shift = SubpixelShift, - subpixel_scale = 1 << subpixel_shift - }; - - //-------------------------------------------------------------------- - span_interpolator_trans() {} - span_interpolator_trans(const trans_type& trans) : m_trans(&trans) {} - span_interpolator_trans(const trans_type& trans, - double x, double y, unsigned) : - m_trans(&trans) - { - begin(x, y, 0); - } - - //---------------------------------------------------------------- - const trans_type& transformer() const { return *m_trans; } - void transformer(const trans_type& trans) { m_trans = &trans; } - - //---------------------------------------------------------------- - void begin(double x, double y, unsigned) - { - m_x = x; - m_y = y; - m_trans->transform(&x, &y); - m_ix = iround(x * subpixel_scale); - m_iy = iround(y * subpixel_scale); - } - - //---------------------------------------------------------------- - void operator++() - { - m_x += 1.0; - double x = m_x; - double y = m_y; - m_trans->transform(&x, &y); - m_ix = iround(x * subpixel_scale); - m_iy = iround(y * subpixel_scale); - } - - //---------------------------------------------------------------- - void coordinates(int* x, int* y) const - { - *x = m_ix; - *y = m_iy; - } - - private: - const trans_type* m_trans; - double m_x; - double m_y; - int m_ix; - int m_iy; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_pattern_gray.h corsix-th-0.62/agg/include/agg_span_pattern_gray.h --- corsix-th-0.30/agg/include/agg_span_pattern_gray.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_pattern_gray.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - - -#ifndef AGG_SPAN_PATTERN_GRAY_INCLUDED -#define AGG_SPAN_PATTERN_GRAY_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //=======================================================span_pattern_gray - template class span_pattern_gray - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - - //-------------------------------------------------------------------- - span_pattern_gray() {} - span_pattern_gray(source_type& src, - unsigned offset_x, unsigned offset_y) : - m_src(&src), - m_offset_x(offset_x), - m_offset_y(offset_y), - m_alpha(color_type::base_mask) - {} - - //-------------------------------------------------------------------- - void attach(source_type& v) { m_src = &v; } - source_type& source() { return *m_src; } - const source_type& source() const { return *m_src; } - - //-------------------------------------------------------------------- - void offset_x(unsigned v) { m_offset_x = v; } - void offset_y(unsigned v) { m_offset_y = v; } - unsigned offset_x() const { return m_offset_x; } - unsigned offset_y() const { return m_offset_y; } - void alpha(value_type v) { m_alpha = v; } - value_type alpha() const { return m_alpha; } - - //-------------------------------------------------------------------- - void prepare() {} - void generate(color_type* span, int x, int y, unsigned len) - { - x += m_offset_x; - y += m_offset_y; - const value_type* p = (const value_type*)m_src->span(x, y, len); - do - { - span->v = *p; - span->a = m_alpha; - p = m_src->next_x(); - ++span; - } - while(--len); - } - - private: - source_type* m_src; - unsigned m_offset_x; - unsigned m_offset_y; - value_type m_alpha; - - }; - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_span_pattern_rgba.h corsix-th-0.62/agg/include/agg_span_pattern_rgba.h --- corsix-th-0.30/agg/include/agg_span_pattern_rgba.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_pattern_rgba.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - - -#ifndef AGG_SPAN_PATTERN_RGBA_INCLUDED -#define AGG_SPAN_PATTERN_RGBA_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //======================================================span_pattern_rgba - template class span_pattern_rgba - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - - //-------------------------------------------------------------------- - span_pattern_rgba() {} - span_pattern_rgba(source_type& src, - unsigned offset_x, unsigned offset_y) : - m_src(&src), - m_offset_x(offset_x), - m_offset_y(offset_y) - {} - - //-------------------------------------------------------------------- - void attach(source_type& v) { m_src = &v; } - source_type& source() { return *m_src; } - const source_type& source() const { return *m_src; } - - //-------------------------------------------------------------------- - void offset_x(unsigned v) { m_offset_x = v; } - void offset_y(unsigned v) { m_offset_y = v; } - unsigned offset_x() const { return m_offset_x; } - unsigned offset_y() const { return m_offset_y; } - void alpha(value_type) {} - value_type alpha() const { return 0; } - - //-------------------------------------------------------------------- - void prepare() {} - void generate(color_type* span, int x, int y, unsigned len) - { - x += m_offset_x; - y += m_offset_y; - const value_type* p = (const value_type*)m_src->span(x, y, len); - do - { - span->r = p[order_type::R]; - span->g = p[order_type::G]; - span->b = p[order_type::B]; - span->a = p[order_type::A]; - p = (const value_type*)m_src->next_x(); - ++span; - } - while(--len); - } - - private: - source_type* m_src; - unsigned m_offset_x; - unsigned m_offset_y; - - }; - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_span_pattern_rgb.h corsix-th-0.62/agg/include/agg_span_pattern_rgb.h --- corsix-th-0.30/agg/include/agg_span_pattern_rgb.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_pattern_rgb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Adaptation for high precision colors has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- - - -#ifndef AGG_SPAN_PATTERN_RGB_INCLUDED -#define AGG_SPAN_PATTERN_RGB_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //========================================================span_pattern_rgb - template class span_pattern_rgb - { - public: - typedef Source source_type; - typedef typename source_type::color_type color_type; - typedef typename source_type::order_type order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - - //-------------------------------------------------------------------- - span_pattern_rgb() {} - span_pattern_rgb(source_type& src, - unsigned offset_x, unsigned offset_y) : - m_src(&src), - m_offset_x(offset_x), - m_offset_y(offset_y), - m_alpha(color_type::base_mask) - {} - - //-------------------------------------------------------------------- - void attach(source_type& v) { m_src = &v; } - source_type& source() { return *m_src; } - const source_type& source() const { return *m_src; } - - //-------------------------------------------------------------------- - void offset_x(unsigned v) { m_offset_x = v; } - void offset_y(unsigned v) { m_offset_y = v; } - unsigned offset_x() const { return m_offset_x; } - unsigned offset_y() const { return m_offset_y; } - void alpha(value_type v) { m_alpha = v; } - value_type alpha() const { return m_alpha; } - - //-------------------------------------------------------------------- - void prepare() {} - void generate(color_type* span, int x, int y, unsigned len) - { - x += m_offset_x; - y += m_offset_y; - const value_type* p = (const value_type*)m_src->span(x, y, len); - do - { - span->r = p[order_type::R]; - span->g = p[order_type::G]; - span->b = p[order_type::B]; - span->a = m_alpha; - p = m_src->next_x(); - ++span; - } - while(--len); - } - - private: - source_type* m_src; - unsigned m_offset_x; - unsigned m_offset_y; - value_type m_alpha; - - }; - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_span_solid.h corsix-th-0.62/agg/include/agg_span_solid.h --- corsix-th-0.30/agg/include/agg_span_solid.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_solid.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// span_solid_rgba8 -// -//---------------------------------------------------------------------------- - -#ifndef AGG_SPAN_SOLID_INCLUDED -#define AGG_SPAN_SOLID_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - //--------------------------------------------------------------span_solid - template class span_solid - { - public: - typedef ColorT color_type; - - //-------------------------------------------------------------------- - void color(const color_type& c) { m_color = c; } - const color_type& color() const { return m_color; } - - //-------------------------------------------------------------------- - void prepare() {} - - //-------------------------------------------------------------------- - void generate(color_type* span, int x, int y, unsigned len) - { - do { *span++ = m_color; } while(--len); - } - - private: - color_type m_color; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_span_subdiv_adaptor.h corsix-th-0.62/agg/include/agg_span_subdiv_adaptor.h --- corsix-th-0.30/agg/include/agg_span_subdiv_adaptor.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_span_subdiv_adaptor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -#ifndef AGG_SPAN_SUBDIV_ADAPTOR_INCLUDED -#define AGG_SPAN_SUBDIV_ADAPTOR_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //=================================================span_subdiv_adaptor - template - class span_subdiv_adaptor - { - public: - typedef Interpolator interpolator_type; - typedef typename interpolator_type::trans_type trans_type; - - enum sublixel_scale_e - { - subpixel_shift = SubpixelShift, - subpixel_scale = 1 << subpixel_shift - }; - - - //---------------------------------------------------------------- - span_subdiv_adaptor() : - m_subdiv_shift(4), - m_subdiv_size(1 << m_subdiv_shift), - m_subdiv_mask(m_subdiv_size - 1) {} - - span_subdiv_adaptor(interpolator_type& interpolator, - unsigned subdiv_shift = 4) : - m_subdiv_shift(subdiv_shift), - m_subdiv_size(1 << m_subdiv_shift), - m_subdiv_mask(m_subdiv_size - 1), - m_interpolator(&interpolator) {} - - span_subdiv_adaptor(interpolator_type& interpolator, - double x, double y, unsigned len, - unsigned subdiv_shift = 4) : - m_subdiv_shift(subdiv_shift), - m_subdiv_size(1 << m_subdiv_shift), - m_subdiv_mask(m_subdiv_size - 1), - m_interpolator(&interpolator) - { - begin(x, y, len); - } - - - //---------------------------------------------------------------- - const interpolator_type& interpolator() const { return *m_interpolator; } - void interpolator(interpolator_type& intr) { m_interpolator = &intr; } - - //---------------------------------------------------------------- - const trans_type& transformer() const - { - return *m_interpolator->transformer(); - } - void transformer(const trans_type& trans) - { - m_interpolator->transformer(trans); - } - - //---------------------------------------------------------------- - unsigned subdiv_shift() const { return m_subdiv_shift; } - void subdiv_shift(unsigned shift) - { - m_subdiv_shift = shift; - m_subdiv_size = 1 << m_subdiv_shift; - m_subdiv_mask = m_subdiv_size - 1; - } - - //---------------------------------------------------------------- - void begin(double x, double y, unsigned len) - { - m_pos = 1; - m_src_x = iround(x * subpixel_scale) + subpixel_scale; - m_src_y = y; - m_len = len; - if(len > m_subdiv_size) len = m_subdiv_size; - m_interpolator->begin(x, y, len); - } - - //---------------------------------------------------------------- - void operator++() - { - ++(*m_interpolator); - if(m_pos >= m_subdiv_size) - { - unsigned len = m_len; - if(len > m_subdiv_size) len = m_subdiv_size; - m_interpolator->resynchronize(double(m_src_x) / double(subpixel_scale) + len, - m_src_y, - len); - m_pos = 0; - } - m_src_x += subpixel_scale; - ++m_pos; - --m_len; - } - - //---------------------------------------------------------------- - void coordinates(int* x, int* y) const - { - m_interpolator->coordinates(x, y); - } - - //---------------------------------------------------------------- - void local_scale(int* x, int* y) const - { - m_interpolator->local_scale(x, y); - } - - - private: - unsigned m_subdiv_shift; - unsigned m_subdiv_size; - unsigned m_subdiv_mask; - interpolator_type* m_interpolator; - int m_src_x; - double m_src_y; - unsigned m_pos; - unsigned m_len; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_trans_affine.h corsix-th-0.62/agg/include/agg_trans_affine.h --- corsix-th-0.30/agg/include/agg_trans_affine.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_trans_affine.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,518 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Affine transformation classes. -// -//---------------------------------------------------------------------------- -#ifndef AGG_TRANS_AFFINE_INCLUDED -#define AGG_TRANS_AFFINE_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - const double affine_epsilon = 1e-14; - - //============================================================trans_affine - // - // See Implementation agg_trans_affine.cpp - // - // Affine transformation are linear transformations in Cartesian coordinates - // (strictly speaking not only in Cartesian, but for the beginning we will - // think so). They are rotation, scaling, translation and skewing. - // After any affine transformation a line segment remains a line segment - // and it will never become a curve. - // - // There will be no math about matrix calculations, since it has been - // described many times. Ask yourself a very simple question: - // "why do we need to understand and use some matrix stuff instead of just - // rotating, scaling and so on". The answers are: - // - // 1. Any combination of transformations can be done by only 4 multiplications - // and 4 additions in floating point. - // 2. One matrix transformation is equivalent to the number of consecutive - // discrete transformations, i.e. the matrix "accumulates" all transformations - // in the order of their settings. Suppose we have 4 transformations: - // * rotate by 30 degrees, - // * scale X to 2.0, - // * scale Y to 1.5, - // * move to (100, 100). - // The result will depend on the order of these transformations, - // and the advantage of matrix is that the sequence of discret calls: - // rotate(30), scaleX(2.0), scaleY(1.5), move(100,100) - // will have exactly the same result as the following matrix transformations: - // - // affine_matrix m; - // m *= rotate_matrix(30); - // m *= scaleX_matrix(2.0); - // m *= scaleY_matrix(1.5); - // m *= move_matrix(100,100); - // - // m.transform_my_point_at_last(x, y); - // - // What is the good of it? In real life we will set-up the matrix only once - // and then transform many points, let alone the convenience to set any - // combination of transformations. - // - // So, how to use it? Very easy - literally as it's shown above. Not quite, - // let us write a correct example: - // - // agg::trans_affine m; - // m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); - // m *= agg::trans_affine_scaling(2.0, 1.5); - // m *= agg::trans_affine_translation(100.0, 100.0); - // m.transform(&x, &y); - // - // The affine matrix is all you need to perform any linear transformation, - // but all transformations have origin point (0,0). It means that we need to - // use 2 translations if we want to rotate someting around (100,100): - // - // m *= agg::trans_affine_translation(-100.0, -100.0); // move to (0,0) - // m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate - // m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100) - //---------------------------------------------------------------------- - struct trans_affine - { - double sx, shy, shx, sy, tx, ty; - - //------------------------------------------ Construction - // Identity matrix - trans_affine() : - sx(1.0), shy(0.0), shx(0.0), sy(1.0), tx(0.0), ty(0.0) - {} - - // Custom matrix. Usually used in derived classes - trans_affine(double v0, double v1, double v2, - double v3, double v4, double v5) : - sx(v0), shy(v1), shx(v2), sy(v3), tx(v4), ty(v5) - {} - - // Custom matrix from m[6] - explicit trans_affine(const double* m) : - sx(m[0]), shy(m[1]), shx(m[2]), sy(m[3]), tx(m[4]), ty(m[5]) - {} - - // Rectangle to a parallelogram. - trans_affine(double x1, double y1, double x2, double y2, - const double* parl) - { - rect_to_parl(x1, y1, x2, y2, parl); - } - - // Parallelogram to a rectangle. - trans_affine(const double* parl, - double x1, double y1, double x2, double y2) - { - parl_to_rect(parl, x1, y1, x2, y2); - } - - // Arbitrary parallelogram transformation. - trans_affine(const double* src, const double* dst) - { - parl_to_parl(src, dst); - } - - //---------------------------------- Parellelogram transformations - // transform a parallelogram to another one. Src and dst are - // pointers to arrays of three points (double[6], x1,y1,...) that - // identify three corners of the parallelograms assuming implicit - // fourth point. The arguments are arrays of double[6] mapped - // to x1,y1, x2,y2, x3,y3 where the coordinates are: - // *-----------------* - // / (x3,y3)/ - // / / - // /(x1,y1) (x2,y2)/ - // *-----------------* - const trans_affine& parl_to_parl(const double* src, - const double* dst); - - const trans_affine& rect_to_parl(double x1, double y1, - double x2, double y2, - const double* parl); - - const trans_affine& parl_to_rect(const double* parl, - double x1, double y1, - double x2, double y2); - - - //------------------------------------------ Operations - // Reset - load an identity matrix - const trans_affine& reset(); - - // Direct transformations operations - const trans_affine& translate(double x, double y); - const trans_affine& rotate(double a); - const trans_affine& scale(double s); - const trans_affine& scale(double x, double y); - - // Multiply matrix to another one - const trans_affine& multiply(const trans_affine& m); - - // Multiply "m" to "this" and assign the result to "this" - const trans_affine& premultiply(const trans_affine& m); - - // Multiply matrix to inverse of another one - const trans_affine& multiply_inv(const trans_affine& m); - - // Multiply inverse of "m" to "this" and assign the result to "this" - const trans_affine& premultiply_inv(const trans_affine& m); - - // Invert matrix. Do not try to invert degenerate matrices, - // there's no check for validity. If you set scale to 0 and - // then try to invert matrix, expect unpredictable result. - const trans_affine& invert(); - - // Mirroring around X - const trans_affine& flip_x(); - - // Mirroring around Y - const trans_affine& flip_y(); - - //------------------------------------------- Load/Store - // Store matrix to an array [6] of double - void store_to(double* m) const - { - *m++ = sx; *m++ = shy; *m++ = shx; *m++ = sy; *m++ = tx; *m++ = ty; - } - - // Load matrix from an array [6] of double - const trans_affine& load_from(const double* m) - { - sx = *m++; shy = *m++; shx = *m++; sy = *m++; tx = *m++; ty = *m++; - return *this; - } - - //------------------------------------------- Operators - - // Multiply the matrix by another one - const trans_affine& operator *= (const trans_affine& m) - { - return multiply(m); - } - - // Multiply the matrix by inverse of another one - const trans_affine& operator /= (const trans_affine& m) - { - return multiply_inv(m); - } - - // Multiply the matrix by another one and return - // the result in a separete matrix. - trans_affine operator * (const trans_affine& m) - { - return trans_affine(*this).multiply(m); - } - - // Multiply the matrix by inverse of another one - // and return the result in a separete matrix. - trans_affine operator / (const trans_affine& m) - { - return trans_affine(*this).multiply_inv(m); - } - - // Calculate and return the inverse matrix - trans_affine operator ~ () const - { - trans_affine ret = *this; - return ret.invert(); - } - - // Equal operator with default epsilon - bool operator == (const trans_affine& m) const - { - return is_equal(m, affine_epsilon); - } - - // Not Equal operator with default epsilon - bool operator != (const trans_affine& m) const - { - return !is_equal(m, affine_epsilon); - } - - //-------------------------------------------- Transformations - // Direct transformation of x and y - void transform(double* x, double* y) const; - - // Direct transformation of x and y, 2x2 matrix only, no translation - void transform_2x2(double* x, double* y) const; - - // Inverse transformation of x and y. It works slower than the - // direct transformation. For massive operations it's better to - // invert() the matrix and then use direct transformations. - void inverse_transform(double* x, double* y) const; - - //-------------------------------------------- Auxiliary - // Calculate the determinant of matrix - double determinant() const - { - return sx * sy - shy * shx; - } - - // Calculate the reciprocal of the determinant - double determinant_reciprocal() const - { - return 1.0 / (sx * sy - shy * shx); - } - - // Get the average scale (by X and Y). - // Basically used to calculate the approximation_scale when - // decomposinting curves into line segments. - double scale() const; - - // Check to see if the matrix is not degenerate - bool is_valid(double epsilon = affine_epsilon) const; - - // Check to see if it's an identity matrix - bool is_identity(double epsilon = affine_epsilon) const; - - // Check to see if two matrices are equal - bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const; - - // Determine the major parameters. Use with caution considering - // possible degenerate cases. - double rotation() const; - void translation(double* dx, double* dy) const; - void scaling(double* x, double* y) const; - void scaling_abs(double* x, double* y) const; - }; - - //------------------------------------------------------------------------ - inline void trans_affine::transform(double* x, double* y) const - { - register double tmp = *x; - *x = tmp * sx + *y * shx + tx; - *y = tmp * shy + *y * sy + ty; - } - - //------------------------------------------------------------------------ - inline void trans_affine::transform_2x2(double* x, double* y) const - { - register double tmp = *x; - *x = tmp * sx + *y * shx; - *y = tmp * shy + *y * sy; - } - - //------------------------------------------------------------------------ - inline void trans_affine::inverse_transform(double* x, double* y) const - { - register double d = determinant_reciprocal(); - register double a = (*x - tx) * d; - register double b = (*y - ty) * d; - *x = a * sy - b * shx; - *y = b * sx - a * shy; - } - - //------------------------------------------------------------------------ - inline double trans_affine::scale() const - { - double x = 0.707106781 * sx + 0.707106781 * shx; - double y = 0.707106781 * shy + 0.707106781 * sy; - return sqrt(x*x + y*y); - } - - //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::translate(double x, double y) - { - tx += x; - ty += y; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::rotate(double a) - { - double ca = cos(a); - double sa = sin(a); - double t0 = sx * ca - shy * sa; - double t2 = shx * ca - sy * sa; - double t4 = tx * ca - ty * sa; - shy = sx * sa + shy * ca; - sy = shx * sa + sy * ca; - ty = tx * sa + ty * ca; - sx = t0; - shx = t2; - tx = t4; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::scale(double x, double y) - { - double mm0 = x; // Possible hint for the optimizer - double mm3 = y; - sx *= mm0; - shx *= mm0; - tx *= mm0; - shy *= mm3; - sy *= mm3; - ty *= mm3; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::scale(double s) - { - double m = s; // Possible hint for the optimizer - sx *= m; - shx *= m; - tx *= m; - shy *= m; - sy *= m; - ty *= m; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::premultiply(const trans_affine& m) - { - trans_affine t = m; - return *this = t.multiply(*this); - } - - //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::multiply_inv(const trans_affine& m) - { - trans_affine t = m; - t.invert(); - return multiply(t); - } - - //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::premultiply_inv(const trans_affine& m) - { - trans_affine t = m; - t.invert(); - return *this = t.multiply(*this); - } - - //------------------------------------------------------------------------ - inline void trans_affine::scaling_abs(double* x, double* y) const - { - // Used to calculate scaling coefficients in image resampling. - // When there is considerable shear this method gives us much - // better estimation than just sx, sy. - *x = sqrt(sx * sx + shx * shx); - *y = sqrt(shy * shy + sy * sy); - } - - //====================================================trans_affine_rotation - // Rotation matrix. sin() and cos() are calculated twice for the same angle. - // There's no harm because the performance of sin()/cos() is very good on all - // modern processors. Besides, this operation is not going to be invoked too - // often. - class trans_affine_rotation : public trans_affine - { - public: - trans_affine_rotation(double a) : - trans_affine(cos(a), sin(a), -sin(a), cos(a), 0.0, 0.0) - {} - }; - - //====================================================trans_affine_scaling - // Scaling matrix. x, y - scale coefficients by X and Y respectively - class trans_affine_scaling : public trans_affine - { - public: - trans_affine_scaling(double x, double y) : - trans_affine(x, 0.0, 0.0, y, 0.0, 0.0) - {} - - trans_affine_scaling(double s) : - trans_affine(s, 0.0, 0.0, s, 0.0, 0.0) - {} - }; - - //================================================trans_affine_translation - // Translation matrix - class trans_affine_translation : public trans_affine - { - public: - trans_affine_translation(double x, double y) : - trans_affine(1.0, 0.0, 0.0, 1.0, x, y) - {} - }; - - //====================================================trans_affine_skewing - // Sckewing (shear) matrix - class trans_affine_skewing : public trans_affine - { - public: - trans_affine_skewing(double x, double y) : - trans_affine(1.0, tan(y), tan(x), 1.0, 0.0, 0.0) - {} - }; - - - //===============================================trans_affine_line_segment - // Rotate, Scale and Translate, associating 0...dist with line segment - // x1,y1,x2,y2 - class trans_affine_line_segment : public trans_affine - { - public: - trans_affine_line_segment(double x1, double y1, double x2, double y2, - double dist) - { - double dx = x2 - x1; - double dy = y2 - y1; - if(dist > 0.0) - { - multiply(trans_affine_scaling(sqrt(dx * dx + dy * dy) / dist)); - } - multiply(trans_affine_rotation(atan2(dy, dx))); - multiply(trans_affine_translation(x1, y1)); - } - }; - - - //============================================trans_affine_reflection_unit - // Reflection matrix. Reflect coordinates across the line through - // the origin containing the unit vector (ux, uy). - // Contributed by John Horigan - class trans_affine_reflection_unit : public trans_affine - { - public: - trans_affine_reflection_unit(double ux, double uy) : - trans_affine(2.0 * ux * ux - 1.0, - 2.0 * ux * uy, - 2.0 * ux * uy, - 2.0 * uy * uy - 1.0, - 0.0, 0.0) - {} - }; - - - //=================================================trans_affine_reflection - // Reflection matrix. Reflect coordinates across the line through - // the origin at the angle a or containing the non-unit vector (x, y). - // Contributed by John Horigan - class trans_affine_reflection : public trans_affine_reflection_unit - { - public: - trans_affine_reflection(double a) : - trans_affine_reflection_unit(cos(a), sin(a)) - {} - - - trans_affine_reflection(double x, double y) : - trans_affine_reflection_unit(x / sqrt(x * x + y * y), y / sqrt(x * x + y * y)) - {} - }; - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_trans_bilinear.h corsix-th-0.62/agg/include/agg_trans_bilinear.h --- corsix-th-0.30/agg/include/agg_trans_bilinear.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_trans_bilinear.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Bilinear 2D transformations -// -//---------------------------------------------------------------------------- -#ifndef AGG_TRANS_BILINEAR_INCLUDED -#define AGG_TRANS_BILINEAR_INCLUDED - -#include "agg_basics.h" -#include "agg_simul_eq.h" - -namespace agg -{ - - //==========================================================trans_bilinear - class trans_bilinear - { - public: - //-------------------------------------------------------------------- - trans_bilinear() : m_valid(false) {} - - //-------------------------------------------------------------------- - // Arbitrary quadrangle transformations - trans_bilinear(const double* src, const double* dst) - { - quad_to_quad(src, dst); - } - - - //-------------------------------------------------------------------- - // Direct transformations - trans_bilinear(double x1, double y1, double x2, double y2, - const double* quad) - { - rect_to_quad(x1, y1, x2, y2, quad); - } - - - //-------------------------------------------------------------------- - // Reverse transformations - trans_bilinear(const double* quad, - double x1, double y1, double x2, double y2) - { - quad_to_rect(quad, x1, y1, x2, y2); - } - - - //-------------------------------------------------------------------- - // Set the transformations using two arbitrary quadrangles. - void quad_to_quad(const double* src, const double* dst) - { - double left[4][4]; - double right[4][2]; - - unsigned i; - for(i = 0; i < 4; i++) - { - unsigned ix = i * 2; - unsigned iy = ix + 1; - left[i][0] = 1.0; - left[i][1] = src[ix] * src[iy]; - left[i][2] = src[ix]; - left[i][3] = src[iy]; - - right[i][0] = dst[ix]; - right[i][1] = dst[iy]; - } - m_valid = simul_eq<4, 2>::solve(left, right, m_mtx); - } - - - //-------------------------------------------------------------------- - // Set the direct transformations, i.e., rectangle -> quadrangle - void rect_to_quad(double x1, double y1, double x2, double y2, - const double* quad) - { - double src[8]; - src[0] = src[6] = x1; - src[2] = src[4] = x2; - src[1] = src[3] = y1; - src[5] = src[7] = y2; - quad_to_quad(src, quad); - } - - - //-------------------------------------------------------------------- - // Set the reverse transformations, i.e., quadrangle -> rectangle - void quad_to_rect(const double* quad, - double x1, double y1, double x2, double y2) - { - double dst[8]; - dst[0] = dst[6] = x1; - dst[2] = dst[4] = x2; - dst[1] = dst[3] = y1; - dst[5] = dst[7] = y2; - quad_to_quad(quad, dst); - } - - //-------------------------------------------------------------------- - // Check if the equations were solved successfully - bool is_valid() const { return m_valid; } - - //-------------------------------------------------------------------- - // Transform a point (x, y) - void transform(double* x, double* y) const - { - double tx = *x; - double ty = *y; - double xy = tx * ty; - *x = m_mtx[0][0] + m_mtx[1][0] * xy + m_mtx[2][0] * tx + m_mtx[3][0] * ty; - *y = m_mtx[0][1] + m_mtx[1][1] * xy + m_mtx[2][1] * tx + m_mtx[3][1] * ty; - } - - - //-------------------------------------------------------------------- - class iterator_x - { - double inc_x; - double inc_y; - - public: - double x; - double y; - - iterator_x() {} - iterator_x(double tx, double ty, double step, const double m[4][2]) : - inc_x(m[1][0] * step * ty + m[2][0] * step), - inc_y(m[1][1] * step * ty + m[2][1] * step), - x(m[0][0] + m[1][0] * tx * ty + m[2][0] * tx + m[3][0] * ty), - y(m[0][1] + m[1][1] * tx * ty + m[2][1] * tx + m[3][1] * ty) - { - } - - void operator ++ () - { - x += inc_x; - y += inc_y; - } - }; - - iterator_x begin(double x, double y, double step) const - { - return iterator_x(x, y, step, m_mtx); - } - - private: - double m_mtx[4][2]; - bool m_valid; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_trans_double_path.h corsix-th-0.62/agg/include/agg_trans_double_path.h --- corsix-th-0.30/agg/include/agg_trans_double_path.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_trans_double_path.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_TRANS_DOUBLE_PATH_INCLUDED -#define AGG_TRANS_DOUBLE_PATH_INCLUDED - -#include "agg_basics.h" -#include "agg_vertex_sequence.h" - -namespace agg -{ - - // See also: agg_trans_double_path.cpp - // - //-------------------------------------------------------trans_double_path - class trans_double_path - { - enum status_e - { - initial, - making_path, - ready - }; - - public: - typedef vertex_sequence vertex_storage; - - trans_double_path(); - - //-------------------------------------------------------------------- - void base_length(double v) { m_base_length = v; } - double base_length() const { return m_base_length; } - - //-------------------------------------------------------------------- - void base_height(double v) { m_base_height = v; } - double base_height() const { return m_base_height; } - - //-------------------------------------------------------------------- - void preserve_x_scale(bool f) { m_preserve_x_scale = f; } - bool preserve_x_scale() const { return m_preserve_x_scale; } - - //-------------------------------------------------------------------- - void reset(); - void move_to1(double x, double y); - void line_to1(double x, double y); - void move_to2(double x, double y); - void line_to2(double x, double y); - void finalize_paths(); - - //-------------------------------------------------------------------- - template - void add_paths(VertexSource1& vs1, VertexSource2& vs2, - unsigned path1_id=0, unsigned path2_id=0) - { - double x; - double y; - - unsigned cmd; - - vs1.rewind(path1_id); - while(!is_stop(cmd = vs1.vertex(&x, &y))) - { - if(is_move_to(cmd)) - { - move_to1(x, y); - } - else - { - if(is_vertex(cmd)) - { - line_to1(x, y); - } - } - } - - vs2.rewind(path2_id); - while(!is_stop(cmd = vs2.vertex(&x, &y))) - { - if(is_move_to(cmd)) - { - move_to2(x, y); - } - else - { - if(is_vertex(cmd)) - { - line_to2(x, y); - } - } - } - finalize_paths(); - } - - //-------------------------------------------------------------------- - double total_length1() const; - double total_length2() const; - void transform(double *x, double *y) const; - - private: - double finalize_path(vertex_storage& vertices); - void transform1(const vertex_storage& vertices, - double kindex, double kx, - double *x, double* y) const; - - vertex_storage m_src_vertices1; - vertex_storage m_src_vertices2; - double m_base_length; - double m_base_height; - double m_kindex1; - double m_kindex2; - status_e m_status1; - status_e m_status2; - bool m_preserve_x_scale; - }; - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_trans_perspective.h corsix-th-0.62/agg/include/agg_trans_perspective.h --- corsix-th-0.30/agg/include/agg_trans_perspective.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_trans_perspective.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,731 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Perspective 2D transformations -// -//---------------------------------------------------------------------------- -#ifndef AGG_TRANS_PERSPECTIVE_INCLUDED -#define AGG_TRANS_PERSPECTIVE_INCLUDED - -#include "agg_trans_affine.h" - -namespace agg -{ - //=======================================================trans_perspective - struct trans_perspective - { - double sx, shy, w0, shx, sy, w1, tx, ty, w2; - - //------------------------------------------------------- Construction - // Identity matrix - trans_perspective() : - sx (1), shy(0), w0(0), - shx(0), sy (1), w1(0), - tx (0), ty (0), w2(1) {} - - // Custom matrix - trans_perspective(double v0, double v1, double v2, - double v3, double v4, double v5, - double v6, double v7, double v8) : - sx (v0), shy(v1), w0(v2), - shx(v3), sy (v4), w1(v5), - tx (v6), ty (v7), w2(v8) {} - - // Custom matrix from m[9] - explicit trans_perspective(const double* m) : - sx (m[0]), shy(m[1]), w0(m[2]), - shx(m[3]), sy (m[4]), w1(m[5]), - tx (m[6]), ty (m[7]), w2(m[8]) {} - - // From affine - explicit trans_perspective(const trans_affine& a) : - sx (a.sx ), shy(a.shy), w0(0), - shx(a.shx), sy (a.sy ), w1(0), - tx (a.tx ), ty (a.ty ), w2(1) {} - - // Rectangle to quadrilateral - trans_perspective(double x1, double y1, double x2, double y2, - const double* quad); - - // Quadrilateral to rectangle - trans_perspective(const double* quad, - double x1, double y1, double x2, double y2); - - // Arbitrary quadrilateral transformations - trans_perspective(const double* src, const double* dst); - - //-------------------------------------- Quadrilateral transformations - // The arguments are double[8] that are mapped to quadrilaterals: - // x1,y1, x2,y2, x3,y3, x4,y4 - bool quad_to_quad(const double* qs, const double* qd); - - bool rect_to_quad(double x1, double y1, - double x2, double y2, - const double* q); - - bool quad_to_rect(const double* q, - double x1, double y1, - double x2, double y2); - - // Map square (0,0,1,1) to the quadrilateral and vice versa - bool square_to_quad(const double* q); - bool quad_to_square(const double* q); - - - //--------------------------------------------------------- Operations - // Reset - load an identity matrix - const trans_perspective& reset(); - - // Invert matrix. Returns false in degenerate case - bool invert(); - - // Direct transformations operations - const trans_perspective& translate(double x, double y); - const trans_perspective& rotate(double a); - const trans_perspective& scale(double s); - const trans_perspective& scale(double x, double y); - - // Multiply the matrix by another one - const trans_perspective& multiply(const trans_perspective& m); - - // Multiply "m" by "this" and assign the result to "this" - const trans_perspective& premultiply(const trans_perspective& m); - - // Multiply matrix to inverse of another one - const trans_perspective& multiply_inv(const trans_perspective& m); - - // Multiply inverse of "m" by "this" and assign the result to "this" - const trans_perspective& premultiply_inv(const trans_perspective& m); - - // Multiply the matrix by another one - const trans_perspective& multiply(const trans_affine& m); - - // Multiply "m" by "this" and assign the result to "this" - const trans_perspective& premultiply(const trans_affine& m); - - // Multiply the matrix by inverse of another one - const trans_perspective& multiply_inv(const trans_affine& m); - - // Multiply inverse of "m" by "this" and assign the result to "this" - const trans_perspective& premultiply_inv(const trans_affine& m); - - //--------------------------------------------------------- Load/Store - void store_to(double* m) const; - const trans_perspective& load_from(const double* m); - - //---------------------------------------------------------- Operators - // Multiply the matrix by another one - const trans_perspective& operator *= (const trans_perspective& m) - { - return multiply(m); - } - const trans_perspective& operator *= (const trans_affine& m) - { - return multiply(m); - } - - // Multiply the matrix by inverse of another one - const trans_perspective& operator /= (const trans_perspective& m) - { - return multiply_inv(m); - } - const trans_perspective& operator /= (const trans_affine& m) - { - return multiply_inv(m); - } - - // Multiply the matrix by another one and return - // the result in a separete matrix. - trans_perspective operator * (const trans_perspective& m) - { - return trans_perspective(*this).multiply(m); - } - trans_perspective operator * (const trans_affine& m) - { - return trans_perspective(*this).multiply(m); - } - - // Multiply the matrix by inverse of another one - // and return the result in a separete matrix. - trans_perspective operator / (const trans_perspective& m) - { - return trans_perspective(*this).multiply_inv(m); - } - trans_perspective operator / (const trans_affine& m) - { - return trans_perspective(*this).multiply_inv(m); - } - - // Calculate and return the inverse matrix - trans_perspective operator ~ () const - { - trans_perspective ret = *this; - ret.invert(); - return ret; - } - - // Equal operator with default epsilon - bool operator == (const trans_perspective& m) const - { - return is_equal(m, affine_epsilon); - } - - // Not Equal operator with default epsilon - bool operator != (const trans_perspective& m) const - { - return !is_equal(m, affine_epsilon); - } - - //---------------------------------------------------- Transformations - // Direct transformation of x and y - void transform(double* x, double* y) const; - - // Direct transformation of x and y, affine part only - void transform_affine(double* x, double* y) const; - - // Direct transformation of x and y, 2x2 matrix only, no translation - void transform_2x2(double* x, double* y) const; - - // Inverse transformation of x and y. It works slow because - // it explicitly inverts the matrix on every call. For massive - // operations it's better to invert() the matrix and then use - // direct transformations. - void inverse_transform(double* x, double* y) const; - - - //---------------------------------------------------------- Auxiliary - const trans_perspective& from_affine(const trans_affine& a); - double determinant() const; - double determinant_reciprocal() const; - - bool is_valid(double epsilon = affine_epsilon) const; - bool is_identity(double epsilon = affine_epsilon) const; - bool is_equal(const trans_perspective& m, - double epsilon = affine_epsilon) const; - - // Determine the major affine parameters. Use with caution - // considering possible degenerate cases. - double scale() const; - double rotation() const; - void translation(double* dx, double* dy) const; - void scaling(double* x, double* y) const; - void scaling_abs(double* x, double* y) const; - - - - //-------------------------------------------------------------------- - class iterator_x - { - double den; - double den_step; - double nom_x; - double nom_x_step; - double nom_y; - double nom_y_step; - - public: - double x; - double y; - - iterator_x() {} - iterator_x(double px, double py, double step, const trans_perspective& m) : - den(px * m.w0 + py * m.w1 + m.w2), - den_step(m.w0 * step), - nom_x(px * m.sx + py * m.shx + m.tx), - nom_x_step(step * m.sx), - nom_y(px * m.shy + py * m.sy + m.ty), - nom_y_step(step * m.shy), - x(nom_x / den), - y(nom_y / den) - {} - - void operator ++ () - { - den += den_step; - nom_x += nom_x_step; - nom_y += nom_y_step; - double d = 1.0 / den; - x = nom_x * d; - y = nom_y * d; - } - }; - - //-------------------------------------------------------------------- - iterator_x begin(double x, double y, double step) const - { - return iterator_x(x, y, step, *this); - } - }; - - - - - - - - - - - - - - - //------------------------------------------------------------------------ - inline bool trans_perspective::square_to_quad(const double* q) - { - double dx = q[0] - q[2] + q[4] - q[6]; - double dy = q[1] - q[3] + q[5] - q[7]; - if(dx == 0.0 && dy == 0.0) - { - // Affine case (parallelogram) - //--------------- - sx = q[2] - q[0]; - shy = q[3] - q[1]; - w0 = 0.0; - shx = q[4] - q[2]; - sy = q[5] - q[3]; - w1 = 0.0; - tx = q[0]; - ty = q[1]; - w2 = 1.0; - } - else - { - double dx1 = q[2] - q[4]; - double dy1 = q[3] - q[5]; - double dx2 = q[6] - q[4]; - double dy2 = q[7] - q[5]; - double den = dx1 * dy2 - dx2 * dy1; - if(den == 0.0) - { - // Singular case - //--------------- - sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0; - return false; - } - // General case - //--------------- - double u = (dx * dy2 - dy * dx2) / den; - double v = (dy * dx1 - dx * dy1) / den; - sx = q[2] - q[0] + u * q[2]; - shy = q[3] - q[1] + u * q[3]; - w0 = u; - shx = q[6] - q[0] + v * q[6]; - sy = q[7] - q[1] + v * q[7]; - w1 = v; - tx = q[0]; - ty = q[1]; - w2 = 1.0; - } - return true; - } - - //------------------------------------------------------------------------ - inline bool trans_perspective::invert() - { - double d0 = sy * w2 - w1 * ty; - double d1 = w0 * ty - shy * w2; - double d2 = shy * w1 - w0 * sy; - double d = sx * d0 + shx * d1 + tx * d2; - if(d == 0.0) - { - sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0; - return false; - } - d = 1.0 / d; - trans_perspective a = *this; - sx = d * d0; - shy = d * d1; - w0 = d * d2; - shx = d * (a.w1 *a.tx - a.shx*a.w2); - sy = d * (a.sx *a.w2 - a.w0 *a.tx); - w1 = d * (a.w0 *a.shx - a.sx *a.w1); - tx = d * (a.shx*a.ty - a.sy *a.tx); - ty = d * (a.shy*a.tx - a.sx *a.ty); - w2 = d * (a.sx *a.sy - a.shy*a.shx); - return true; - } - - //------------------------------------------------------------------------ - inline bool trans_perspective::quad_to_square(const double* q) - { - if(!square_to_quad(q)) return false; - invert(); - return true; - } - - //------------------------------------------------------------------------ - inline bool trans_perspective::quad_to_quad(const double* qs, - const double* qd) - { - trans_perspective p; - if(! quad_to_square(qs)) return false; - if(!p.square_to_quad(qd)) return false; - multiply(p); - return true; - } - - //------------------------------------------------------------------------ - inline bool trans_perspective::rect_to_quad(double x1, double y1, - double x2, double y2, - const double* q) - { - double r[8]; - r[0] = r[6] = x1; - r[2] = r[4] = x2; - r[1] = r[3] = y1; - r[5] = r[7] = y2; - return quad_to_quad(r, q); - } - - //------------------------------------------------------------------------ - inline bool trans_perspective::quad_to_rect(const double* q, - double x1, double y1, - double x2, double y2) - { - double r[8]; - r[0] = r[6] = x1; - r[2] = r[4] = x2; - r[1] = r[3] = y1; - r[5] = r[7] = y2; - return quad_to_quad(q, r); - } - - //------------------------------------------------------------------------ - inline trans_perspective::trans_perspective(double x1, double y1, - double x2, double y2, - const double* quad) - { - rect_to_quad(x1, y1, x2, y2, quad); - } - - //------------------------------------------------------------------------ - inline trans_perspective::trans_perspective(const double* quad, - double x1, double y1, - double x2, double y2) - { - quad_to_rect(quad, x1, y1, x2, y2); - } - - //------------------------------------------------------------------------ - inline trans_perspective::trans_perspective(const double* src, - const double* dst) - { - quad_to_quad(src, dst); - } - - //------------------------------------------------------------------------ - inline const trans_perspective& trans_perspective::reset() - { - sx = 1; shy = 0; w0 = 0; - shx = 0; sy = 1; w1 = 0; - tx = 0; ty = 0; w2 = 1; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& - trans_perspective::multiply(const trans_perspective& a) - { - trans_perspective b = *this; - sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; - shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; - tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; - shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; - sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; - ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; - w0 = a.w0 *b.sx + a.w1 *b.shy + a.w2*b.w0; - w1 = a.w0 *b.shx + a.w1 *b.sy + a.w2*b.w1; - w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2*b.w2; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& - trans_perspective::multiply(const trans_affine& a) - { - trans_perspective b = *this; - sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; - shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; - tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; - shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; - sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; - ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& - trans_perspective::premultiply(const trans_perspective& b) - { - trans_perspective a = *this; - sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; - shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; - tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; - shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; - sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; - ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; - w0 = a.w0 *b.sx + a.w1 *b.shy + a.w2*b.w0; - w1 = a.w0 *b.shx + a.w1 *b.sy + a.w2*b.w1; - w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2*b.w2; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& - trans_perspective::premultiply(const trans_affine& b) - { - trans_perspective a = *this; - sx = a.sx *b.sx + a.shx*b.shy; - shx = a.sx *b.shx + a.shx*b.sy; - tx = a.sx *b.tx + a.shx*b.ty + a.tx; - shy = a.shy*b.sx + a.sy *b.shy; - sy = a.shy*b.shx + a.sy *b.sy; - ty = a.shy*b.tx + a.sy *b.ty + a.ty; - w0 = a.w0 *b.sx + a.w1 *b.shy; - w1 = a.w0 *b.shx + a.w1 *b.sy; - w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2; - return *this; - } - - //------------------------------------------------------------------------ - const trans_perspective& - trans_perspective::multiply_inv(const trans_perspective& m) - { - trans_perspective t = m; - t.invert(); - return multiply(t); - } - - //------------------------------------------------------------------------ - const trans_perspective& - trans_perspective::multiply_inv(const trans_affine& m) - { - trans_affine t = m; - t.invert(); - return multiply(t); - } - - //------------------------------------------------------------------------ - const trans_perspective& - trans_perspective::premultiply_inv(const trans_perspective& m) - { - trans_perspective t = m; - t.invert(); - return *this = t.multiply(*this); - } - - //------------------------------------------------------------------------ - const trans_perspective& - trans_perspective::premultiply_inv(const trans_affine& m) - { - trans_perspective t(m); - t.invert(); - return *this = t.multiply(*this); - } - - //------------------------------------------------------------------------ - inline const trans_perspective& - trans_perspective::translate(double x, double y) - { - tx += x; - ty += y; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& trans_perspective::rotate(double a) - { - multiply(trans_affine_rotation(a)); - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& trans_perspective::scale(double s) - { - multiply(trans_affine_scaling(s)); - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& trans_perspective::scale(double x, double y) - { - multiply(trans_affine_scaling(x, y)); - return *this; - } - - //------------------------------------------------------------------------ - inline void trans_perspective::transform(double* px, double* py) const - { - double x = *px; - double y = *py; - double m = 1.0 / (x*w0 + y*w1 + w2); - *px = m * (x*sx + y*shx + tx); - *py = m * (x*shy + y*sy + ty); - } - - //------------------------------------------------------------------------ - inline void trans_perspective::transform_affine(double* x, double* y) const - { - double tmp = *x; - *x = tmp * sx + *y * shx + tx; - *y = tmp * shy + *y * sy + ty; - } - - //------------------------------------------------------------------------ - inline void trans_perspective::transform_2x2(double* x, double* y) const - { - double tmp = *x; - *x = tmp * sx + *y * shx; - *y = tmp * shy + *y * sy; - } - - //------------------------------------------------------------------------ - inline void trans_perspective::inverse_transform(double* x, double* y) const - { - trans_perspective t(*this); - if(t.invert()) t.transform(x, y); - } - - //------------------------------------------------------------------------ - inline void trans_perspective::store_to(double* m) const - { - *m++ = sx; *m++ = shy; *m++ = w0; - *m++ = shx; *m++ = sy; *m++ = w1; - *m++ = tx; *m++ = ty; *m++ = w2; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& trans_perspective::load_from(const double* m) - { - sx = *m++; shy = *m++; w0 = *m++; - shx = *m++; sy = *m++; w1 = *m++; - tx = *m++; ty = *m++; w2 = *m++; - return *this; - } - - //------------------------------------------------------------------------ - inline const trans_perspective& - trans_perspective::from_affine(const trans_affine& a) - { - sx = a.sx; shy = a.shy; w0 = 0; - shx = a.shx; sy = a.sy; w1 = 0; - tx = a.tx; ty = a.ty; w2 = 1; - return *this; - } - - //------------------------------------------------------------------------ - inline double trans_perspective::determinant() const - { - return sx * (sy * w2 - ty * w1) + - shx * (ty * w0 - shy * w2) + - tx * (shy * w1 - sy * w0); - } - - //------------------------------------------------------------------------ - inline double trans_perspective::determinant_reciprocal() const - { - return 1.0 / determinant(); - } - - //------------------------------------------------------------------------ - inline bool trans_perspective::is_valid(double epsilon) const - { - return fabs(sx) > epsilon && fabs(sy) > epsilon && fabs(w2) > epsilon; - } - - //------------------------------------------------------------------------ - inline bool trans_perspective::is_identity(double epsilon) const - { - return is_equal_eps(sx, 1.0, epsilon) && - is_equal_eps(shy, 0.0, epsilon) && - is_equal_eps(w0, 0.0, epsilon) && - is_equal_eps(shx, 0.0, epsilon) && - is_equal_eps(sy, 1.0, epsilon) && - is_equal_eps(w1, 0.0, epsilon) && - is_equal_eps(tx, 0.0, epsilon) && - is_equal_eps(ty, 0.0, epsilon) && - is_equal_eps(w2, 1.0, epsilon); - } - - //------------------------------------------------------------------------ - inline bool trans_perspective::is_equal(const trans_perspective& m, - double epsilon) const - { - return is_equal_eps(sx, m.sx, epsilon) && - is_equal_eps(shy, m.shy, epsilon) && - is_equal_eps(w0, m.w0, epsilon) && - is_equal_eps(shx, m.shx, epsilon) && - is_equal_eps(sy, m.sy, epsilon) && - is_equal_eps(w1, m.w1, epsilon) && - is_equal_eps(tx, m.tx, epsilon) && - is_equal_eps(ty, m.ty, epsilon) && - is_equal_eps(w2, m.w2, epsilon); - } - - //------------------------------------------------------------------------ - inline double trans_perspective::scale() const - { - double x = 0.707106781 * sx + 0.707106781 * shx; - double y = 0.707106781 * shy + 0.707106781 * sy; - return sqrt(x*x + y*y); - } - - //------------------------------------------------------------------------ - inline double trans_perspective::rotation() const - { - double x1 = 0.0; - double y1 = 0.0; - double x2 = 1.0; - double y2 = 0.0; - transform(&x1, &y1); - transform(&x2, &y2); - return atan2(y2-y1, x2-x1); - } - - //------------------------------------------------------------------------ - void trans_perspective::translation(double* dx, double* dy) const - { - *dx = tx; - *dy = ty; - } - - //------------------------------------------------------------------------ - void trans_perspective::scaling(double* x, double* y) const - { - double x1 = 0.0; - double y1 = 0.0; - double x2 = 1.0; - double y2 = 1.0; - trans_perspective t(*this); - t *= trans_affine_rotation(-rotation()); - t.transform(&x1, &y1); - t.transform(&x2, &y2); - *x = x2 - x1; - *y = y2 - y1; - } - - //------------------------------------------------------------------------ - void trans_perspective::scaling_abs(double* x, double* y) const - { - *x = sqrt(sx * sx + shx * shx); - *y = sqrt(shy * shy + sy * sy); - } - - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_trans_single_path.h corsix-th-0.62/agg/include/agg_trans_single_path.h --- corsix-th-0.30/agg/include/agg_trans_single_path.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_trans_single_path.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_TRANS_SINGLE_PATH_INCLUDED -#define AGG_TRANS_SINGLE_PATH_INCLUDED - -#include "agg_basics.h" -#include "agg_vertex_sequence.h" - -namespace agg -{ - - // See also: agg_trans_single_path.cpp - // - //-------------------------------------------------------trans_single_path - class trans_single_path - { - enum status_e - { - initial, - making_path, - ready - }; - - public: - typedef vertex_sequence vertex_storage; - - trans_single_path(); - - //-------------------------------------------------------------------- - void base_length(double v) { m_base_length = v; } - double base_length() const { return m_base_length; } - - //-------------------------------------------------------------------- - void preserve_x_scale(bool f) { m_preserve_x_scale = f; } - bool preserve_x_scale() const { return m_preserve_x_scale; } - - //-------------------------------------------------------------------- - void reset(); - void move_to(double x, double y); - void line_to(double x, double y); - void finalize_path(); - - //-------------------------------------------------------------------- - template - void add_path(VertexSource& vs, unsigned path_id=0) - { - double x; - double y; - - unsigned cmd; - vs.rewind(path_id); - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - if(is_move_to(cmd)) - { - move_to(x, y); - } - else - { - if(is_vertex(cmd)) - { - line_to(x, y); - } - } - } - finalize_path(); - } - - //-------------------------------------------------------------------- - double total_length() const; - void transform(double *x, double *y) const; - - private: - vertex_storage m_src_vertices; - double m_base_length; - double m_kindex; - status_e m_status; - bool m_preserve_x_scale; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_trans_viewport.h corsix-th-0.62/agg/include/agg_trans_viewport.h --- corsix-th-0.30/agg/include/agg_trans_viewport.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_trans_viewport.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,303 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Viewport transformer - simple orthogonal conversions from world coordinates -// to screen (device) ones. -// -//---------------------------------------------------------------------------- - -#ifndef AGG_TRANS_VIEWPORT_INCLUDED -#define AGG_TRANS_VIEWPORT_INCLUDED - -#include -#include "agg_trans_affine.h" - - -namespace agg -{ - - enum aspect_ratio_e - { - aspect_ratio_stretch, - aspect_ratio_meet, - aspect_ratio_slice - }; - - - //----------------------------------------------------------trans_viewport - class trans_viewport - { - public: - //------------------------------------------------------------------- - trans_viewport() : - m_world_x1(0.0), - m_world_y1(0.0), - m_world_x2(1.0), - m_world_y2(1.0), - m_device_x1(0.0), - m_device_y1(0.0), - m_device_x2(1.0), - m_device_y2(1.0), - m_aspect(aspect_ratio_stretch), - m_is_valid(true), - m_align_x(0.5), - m_align_y(0.5), - m_wx1(0.0), - m_wy1(0.0), - m_wx2(1.0), - m_wy2(1.0), - m_dx1(0.0), - m_dy1(0.0), - m_kx(1.0), - m_ky(1.0) - {} - - //------------------------------------------------------------------- - void preserve_aspect_ratio(double alignx, - double aligny, - aspect_ratio_e aspect) - { - m_align_x = alignx; - m_align_y = aligny; - m_aspect = aspect; - update(); - } - - //------------------------------------------------------------------- - void device_viewport(double x1, double y1, double x2, double y2) - { - m_device_x1 = x1; - m_device_y1 = y1; - m_device_x2 = x2; - m_device_y2 = y2; - update(); - } - - //------------------------------------------------------------------- - void world_viewport(double x1, double y1, double x2, double y2) - { - m_world_x1 = x1; - m_world_y1 = y1; - m_world_x2 = x2; - m_world_y2 = y2; - update(); - } - - //------------------------------------------------------------------- - void device_viewport(double* x1, double* y1, double* x2, double* y2) const - { - *x1 = m_device_x1; - *y1 = m_device_y1; - *x2 = m_device_x2; - *y2 = m_device_y2; - } - - //------------------------------------------------------------------- - void world_viewport(double* x1, double* y1, double* x2, double* y2) const - { - *x1 = m_world_x1; - *y1 = m_world_y1; - *x2 = m_world_x2; - *y2 = m_world_y2; - } - - //------------------------------------------------------------------- - void world_viewport_actual(double* x1, double* y1, - double* x2, double* y2) const - { - *x1 = m_wx1; - *y1 = m_wy1; - *x2 = m_wx2; - *y2 = m_wy2; - } - - //------------------------------------------------------------------- - bool is_valid() const { return m_is_valid; } - double align_x() const { return m_align_x; } - double align_y() const { return m_align_y; } - aspect_ratio_e aspect_ratio() const { return m_aspect; } - - //------------------------------------------------------------------- - void transform(double* x, double* y) const - { - *x = (*x - m_wx1) * m_kx + m_dx1; - *y = (*y - m_wy1) * m_ky + m_dy1; - } - - //------------------------------------------------------------------- - void transform_scale_only(double* x, double* y) const - { - *x *= m_kx; - *y *= m_ky; - } - - //------------------------------------------------------------------- - void inverse_transform(double* x, double* y) const - { - *x = (*x - m_dx1) / m_kx + m_wx1; - *y = (*y - m_dy1) / m_ky + m_wy1; - } - - //------------------------------------------------------------------- - void inverse_transform_scale_only(double* x, double* y) const - { - *x /= m_kx; - *y /= m_ky; - } - - //------------------------------------------------------------------- - double device_dx() const { return m_dx1 - m_wx1 * m_kx; } - double device_dy() const { return m_dy1 - m_wy1 * m_ky; } - - //------------------------------------------------------------------- - double scale_x() const - { - return m_kx; - } - - //------------------------------------------------------------------- - double scale_y() const - { - return m_ky; - } - - //------------------------------------------------------------------- - double scale() const - { - return (m_kx + m_ky) * 0.5; - } - - //------------------------------------------------------------------- - trans_affine to_affine() const - { - trans_affine mtx = trans_affine_translation(-m_wx1, -m_wy1); - mtx *= trans_affine_scaling(m_kx, m_ky); - mtx *= trans_affine_translation(m_dx1, m_dy1); - return mtx; - } - - //------------------------------------------------------------------- - trans_affine to_affine_scale_only() const - { - return trans_affine_scaling(m_kx, m_ky); - } - - //------------------------------------------------------------------- - unsigned byte_size() const - { - return sizeof(*this); - } - - void serialize(int8u* ptr) const - { - memcpy(ptr, this, sizeof(*this)); - } - - void deserialize(const int8u* ptr) - { - memcpy(this, ptr, sizeof(*this)); - } - - private: - void update(); - - double m_world_x1; - double m_world_y1; - double m_world_x2; - double m_world_y2; - double m_device_x1; - double m_device_y1; - double m_device_x2; - double m_device_y2; - aspect_ratio_e m_aspect; - bool m_is_valid; - double m_align_x; - double m_align_y; - double m_wx1; - double m_wy1; - double m_wx2; - double m_wy2; - double m_dx1; - double m_dy1; - double m_kx; - double m_ky; - }; - - - - //----------------------------------------------------------------------- - inline void trans_viewport::update() - { - const double epsilon = 1e-30; - if(fabs(m_world_x1 - m_world_x2) < epsilon || - fabs(m_world_y1 - m_world_y2) < epsilon || - fabs(m_device_x1 - m_device_x2) < epsilon || - fabs(m_device_y1 - m_device_y2) < epsilon) - { - m_wx1 = m_world_x1; - m_wy1 = m_world_y1; - m_wx2 = m_world_x1 + 1.0; - m_wy2 = m_world_y2 + 1.0; - m_dx1 = m_device_x1; - m_dy1 = m_device_y1; - m_kx = 1.0; - m_ky = 1.0; - m_is_valid = false; - return; - } - - double world_x1 = m_world_x1; - double world_y1 = m_world_y1; - double world_x2 = m_world_x2; - double world_y2 = m_world_y2; - double device_x1 = m_device_x1; - double device_y1 = m_device_y1; - double device_x2 = m_device_x2; - double device_y2 = m_device_y2; - if(m_aspect != aspect_ratio_stretch) - { - double d; - m_kx = (device_x2 - device_x1) / (world_x2 - world_x1); - m_ky = (device_y2 - device_y1) / (world_y2 - world_y1); - - if((m_aspect == aspect_ratio_meet) == (m_kx < m_ky)) - { - d = (world_y2 - world_y1) * m_ky / m_kx; - world_y1 += (world_y2 - world_y1 - d) * m_align_y; - world_y2 = world_y1 + d; - } - else - { - d = (world_x2 - world_x1) * m_kx / m_ky; - world_x1 += (world_x2 - world_x1 - d) * m_align_x; - world_x2 = world_x1 + d; - } - } - m_wx1 = world_x1; - m_wy1 = world_y1; - m_wx2 = world_x2; - m_wy2 = world_y2; - m_dx1 = device_x1; - m_dy1 = device_y1; - m_kx = (device_x2 - device_x1) / (world_x2 - world_x1); - m_ky = (device_y2 - device_y1) / (world_y2 - world_y1); - m_is_valid = true; - } - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_trans_warp_magnifier.h corsix-th-0.62/agg/include/agg_trans_warp_magnifier.h --- corsix-th-0.30/agg/include/agg_trans_warp_magnifier.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_trans_warp_magnifier.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_WARP_MAGNIFIER_INCLUDED -#define AGG_WARP_MAGNIFIER_INCLUDED - - -namespace agg -{ - - //----------------------------------------------------trans_warp_magnifier - // - // See Inmplementation agg_trans_warp_magnifier.cpp - // - class trans_warp_magnifier - { - public: - trans_warp_magnifier() : m_xc(0.0), m_yc(0.0), m_magn(1.0), m_radius(1.0) {} - - void center(double x, double y) { m_xc = x; m_yc = y; } - void magnification(double m) { m_magn = m; } - void radius(double r) { m_radius = r; } - - double xc() const { return m_xc; } - double yc() const { return m_yc; } - double magnification() const { return m_magn; } - double radius() const { return m_radius; } - - void transform(double* x, double* y) const; - void inverse_transform(double* x, double* y) const; - - private: - double m_xc; - double m_yc; - double m_magn; - double m_radius; - }; - - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_vcgen_bspline.h corsix-th-0.62/agg/include/agg_vcgen_bspline.h --- corsix-th-0.30/agg/include/agg_vcgen_bspline.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vcgen_bspline.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VCGEN_BSPLINE_INCLUDED -#define AGG_VCGEN_BSPLINE_INCLUDED - -#include "agg_basics.h" -#include "agg_array.h" -#include "agg_bspline.h" - - -namespace agg -{ - - //==========================================================vcgen_bspline - class vcgen_bspline - { - enum status_e - { - initial, - ready, - polygon, - end_poly, - stop - }; - - public: - typedef pod_bvector vertex_storage; - - vcgen_bspline(); - - void interpolation_step(double v) { m_interpolation_step = v; } - double interpolation_step() const { return m_interpolation_step; } - - // Vertex Generator Interface - void remove_all(); - void add_vertex(double x, double y, unsigned cmd); - - // Vertex Source Interface - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - vcgen_bspline(const vcgen_bspline&); - const vcgen_bspline& operator = (const vcgen_bspline&); - - vertex_storage m_src_vertices; - bspline m_spline_x; - bspline m_spline_y; - double m_interpolation_step; - unsigned m_closed; - status_e m_status; - unsigned m_src_vertex; - double m_cur_abscissa; - double m_max_abscissa; - }; - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_vcgen_contour.h corsix-th-0.62/agg/include/agg_vcgen_contour.h --- corsix-th-0.30/agg/include/agg_vcgen_contour.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vcgen_contour.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VCGEN_CONTOUR_INCLUDED -#define AGG_VCGEN_CONTOUR_INCLUDED - -#include "agg_math_stroke.h" - -namespace agg -{ - - //----------------------------------------------------------vcgen_contour - // - // See Implementation agg_vcgen_contour.cpp - // - class vcgen_contour - { - enum status_e - { - initial, - ready, - outline, - out_vertices, - end_poly, - stop - }; - - public: - typedef vertex_sequence vertex_storage; - typedef pod_bvector coord_storage; - - vcgen_contour(); - - void line_cap(line_cap_e lc) { m_stroker.line_cap(lc); } - void line_join(line_join_e lj) { m_stroker.line_join(lj); } - void inner_join(inner_join_e ij) { m_stroker.inner_join(ij); } - - line_cap_e line_cap() const { return m_stroker.line_cap(); } - line_join_e line_join() const { return m_stroker.line_join(); } - inner_join_e inner_join() const { return m_stroker.inner_join(); } - - void width(double w) { m_stroker.width(m_width = w); } - void miter_limit(double ml) { m_stroker.miter_limit(ml); } - void miter_limit_theta(double t) { m_stroker.miter_limit_theta(t); } - void inner_miter_limit(double ml) { m_stroker.inner_miter_limit(ml); } - void approximation_scale(double as) { m_stroker.approximation_scale(as); } - - double width() const { return m_width; } - double miter_limit() const { return m_stroker.miter_limit(); } - double inner_miter_limit() const { return m_stroker.inner_miter_limit(); } - double approximation_scale() const { return m_stroker.approximation_scale(); } - - void auto_detect_orientation(bool v) { m_auto_detect = v; } - bool auto_detect_orientation() const { return m_auto_detect; } - - // Generator interface - void remove_all(); - void add_vertex(double x, double y, unsigned cmd); - - // Vertex Source Interface - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - vcgen_contour(const vcgen_contour&); - const vcgen_contour& operator = (const vcgen_contour&); - - math_stroke m_stroker; - double m_width; - vertex_storage m_src_vertices; - coord_storage m_out_vertices; - status_e m_status; - unsigned m_src_vertex; - unsigned m_out_vertex; - unsigned m_closed; - unsigned m_orientation; - bool m_auto_detect; - }; - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_vcgen_dash.h corsix-th-0.62/agg/include/agg_vcgen_dash.h --- corsix-th-0.30/agg/include/agg_vcgen_dash.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vcgen_dash.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Line dash generator -// -//---------------------------------------------------------------------------- -#ifndef AGG_VCGEN_DASH_INCLUDED -#define AGG_VCGEN_DASH_INCLUDED - -#include "agg_basics.h" -#include "agg_vertex_sequence.h" - -namespace agg -{ - - //---------------------------------------------------------------vcgen_dash - // - // See Implementation agg_vcgen_dash.cpp - // - class vcgen_dash - { - enum max_dashes_e - { - max_dashes = 32 - }; - - enum status_e - { - initial, - ready, - polyline, - stop - }; - - public: - typedef vertex_sequence vertex_storage; - - vcgen_dash(); - - void remove_all_dashes(); - void add_dash(double dash_len, double gap_len); - void dash_start(double ds); - - void shorten(double s) { m_shorten = s; } - double shorten() const { return m_shorten; } - - // Vertex Generator Interface - void remove_all(); - void add_vertex(double x, double y, unsigned cmd); - - // Vertex Source Interface - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - vcgen_dash(const vcgen_dash&); - const vcgen_dash& operator = (const vcgen_dash&); - - void calc_dash_start(double ds); - - double m_dashes[max_dashes]; - double m_total_dash_len; - unsigned m_num_dashes; - double m_dash_start; - double m_shorten; - double m_curr_dash_start; - unsigned m_curr_dash; - double m_curr_rest; - const vertex_dist* m_v1; - const vertex_dist* m_v2; - - vertex_storage m_src_vertices; - unsigned m_closed; - status_e m_status; - unsigned m_src_vertex; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_vcgen_markers_term.h corsix-th-0.62/agg/include/agg_vcgen_markers_term.h --- corsix-th-0.30/agg/include/agg_vcgen_markers_term.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vcgen_markers_term.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VCGEN_MARKERS_TERM_INCLUDED -#define AGG_VCGEN_MARKERS_TERM_INCLUDED - -#include "agg_basics.h" -#include "agg_vertex_sequence.h" - -namespace agg -{ - - //======================================================vcgen_markers_term - // - // See Implemantation agg_vcgen_markers_term.cpp - // Terminal markers generator (arrowhead/arrowtail) - // - //------------------------------------------------------------------------ - class vcgen_markers_term - { - public: - vcgen_markers_term() : m_curr_id(0), m_curr_idx(0) {} - - // Vertex Generator Interface - void remove_all(); - void add_vertex(double x, double y, unsigned cmd); - - // Vertex Source Interface - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - vcgen_markers_term(const vcgen_markers_term&); - const vcgen_markers_term& operator = (const vcgen_markers_term&); - - struct coord_type - { - double x, y; - - coord_type() {} - coord_type(double x_, double y_) : x(x_), y(y_) {} - }; - - typedef pod_bvector coord_storage; - - coord_storage m_markers; - unsigned m_curr_id; - unsigned m_curr_idx; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_vcgen_smooth_poly1.h corsix-th-0.62/agg/include/agg_vcgen_smooth_poly1.h --- corsix-th-0.30/agg/include/agg_vcgen_smooth_poly1.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vcgen_smooth_poly1.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VCGEN_SMOOTH_POLY1_INCLUDED -#define AGG_VCGEN_SMOOTH_POLY1_INCLUDED - -#include "agg_basics.h" -#include "agg_vertex_sequence.h" - - -namespace agg -{ - - //======================================================vcgen_smooth_poly1 - // - // See Implementation agg_vcgen_smooth_poly1.cpp - // Smooth polygon generator - // - //------------------------------------------------------------------------ - class vcgen_smooth_poly1 - { - enum status_e - { - initial, - ready, - polygon, - ctrl_b, - ctrl_e, - ctrl1, - ctrl2, - end_poly, - stop - }; - - public: - typedef vertex_sequence vertex_storage; - - vcgen_smooth_poly1(); - - void smooth_value(double v) { m_smooth_value = v * 0.5; } - double smooth_value() const { return m_smooth_value * 2.0; } - - // Vertex Generator Interface - void remove_all(); - void add_vertex(double x, double y, unsigned cmd); - - // Vertex Source Interface - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - vcgen_smooth_poly1(const vcgen_smooth_poly1&); - const vcgen_smooth_poly1& operator = (const vcgen_smooth_poly1&); - - void calculate(const vertex_dist& v0, - const vertex_dist& v1, - const vertex_dist& v2, - const vertex_dist& v3); - - vertex_storage m_src_vertices; - double m_smooth_value; - unsigned m_closed; - status_e m_status; - unsigned m_src_vertex; - double m_ctrl1_x; - double m_ctrl1_y; - double m_ctrl2_x; - double m_ctrl2_y; - }; - -} - - -#endif - diff -Nru corsix-th-0.30/agg/include/agg_vcgen_stroke.cpp corsix-th-0.62/agg/include/agg_vcgen_stroke.cpp --- corsix-th-0.30/agg/include/agg_vcgen_stroke.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vcgen_stroke.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,213 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Stroke generator -// -//---------------------------------------------------------------------------- -#include -#include "agg_vcgen_stroke.h" -#include "agg_shorten_path.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - vcgen_stroke::vcgen_stroke() : - m_stroker(), - m_src_vertices(), - m_out_vertices(), - m_shorten(0.0), - m_closed(0), - m_status(initial), - m_src_vertex(0), - m_out_vertex(0) - { - } - - //------------------------------------------------------------------------ - void vcgen_stroke::remove_all() - { - m_src_vertices.remove_all(); - m_closed = 0; - m_status = initial; - } - - - //------------------------------------------------------------------------ - void vcgen_stroke::add_vertex(double x, double y, unsigned cmd) - { - m_status = initial; - if(is_move_to(cmd)) - { - m_src_vertices.modify_last(vertex_dist(x, y)); - } - else - { - if(is_vertex(cmd)) - { - m_src_vertices.add(vertex_dist(x, y)); - } - else - { - m_closed = get_close_flag(cmd); - } - } - } - - //------------------------------------------------------------------------ - void vcgen_stroke::rewind(unsigned) - { - if(m_status == initial) - { - m_src_vertices.close(m_closed != 0); - shorten_path(m_src_vertices, m_shorten, m_closed); - if(m_src_vertices.size() < 3) m_closed = 0; - } - m_status = ready; - m_src_vertex = 0; - m_out_vertex = 0; - } - - - //------------------------------------------------------------------------ - unsigned vcgen_stroke::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_line_to; - while(!is_stop(cmd)) - { - switch(m_status) - { - case initial: - rewind(0); - - case ready: - if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) - { - cmd = path_cmd_stop; - break; - } - m_status = m_closed ? outline1 : cap1; - cmd = path_cmd_move_to; - m_src_vertex = 0; - m_out_vertex = 0; - break; - - case cap1: - m_stroker.calc_cap(m_out_vertices, - m_src_vertices[0], - m_src_vertices[1], - m_src_vertices[0].dist); - m_src_vertex = 1; - m_prev_status = outline1; - m_status = out_vertices; - m_out_vertex = 0; - break; - - case cap2: - m_stroker.calc_cap(m_out_vertices, - m_src_vertices[m_src_vertices.size() - 1], - m_src_vertices[m_src_vertices.size() - 2], - m_src_vertices[m_src_vertices.size() - 2].dist); - m_prev_status = outline2; - m_status = out_vertices; - m_out_vertex = 0; - break; - - case outline1: - if(m_closed) - { - if(m_src_vertex >= m_src_vertices.size()) - { - m_prev_status = close_first; - m_status = end_poly1; - break; - } - } - else - { - if(m_src_vertex >= m_src_vertices.size() - 1) - { - m_status = cap2; - break; - } - } - m_stroker.calc_join(m_out_vertices, - m_src_vertices.prev(m_src_vertex), - m_src_vertices.curr(m_src_vertex), - m_src_vertices.next(m_src_vertex), - m_src_vertices.prev(m_src_vertex).dist, - m_src_vertices.curr(m_src_vertex).dist); - ++m_src_vertex; - m_prev_status = m_status; - m_status = out_vertices; - m_out_vertex = 0; - break; - - case close_first: - m_status = outline2; - cmd = path_cmd_move_to; - - case outline2: - if(m_src_vertex <= unsigned(m_closed == 0)) - { - m_status = end_poly2; - m_prev_status = stop; - break; - } - - --m_src_vertex; - m_stroker.calc_join(m_out_vertices, - m_src_vertices.next(m_src_vertex), - m_src_vertices.curr(m_src_vertex), - m_src_vertices.prev(m_src_vertex), - m_src_vertices.curr(m_src_vertex).dist, - m_src_vertices.prev(m_src_vertex).dist); - - m_prev_status = m_status; - m_status = out_vertices; - m_out_vertex = 0; - break; - - case out_vertices: - if(m_out_vertex >= m_out_vertices.size()) - { - m_status = m_prev_status; - } - else - { - const point_d& c = m_out_vertices[m_out_vertex++]; - *x = c.x; - *y = c.y; - return cmd; - } - break; - - case end_poly1: - m_status = m_prev_status; - return path_cmd_end_poly | path_flags_close | path_flags_ccw; - - case end_poly2: - m_status = m_prev_status; - return path_cmd_end_poly | path_flags_close | path_flags_cw; - - case stop: - cmd = path_cmd_stop; - break; - } - } - return cmd; - } - -} diff -Nru corsix-th-0.30/agg/include/agg_vcgen_stroke.h corsix-th-0.62/agg/include/agg_vcgen_stroke.h --- corsix-th-0.30/agg/include/agg_vcgen_stroke.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vcgen_stroke.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VCGEN_STROKE_INCLUDED -#define AGG_VCGEN_STROKE_INCLUDED - -#include "agg_math_stroke.h" - - -namespace agg -{ - - //============================================================vcgen_stroke - // - // See Implementation agg_vcgen_stroke.cpp - // Stroke generator - // - //------------------------------------------------------------------------ - class vcgen_stroke - { - enum status_e - { - initial, - ready, - cap1, - cap2, - outline1, - close_first, - outline2, - out_vertices, - end_poly1, - end_poly2, - stop - }; - - public: - typedef vertex_sequence vertex_storage; - typedef pod_bvector coord_storage; - - vcgen_stroke(); - - void line_cap(line_cap_e lc) { m_stroker.line_cap(lc); } - void line_join(line_join_e lj) { m_stroker.line_join(lj); } - void inner_join(inner_join_e ij) { m_stroker.inner_join(ij); } - - line_cap_e line_cap() const { return m_stroker.line_cap(); } - line_join_e line_join() const { return m_stroker.line_join(); } - inner_join_e inner_join() const { return m_stroker.inner_join(); } - - void width(double w) { m_stroker.width(w); } - void miter_limit(double ml) { m_stroker.miter_limit(ml); } - void miter_limit_theta(double t) { m_stroker.miter_limit_theta(t); } - void inner_miter_limit(double ml) { m_stroker.inner_miter_limit(ml); } - void approximation_scale(double as) { m_stroker.approximation_scale(as); } - - double width() const { return m_stroker.width(); } - double miter_limit() const { return m_stroker.miter_limit(); } - double inner_miter_limit() const { return m_stroker.inner_miter_limit(); } - double approximation_scale() const { return m_stroker.approximation_scale(); } - - void shorten(double s) { m_shorten = s; } - double shorten() const { return m_shorten; } - - // Vertex Generator Interface - void remove_all(); - void add_vertex(double x, double y, unsigned cmd); - - // Vertex Source Interface - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - private: - vcgen_stroke(const vcgen_stroke&); - const vcgen_stroke& operator = (const vcgen_stroke&); - - math_stroke m_stroker; - vertex_storage m_src_vertices; - coord_storage m_out_vertices; - double m_shorten; - unsigned m_closed; - status_e m_status; - status_e m_prev_status; - unsigned m_src_vertex; - unsigned m_out_vertex; - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_vcgen_vertex_sequence.h corsix-th-0.62/agg/include/agg_vcgen_vertex_sequence.h --- corsix-th-0.30/agg/include/agg_vcgen_vertex_sequence.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vcgen_vertex_sequence.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VCGEN_VERTEX_SEQUENCE_INCLUDED -#define AGG_VCGEN_VERTEX_SEQUENCE_INCLUDED - -#include "agg_basics.h" -#include "agg_vertex_sequence.h" -#include "agg_shorten_path.h" - -namespace agg -{ - - //===================================================vcgen_vertex_sequence - class vcgen_vertex_sequence - { - public: - typedef vertex_dist_cmd vertex_type; - typedef vertex_sequence vertex_storage; - - vcgen_vertex_sequence() : - m_flags(0), - m_cur_vertex(0), - m_shorten(0.0), - m_ready(false) - { - } - - // Vertex Generator Interface - void remove_all(); - void add_vertex(double x, double y, unsigned cmd); - - // Vertex Source Interface - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - void shorten(double s) { m_shorten = s; } - double shorten() const { return m_shorten; } - - private: - vcgen_vertex_sequence(const vcgen_vertex_sequence&); - const vcgen_vertex_sequence& operator = (const vcgen_vertex_sequence&); - - vertex_storage m_src_vertices; - unsigned m_flags; - unsigned m_cur_vertex; - double m_shorten; - bool m_ready; - }; - - - //------------------------------------------------------------------------ - inline void vcgen_vertex_sequence::remove_all() - { - m_ready = false; - m_src_vertices.remove_all(); - m_cur_vertex = 0; - m_flags = 0; - } - - //------------------------------------------------------------------------ - inline void vcgen_vertex_sequence::add_vertex(double x, double y, unsigned cmd) - { - m_ready = false; - if(is_move_to(cmd)) - { - m_src_vertices.modify_last(vertex_dist_cmd(x, y, cmd)); - } - else - { - if(is_vertex(cmd)) - { - m_src_vertices.add(vertex_dist_cmd(x, y, cmd)); - } - else - { - m_flags = cmd & path_flags_mask; - } - } - } - - - //------------------------------------------------------------------------ - inline void vcgen_vertex_sequence::rewind(unsigned) - { - if(!m_ready) - { - m_src_vertices.close(is_closed(m_flags)); - shorten_path(m_src_vertices, m_shorten, get_close_flag(m_flags)); - } - m_ready = true; - m_cur_vertex = 0; - } - - //------------------------------------------------------------------------ - inline unsigned vcgen_vertex_sequence::vertex(double* x, double* y) - { - if(!m_ready) - { - rewind(0); - } - - if(m_cur_vertex == m_src_vertices.size()) - { - ++m_cur_vertex; - return path_cmd_end_poly | m_flags; - } - - if(m_cur_vertex > m_src_vertices.size()) - { - return path_cmd_stop; - } - - vertex_type& v = m_src_vertices[m_cur_vertex++]; - *x = v.x; - *y = v.y; - return v.cmd; - } - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_vertex_sequence.h corsix-th-0.62/agg/include/agg_vertex_sequence.h --- corsix-th-0.30/agg/include/agg_vertex_sequence.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vertex_sequence.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,172 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// vertex_sequence container and vertex_dist struct -// -//---------------------------------------------------------------------------- -#ifndef AGG_VERTEX_SEQUENCE_INCLUDED -#define AGG_VERTEX_SEQUENCE_INCLUDED - -#include "agg_basics.h" -#include "agg_array.h" -#include "agg_math.h" - -namespace agg -{ - - //----------------------------------------------------------vertex_sequence - // Modified agg::pod_bvector. The data is interpreted as a sequence - // of vertices. It means that the type T must expose: - // - // bool T::operator() (const T& val) - // - // that is called every time new vertex is being added. The main purpose - // of this operator is the possibility to calculate some values during - // adding and to return true if the vertex fits some criteria or false if - // it doesn't. In the last case the new vertex is not added. - // - // The simple example is filtering coinciding vertices with calculation - // of the distance between the current and previous ones: - // - // struct vertex_dist - // { - // double x; - // double y; - // double dist; - // - // vertex_dist() {} - // vertex_dist(double x_, double y_) : - // x(x_), - // y(y_), - // dist(0.0) - // { - // } - // - // bool operator () (const vertex_dist& val) - // { - // return (dist = calc_distance(x, y, val.x, val.y)) > EPSILON; - // } - // }; - // - // Function close() calls this operator and removes the last vertex if - // necessary. - //------------------------------------------------------------------------ - template - class vertex_sequence : public pod_bvector - { - public: - typedef pod_bvector base_type; - - void add(const T& val); - void modify_last(const T& val); - void close(bool remove_flag); - }; - - - - //------------------------------------------------------------------------ - template - void vertex_sequence::add(const T& val) - { - if(base_type::size() > 1) - { - if(!(*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) - { - base_type::remove_last(); - } - } - base_type::add(val); - } - - - //------------------------------------------------------------------------ - template - void vertex_sequence::modify_last(const T& val) - { - base_type::remove_last(); - add(val); - } - - - - //------------------------------------------------------------------------ - template - void vertex_sequence::close(bool closed) - { - while(base_type::size() > 1) - { - if((*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) break; - T t = (*this)[base_type::size() - 1]; - base_type::remove_last(); - modify_last(t); - } - - if(closed) - { - while(base_type::size() > 1) - { - if((*this)[base_type::size() - 1]((*this)[0])) break; - base_type::remove_last(); - } - } - } - - - //-------------------------------------------------------------vertex_dist - // Vertex (x, y) with the distance to the next one. The last vertex has - // distance between the last and the first points if the polygon is closed - // and 0.0 if it's a polyline. - struct vertex_dist - { - double x; - double y; - double dist; - - vertex_dist() {} - vertex_dist(double x_, double y_) : - x(x_), - y(y_), - dist(0.0) - { - } - - bool operator () (const vertex_dist& val) - { - bool ret = (dist = calc_distance(x, y, val.x, val.y)) > vertex_dist_epsilon; - if(!ret) dist = 1.0 / vertex_dist_epsilon; - return ret; - } - }; - - - - //--------------------------------------------------------vertex_dist_cmd - // Save as the above but with additional "command" value - struct vertex_dist_cmd : public vertex_dist - { - unsigned cmd; - - vertex_dist_cmd() {} - vertex_dist_cmd(double x_, double y_, unsigned cmd_) : - vertex_dist(x_, y_), - cmd(cmd_) - { - } - }; - - -} - -#endif diff -Nru corsix-th-0.30/agg/include/agg_vpgen_clip_polygon.h corsix-th-0.62/agg/include/agg_vpgen_clip_polygon.h --- corsix-th-0.30/agg/include/agg_vpgen_clip_polygon.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vpgen_clip_polygon.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VPGEN_CLIP_POLYGON_INCLUDED -#define AGG_VPGEN_CLIP_POLYGON_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //======================================================vpgen_clip_polygon - // - // See Implementation agg_vpgen_clip_polygon.cpp - // - class vpgen_clip_polygon - { - public: - vpgen_clip_polygon() : - m_clip_box(0, 0, 1, 1), - m_x1(0), - m_y1(0), - m_clip_flags(0), - m_num_vertices(0), - m_vertex(0), - m_cmd(path_cmd_move_to) - { - } - - void clip_box(double x1, double y1, double x2, double y2) - { - m_clip_box.x1 = x1; - m_clip_box.y1 = y1; - m_clip_box.x2 = x2; - m_clip_box.y2 = y2; - m_clip_box.normalize(); - } - - - double x1() const { return m_clip_box.x1; } - double y1() const { return m_clip_box.y1; } - double x2() const { return m_clip_box.x2; } - double y2() const { return m_clip_box.y2; } - - static bool auto_close() { return true; } - static bool auto_unclose() { return false; } - - void reset(); - void move_to(double x, double y); - void line_to(double x, double y); - unsigned vertex(double* x, double* y); - - private: - unsigned clipping_flags(double x, double y); - - private: - rect_d m_clip_box; - double m_x1; - double m_y1; - unsigned m_clip_flags; - double m_x[4]; - double m_y[4]; - unsigned m_num_vertices; - unsigned m_vertex; - unsigned m_cmd; - }; - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_vpgen_clip_polyline.h corsix-th-0.62/agg/include/agg_vpgen_clip_polyline.h --- corsix-th-0.30/agg/include/agg_vpgen_clip_polyline.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vpgen_clip_polyline.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VPGEN_CLIP_POLYLINE_INCLUDED -#define AGG_VPGEN_CLIP_POLYLINE_INCLUDED - -#include "agg_basics.h" - -namespace agg -{ - - //======================================================vpgen_clip_polyline - // - // See Implementation agg_vpgen_clip_polyline.cpp - // - class vpgen_clip_polyline - { - public: - vpgen_clip_polyline() : - m_clip_box(0, 0, 1, 1), - m_x1(0), - m_y1(0), - m_num_vertices(0), - m_vertex(0), - m_move_to(false) - { - } - - void clip_box(double x1, double y1, double x2, double y2) - { - m_clip_box.x1 = x1; - m_clip_box.y1 = y1; - m_clip_box.x2 = x2; - m_clip_box.y2 = y2; - m_clip_box.normalize(); - } - - double x1() const { return m_clip_box.x1; } - double y1() const { return m_clip_box.y1; } - double x2() const { return m_clip_box.x2; } - double y2() const { return m_clip_box.y2; } - - static bool auto_close() { return false; } - static bool auto_unclose() { return true; } - - void reset(); - void move_to(double x, double y); - void line_to(double x, double y); - unsigned vertex(double* x, double* y); - - private: - rect_d m_clip_box; - double m_x1; - double m_y1; - double m_x[2]; - double m_y[2]; - unsigned m_cmd[2]; - unsigned m_num_vertices; - unsigned m_vertex; - bool m_move_to; - }; - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/agg_vpgen_segmentator.h corsix-th-0.62/agg/include/agg_vpgen_segmentator.h --- corsix-th-0.30/agg/include/agg_vpgen_segmentator.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/agg_vpgen_segmentator.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_VPGEN_SEGMENTATOR_INCLUDED -#define AGG_VPGEN_SEGMENTATOR_INCLUDED - -#include -#include "agg_basics.h" - -namespace agg -{ - - //=======================================================vpgen_segmentator - // - // See Implementation agg_vpgen_segmentator.cpp - // - class vpgen_segmentator - { - public: - vpgen_segmentator() : m_approximation_scale(1.0) {} - - void approximation_scale(double s) { m_approximation_scale = s; } - double approximation_scale() const { return m_approximation_scale; } - - static bool auto_close() { return false; } - static bool auto_unclose() { return false; } - - void reset() { m_cmd = path_cmd_stop; } - void move_to(double x, double y); - void line_to(double x, double y); - unsigned vertex(double* x, double* y); - - private: - double m_approximation_scale; - double m_x1; - double m_y1; - double m_dx; - double m_dy; - double m_dl; - double m_ddl; - unsigned m_cmd; - }; - - - -} - -#endif - diff -Nru corsix-th-0.30/agg/include/util/agg_color_conv.h corsix-th-0.62/agg/include/util/agg_color_conv.h --- corsix-th-0.30/agg/include/util/agg_color_conv.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/util/agg_color_conv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Conversion from one colorspace/pixel format to another -// -//---------------------------------------------------------------------------- - -#ifndef AGG_COLOR_CONV_INCLUDED -#define AGG_COLOR_CONV_INCLUDED - -#include -#include "agg_basics.h" -#include "agg_rendering_buffer.h" - - - - -namespace agg -{ - - //--------------------------------------------------------------color_conv - template - void color_conv(RenBuf* dst, const RenBuf* src, CopyRow copy_row_functor) - { - unsigned width = src->width(); - unsigned height = src->height(); - - if(dst->width() < width) width = dst->width(); - if(dst->height() < height) height = dst->height(); - - if(width) - { - unsigned y; - for(y = 0; y < height; y++) - { - copy_row_functor(dst->row_ptr(0, y, width), - src->row_ptr(y), - width); - } - } - } - - - //---------------------------------------------------------color_conv_row - template - void color_conv_row(int8u* dst, - const int8u* src, - unsigned width, - CopyRow copy_row_functor) - { - copy_row_functor(dst, src, width); - } - - - //---------------------------------------------------------color_conv_same - template class color_conv_same - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - memmove(dst, src, width*BPP); - } - }; - - -} - - - -#endif diff -Nru corsix-th-0.30/agg/include/util/agg_color_conv_rgb16.h corsix-th-0.62/agg/include/util/agg_color_conv_rgb16.h --- corsix-th-0.30/agg/include/util/agg_color_conv_rgb16.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/util/agg_color_conv_rgb16.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,285 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// This part of the library has been sponsored by -// Liberty Technology Systems, Inc., visit http://lib-sys.com -// -// Liberty Technology Systems, Inc. is the provider of -// PostScript and PDF technology for software developers. -// -//---------------------------------------------------------------------------- -// -// A set of functors used with color_conv(). See file agg_color_conv.h -// These functors can convert images with up to 8 bits per component. -// Use convertors in the following way: -// -// agg::color_conv(dst, src, agg::color_conv_XXXX_to_YYYY()); -//---------------------------------------------------------------------------- - -#ifndef AGG_COLOR_CONV_RGB16_INCLUDED -#define AGG_COLOR_CONV_RGB16_INCLUDED - -#include "agg_basics.h" -#include "agg_color_conv.h" - -namespace agg -{ - - //-------------------------------------------------color_conv_gray16_to_gray8 - class color_conv_gray16_to_gray8 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - int16u* s = (int16u*)src; - do - { - *dst++ = *s++ >> 8; - } - while(--width); - } - }; - - - //-----------------------------------------------------color_conv_rgb24_rgb48 - template class color_conv_rgb24_rgb48 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - int16u* d = (int16u*)dst; - do - { - *d++ = (src[I1] << 8) | src[I1]; - *d++ = (src[1] << 8) | src[1] ; - *d++ = (src[I3] << 8) | src[I3]; - src += 3; - } - while(--width); - } - }; - - typedef color_conv_rgb24_rgb48<0,2> color_conv_rgb24_to_rgb48; - typedef color_conv_rgb24_rgb48<0,2> color_conv_bgr24_to_bgr48; - typedef color_conv_rgb24_rgb48<2,0> color_conv_rgb24_to_bgr48; - typedef color_conv_rgb24_rgb48<2,0> color_conv_bgr24_to_rgb48; - - - //-----------------------------------------------------color_conv_rgb24_rgb48 - template class color_conv_rgb48_rgb24 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - const int16u* s = (const int16u*)src; - do - { - *dst++ = s[I1] >> 8; - *dst++ = s[1] >> 8; - *dst++ = s[I3] >> 8; - s += 3; - } - while(--width); - } - }; - - typedef color_conv_rgb48_rgb24<0,2> color_conv_rgb48_to_rgb24; - typedef color_conv_rgb48_rgb24<0,2> color_conv_bgr48_to_bgr24; - typedef color_conv_rgb48_rgb24<2,0> color_conv_rgb48_to_bgr24; - typedef color_conv_rgb48_rgb24<2,0> color_conv_bgr48_to_rgb24; - - - //----------------------------------------------color_conv_rgbAAA_rgb24 - template class color_conv_rgbAAA_rgb24 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - int32u rgb = *(int32u*)src; - dst[R] = int8u(rgb >> 22); - dst[1] = int8u(rgb >> 12); - dst[B] = int8u(rgb >> 2); - src += 4; - dst += 3; - } - while(--width); - } - }; - - typedef color_conv_rgbAAA_rgb24<0,2> color_conv_rgbAAA_to_rgb24; - typedef color_conv_rgbAAA_rgb24<2,0> color_conv_rgbAAA_to_bgr24; - typedef color_conv_rgbAAA_rgb24<2,0> color_conv_bgrAAA_to_rgb24; - typedef color_conv_rgbAAA_rgb24<0,2> color_conv_bgrAAA_to_bgr24; - - - //----------------------------------------------color_conv_rgbBBA_rgb24 - template class color_conv_rgbBBA_rgb24 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - int32u rgb = *(int32u*)src; - dst[R] = int8u(rgb >> 24); - dst[1] = int8u(rgb >> 13); - dst[B] = int8u(rgb >> 2); - src += 4; - dst += 3; - } - while(--width); - } - }; - - typedef color_conv_rgbBBA_rgb24<0,2> color_conv_rgbBBA_to_rgb24; - typedef color_conv_rgbBBA_rgb24<2,0> color_conv_rgbBBA_to_bgr24; - - - //----------------------------------------------color_conv_bgrABB_rgb24 - template class color_conv_bgrABB_rgb24 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - int32u bgr = *(int32u*)src; - dst[R] = int8u(bgr >> 3); - dst[1] = int8u(bgr >> 14); - dst[B] = int8u(bgr >> 24); - src += 4; - dst += 3; - } - while(--width); - } - }; - - typedef color_conv_bgrABB_rgb24<2,0> color_conv_bgrABB_to_rgb24; - typedef color_conv_bgrABB_rgb24<0,2> color_conv_bgrABB_to_bgr24; - - - //-------------------------------------------------color_conv_rgba64_rgba32 - template class color_conv_rgba64_rgba32 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *dst++ = int8u(((int16u*)src)[I1] >> 8); - *dst++ = int8u(((int16u*)src)[I2] >> 8); - *dst++ = int8u(((int16u*)src)[I3] >> 8); - *dst++ = int8u(((int16u*)src)[I4] >> 8); - src += 8; - } - while(--width); - } - }; - - //------------------------------------------------------------------------ - typedef color_conv_rgba64_rgba32<0,1,2,3> color_conv_rgba64_to_rgba32; //----color_conv_rgba64_to_rgba32 - typedef color_conv_rgba64_rgba32<0,1,2,3> color_conv_argb64_to_argb32; //----color_conv_argb64_to_argb32 - typedef color_conv_rgba64_rgba32<0,1,2,3> color_conv_bgra64_to_bgra32; //----color_conv_bgra64_to_bgra32 - typedef color_conv_rgba64_rgba32<0,1,2,3> color_conv_abgr64_to_abgr32; //----color_conv_abgr64_to_abgr32 - typedef color_conv_rgba64_rgba32<0,3,2,1> color_conv_argb64_to_abgr32; //----color_conv_argb64_to_abgr32 - typedef color_conv_rgba64_rgba32<3,2,1,0> color_conv_argb64_to_bgra32; //----color_conv_argb64_to_bgra32 - typedef color_conv_rgba64_rgba32<1,2,3,0> color_conv_argb64_to_rgba32; //----color_conv_argb64_to_rgba32 - typedef color_conv_rgba64_rgba32<3,0,1,2> color_conv_bgra64_to_abgr32; //----color_conv_bgra64_to_abgr32 - typedef color_conv_rgba64_rgba32<3,2,1,0> color_conv_bgra64_to_argb32; //----color_conv_bgra64_to_argb32 - typedef color_conv_rgba64_rgba32<2,1,0,3> color_conv_bgra64_to_rgba32; //----color_conv_bgra64_to_rgba32 - typedef color_conv_rgba64_rgba32<3,2,1,0> color_conv_rgba64_to_abgr32; //----color_conv_rgba64_to_abgr32 - typedef color_conv_rgba64_rgba32<3,0,1,2> color_conv_rgba64_to_argb32; //----color_conv_rgba64_to_argb32 - typedef color_conv_rgba64_rgba32<2,1,0,3> color_conv_rgba64_to_bgra32; //----color_conv_rgba64_to_bgra32 - typedef color_conv_rgba64_rgba32<0,3,2,1> color_conv_abgr64_to_argb32; //----color_conv_abgr64_to_argb32 - typedef color_conv_rgba64_rgba32<1,2,3,0> color_conv_abgr64_to_bgra32; //----color_conv_abgr64_to_bgra32 - typedef color_conv_rgba64_rgba32<3,2,1,0> color_conv_abgr64_to_rgba32; //----color_conv_abgr64_to_rgba32 - - - - //--------------------------------------------color_conv_rgb24_rgba64 - template class color_conv_rgb24_rgba64 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - int16u* d = (int16u*)dst; - do - { - d[I1] = (src[0] << 8) | src[0]; - d[I2] = (src[1] << 8) | src[1]; - d[I3] = (src[2] << 8) | src[2]; - d[A] = 65535; - d += 4; - src += 3; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgb24_rgba64<1,2,3,0> color_conv_rgb24_to_argb64; //----color_conv_rgb24_to_argb64 - typedef color_conv_rgb24_rgba64<3,2,1,0> color_conv_rgb24_to_abgr64; //----color_conv_rgb24_to_abgr64 - typedef color_conv_rgb24_rgba64<2,1,0,3> color_conv_rgb24_to_bgra64; //----color_conv_rgb24_to_bgra64 - typedef color_conv_rgb24_rgba64<0,1,2,3> color_conv_rgb24_to_rgba64; //----color_conv_rgb24_to_rgba64 - typedef color_conv_rgb24_rgba64<3,2,1,0> color_conv_bgr24_to_argb64; //----color_conv_bgr24_to_argb64 - typedef color_conv_rgb24_rgba64<1,2,3,0> color_conv_bgr24_to_abgr64; //----color_conv_bgr24_to_abgr64 - typedef color_conv_rgb24_rgba64<0,1,2,3> color_conv_bgr24_to_bgra64; //----color_conv_bgr24_to_bgra64 - typedef color_conv_rgb24_rgba64<2,1,0,3> color_conv_bgr24_to_rgba64; //----color_conv_bgr24_to_rgba64 - - - template class color_conv_rgb24_gray16 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - int16u* d = (int16u*)dst; - do - { - *d++ = src[R]*77 + src[1]*150 + src[B]*29; - src += 3; - } - while(--width); - } - }; - - typedef color_conv_rgb24_gray16<0,2> color_conv_rgb24_to_gray16; - typedef color_conv_rgb24_gray16<2,0> color_conv_bgr24_to_gray16; - - -} - - -#endif diff -Nru corsix-th-0.30/agg/include/util/agg_color_conv_rgb8.h corsix-th-0.62/agg/include/util/agg_color_conv_rgb8.h --- corsix-th-0.30/agg/include/util/agg_color_conv_rgb8.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/include/util/agg_color_conv_rgb8.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,469 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// A set of functors used with color_conv(). See file agg_color_conv.h -// These functors can convert images with up to 8 bits per component. -// Use convertors in the following way: -// -// agg::color_conv(dst, src, agg::color_conv_XXXX_to_YYYY()); -// whare XXXX and YYYY can be any of: -// rgb24 -// bgr24 -// rgba32 -// abgr32 -// argb32 -// bgra32 -// rgb555 -// rgb565 -//---------------------------------------------------------------------------- - -#ifndef AGG_COLOR_CONV_RGB8_INCLUDED -#define AGG_COLOR_CONV_RGB8_INCLUDED - -#include "agg_basics.h" -#include "agg_color_conv.h" - -namespace agg -{ - - //-----------------------------------------------------color_conv_rgb24 - class color_conv_rgb24 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *dst++ = src[2]; - *dst++ = src[1]; - *dst++ = src[0]; - src += 3; - } - while(--width); - } - }; - - typedef color_conv_rgb24 color_conv_rgb24_to_bgr24; - typedef color_conv_rgb24 color_conv_bgr24_to_rgb24; - - typedef color_conv_same<3> color_conv_bgr24_to_bgr24; - typedef color_conv_same<3> color_conv_rgb24_to_rgb24; - - - - //------------------------------------------------------color_conv_rgba32 - template class color_conv_rgba32 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *dst++ = src[I1]; - *dst++ = src[I2]; - *dst++ = src[I3]; - *dst++ = src[I4]; - src += 4; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgba32<0,3,2,1> color_conv_argb32_to_abgr32; //----color_conv_argb32_to_abgr32 - typedef color_conv_rgba32<3,2,1,0> color_conv_argb32_to_bgra32; //----color_conv_argb32_to_bgra32 - typedef color_conv_rgba32<1,2,3,0> color_conv_argb32_to_rgba32; //----color_conv_argb32_to_rgba32 - typedef color_conv_rgba32<3,0,1,2> color_conv_bgra32_to_abgr32; //----color_conv_bgra32_to_abgr32 - typedef color_conv_rgba32<3,2,1,0> color_conv_bgra32_to_argb32; //----color_conv_bgra32_to_argb32 - typedef color_conv_rgba32<2,1,0,3> color_conv_bgra32_to_rgba32; //----color_conv_bgra32_to_rgba32 - typedef color_conv_rgba32<3,2,1,0> color_conv_rgba32_to_abgr32; //----color_conv_rgba32_to_abgr32 - typedef color_conv_rgba32<3,0,1,2> color_conv_rgba32_to_argb32; //----color_conv_rgba32_to_argb32 - typedef color_conv_rgba32<2,1,0,3> color_conv_rgba32_to_bgra32; //----color_conv_rgba32_to_bgra32 - typedef color_conv_rgba32<0,3,2,1> color_conv_abgr32_to_argb32; //----color_conv_abgr32_to_argb32 - typedef color_conv_rgba32<1,2,3,0> color_conv_abgr32_to_bgra32; //----color_conv_abgr32_to_bgra32 - typedef color_conv_rgba32<3,2,1,0> color_conv_abgr32_to_rgba32; //----color_conv_abgr32_to_rgba32 - - //------------------------------------------------------------------------ - typedef color_conv_same<4> color_conv_rgba32_to_rgba32; //----color_conv_rgba32_to_rgba32 - typedef color_conv_same<4> color_conv_argb32_to_argb32; //----color_conv_argb32_to_argb32 - typedef color_conv_same<4> color_conv_bgra32_to_bgra32; //----color_conv_bgra32_to_bgra32 - typedef color_conv_same<4> color_conv_abgr32_to_abgr32; //----color_conv_abgr32_to_abgr32 - - - //--------------------------------------------color_conv_rgb24_rgba32 - template class color_conv_rgb24_rgba32 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - dst[I1] = *src++; - dst[I2] = *src++; - dst[I3] = *src++; - dst[A] = 255; - dst += 4; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgb24_rgba32<1,2,3,0> color_conv_rgb24_to_argb32; //----color_conv_rgb24_to_argb32 - typedef color_conv_rgb24_rgba32<3,2,1,0> color_conv_rgb24_to_abgr32; //----color_conv_rgb24_to_abgr32 - typedef color_conv_rgb24_rgba32<2,1,0,3> color_conv_rgb24_to_bgra32; //----color_conv_rgb24_to_bgra32 - typedef color_conv_rgb24_rgba32<0,1,2,3> color_conv_rgb24_to_rgba32; //----color_conv_rgb24_to_rgba32 - typedef color_conv_rgb24_rgba32<3,2,1,0> color_conv_bgr24_to_argb32; //----color_conv_bgr24_to_argb32 - typedef color_conv_rgb24_rgba32<1,2,3,0> color_conv_bgr24_to_abgr32; //----color_conv_bgr24_to_abgr32 - typedef color_conv_rgb24_rgba32<0,1,2,3> color_conv_bgr24_to_bgra32; //----color_conv_bgr24_to_bgra32 - typedef color_conv_rgb24_rgba32<2,1,0,3> color_conv_bgr24_to_rgba32; //----color_conv_bgr24_to_rgba32 - - - - //-------------------------------------------------color_conv_rgba32_rgb24 - template class color_conv_rgba32_rgb24 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *dst++ = src[I1]; - *dst++ = src[I2]; - *dst++ = src[I3]; - src += 4; - } - while(--width); - } - }; - - - - //------------------------------------------------------------------------ - typedef color_conv_rgba32_rgb24<1,2,3> color_conv_argb32_to_rgb24; //----color_conv_argb32_to_rgb24 - typedef color_conv_rgba32_rgb24<3,2,1> color_conv_abgr32_to_rgb24; //----color_conv_abgr32_to_rgb24 - typedef color_conv_rgba32_rgb24<2,1,0> color_conv_bgra32_to_rgb24; //----color_conv_bgra32_to_rgb24 - typedef color_conv_rgba32_rgb24<0,1,2> color_conv_rgba32_to_rgb24; //----color_conv_rgba32_to_rgb24 - typedef color_conv_rgba32_rgb24<3,2,1> color_conv_argb32_to_bgr24; //----color_conv_argb32_to_bgr24 - typedef color_conv_rgba32_rgb24<1,2,3> color_conv_abgr32_to_bgr24; //----color_conv_abgr32_to_bgr24 - typedef color_conv_rgba32_rgb24<0,1,2> color_conv_bgra32_to_bgr24; //----color_conv_bgra32_to_bgr24 - typedef color_conv_rgba32_rgb24<2,1,0> color_conv_rgba32_to_bgr24; //----color_conv_rgba32_to_bgr24 - - - //------------------------------------------------color_conv_rgb555_rgb24 - template class color_conv_rgb555_rgb24 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - unsigned rgb = *(int16u*)src; - dst[R] = (int8u)((rgb >> 7) & 0xF8); - dst[1] = (int8u)((rgb >> 2) & 0xF8); - dst[B] = (int8u)((rgb << 3) & 0xF8); - src += 2; - dst += 3; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgb555_rgb24<2,0> color_conv_rgb555_to_bgr24; //----color_conv_rgb555_to_bgr24 - typedef color_conv_rgb555_rgb24<0,2> color_conv_rgb555_to_rgb24; //----color_conv_rgb555_to_rgb24 - - - //-------------------------------------------------color_conv_rgb24_rgb555 - template class color_conv_rgb24_rgb555 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *(int16u*)dst = (int16u)(((unsigned(src[R]) << 7) & 0x7C00) | - ((unsigned(src[1]) << 2) & 0x3E0) | - ((unsigned(src[B]) >> 3))); - src += 3; - dst += 2; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgb24_rgb555<2,0> color_conv_bgr24_to_rgb555; //----color_conv_bgr24_to_rgb555 - typedef color_conv_rgb24_rgb555<0,2> color_conv_rgb24_to_rgb555; //----color_conv_rgb24_to_rgb555 - - - //-------------------------------------------------color_conv_rgb565_rgb24 - template class color_conv_rgb565_rgb24 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - unsigned rgb = *(int16u*)src; - dst[R] = (rgb >> 8) & 0xF8; - dst[1] = (rgb >> 3) & 0xFC; - dst[B] = (rgb << 3) & 0xF8; - src += 2; - dst += 3; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgb565_rgb24<2,0> color_conv_rgb565_to_bgr24; //----color_conv_rgb565_to_bgr24 - typedef color_conv_rgb565_rgb24<0,2> color_conv_rgb565_to_rgb24; //----color_conv_rgb565_to_rgb24 - - - //-------------------------------------------------color_conv_rgb24_rgb565 - template class color_conv_rgb24_rgb565 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *(int16u*)dst = (int16u)(((unsigned(src[R]) << 8) & 0xF800) | - ((unsigned(src[1]) << 3) & 0x7E0) | - ((unsigned(src[B]) >> 3))); - src += 3; - dst += 2; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgb24_rgb565<2,0> color_conv_bgr24_to_rgb565; //----color_conv_bgr24_to_rgb565 - typedef color_conv_rgb24_rgb565<0,2> color_conv_rgb24_to_rgb565; //----color_conv_rgb24_to_rgb565 - - - - //-------------------------------------------------color_conv_rgb555_rgba32 - template class color_conv_rgb555_rgba32 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - int rgb = *(int16*)src; - dst[R] = (int8u)((rgb >> 7) & 0xF8); - dst[G] = (int8u)((rgb >> 2) & 0xF8); - dst[B] = (int8u)((rgb << 3) & 0xF8); - dst[A] = (int8u)(rgb >> 15); - src += 2; - dst += 4; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgb555_rgba32<1,2,3,0> color_conv_rgb555_to_argb32; //----color_conv_rgb555_to_argb32 - typedef color_conv_rgb555_rgba32<3,2,1,0> color_conv_rgb555_to_abgr32; //----color_conv_rgb555_to_abgr32 - typedef color_conv_rgb555_rgba32<2,1,0,3> color_conv_rgb555_to_bgra32; //----color_conv_rgb555_to_bgra32 - typedef color_conv_rgb555_rgba32<0,1,2,3> color_conv_rgb555_to_rgba32; //----color_conv_rgb555_to_rgba32 - - - //------------------------------------------------color_conv_rgba32_rgb555 - template class color_conv_rgba32_rgb555 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *(int16u*)dst = (int16u)(((unsigned(src[R]) << 7) & 0x7C00) | - ((unsigned(src[G]) << 2) & 0x3E0) | - ((unsigned(src[B]) >> 3)) | - ((unsigned(src[A]) << 8) & 0x8000)); - src += 4; - dst += 2; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgba32_rgb555<1,2,3,0> color_conv_argb32_to_rgb555; //----color_conv_argb32_to_rgb555 - typedef color_conv_rgba32_rgb555<3,2,1,0> color_conv_abgr32_to_rgb555; //----color_conv_abgr32_to_rgb555 - typedef color_conv_rgba32_rgb555<2,1,0,3> color_conv_bgra32_to_rgb555; //----color_conv_bgra32_to_rgb555 - typedef color_conv_rgba32_rgb555<0,1,2,3> color_conv_rgba32_to_rgb555; //----color_conv_rgba32_to_rgb555 - - - - //------------------------------------------------color_conv_rgb565_rgba32 - template class color_conv_rgb565_rgba32 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - int rgb = *(int16*)src; - dst[R] = (rgb >> 8) & 0xF8; - dst[G] = (rgb >> 3) & 0xFC; - dst[B] = (rgb << 3) & 0xF8; - dst[A] = 255; - src += 2; - dst += 4; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgb565_rgba32<1,2,3,0> color_conv_rgb565_to_argb32; //----color_conv_rgb565_to_argb32 - typedef color_conv_rgb565_rgba32<3,2,1,0> color_conv_rgb565_to_abgr32; //----color_conv_rgb565_to_abgr32 - typedef color_conv_rgb565_rgba32<2,1,0,3> color_conv_rgb565_to_bgra32; //----color_conv_rgb565_to_bgra32 - typedef color_conv_rgb565_rgba32<0,1,2,3> color_conv_rgb565_to_rgba32; //----color_conv_rgb565_to_rgba32 - - - //------------------------------------------------color_conv_rgba32_rgb565 - template class color_conv_rgba32_rgb565 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *(int16u*)dst = (int16u)(((unsigned(src[R]) << 8) & 0xF800) | - ((unsigned(src[G]) << 3) & 0x7E0) | - ((unsigned(src[B]) >> 3))); - src += 4; - dst += 2; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_rgba32_rgb565<1,2,3> color_conv_argb32_to_rgb565; //----color_conv_argb32_to_rgb565 - typedef color_conv_rgba32_rgb565<3,2,1> color_conv_abgr32_to_rgb565; //----color_conv_abgr32_to_rgb565 - typedef color_conv_rgba32_rgb565<2,1,0> color_conv_bgra32_to_rgb565; //----color_conv_bgra32_to_rgb565 - typedef color_conv_rgba32_rgb565<0,1,2> color_conv_rgba32_to_rgb565; //----color_conv_rgba32_to_rgb565 - - - //---------------------------------------------color_conv_rgb555_to_rgb565 - class color_conv_rgb555_to_rgb565 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - unsigned rgb = *(int16u*)src; - *(int16u*)dst = (int16u)(((rgb << 1) & 0xFFC0) | (rgb & 0x1F)); - src += 2; - dst += 2; - } - while(--width); - } - }; - - - //----------------------------------------------color_conv_rgb565_to_rgb555 - class color_conv_rgb565_to_rgb555 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - unsigned rgb = *(int16u*)src; - *(int16u*)dst = (int16u)(((rgb >> 1) & 0x7FE0) | (rgb & 0x1F)); - src += 2; - dst += 2; - } - while(--width); - } - }; - - - //------------------------------------------------------------------------ - typedef color_conv_same<2> color_conv_rgb555_to_rgb555; //----color_conv_rgb555_to_rgb555 - typedef color_conv_same<2> color_conv_rgb565_to_rgb565; //----color_conv_rgb565_to_rgb565 - - - template class color_conv_rgb24_gray8 - { - public: - void operator () (int8u* dst, - const int8u* src, - unsigned width) const - { - do - { - *dst++ = (src[R]*77 + src[1]*150 + src[B]*29) >> 8; - src += 3; - } - while(--width); - } - }; - - typedef color_conv_rgb24_gray8<0,2> color_conv_rgb24_to_gray8; //----color_conv_rgb24_to_gray8 - typedef color_conv_rgb24_gray8<2,0> color_conv_bgr24_to_gray8; //----color_conv_bgr24_to_gray8 - - -} - - - -#endif diff -Nru corsix-th-0.30/agg/news corsix-th-0.62/agg/news --- corsix-th-0.30/agg/news 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/news 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -Visit http://antigrain.com/news \ No newline at end of file diff -Nru corsix-th-0.30/agg/readme corsix-th-0.62/agg/readme --- corsix-th-0.30/agg/readme 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/readme 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -The Anti-Grain Geometry Project -A high quality rendering engine for C++ -http://antigrain.com - -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) - -Permission to copy, use, modify, sell and distribute this software -is granted provided this copyright notice appears in all copies. -This software is provided "as is" without express or implied -warranty, and with no claim as to its suitability for any purpose. - ---------------------------------- - -Use automake to build the library. - -If automake is not available you still can use the old make. -There is a very simple Makefile that can be used. Note that -if you use automake it will overwrite Makefile. - ---------------------------------- - -If building on AmigaOS 4.0 or higher type the following for -instructions on what targets are available. - make -f Makefile.AmigaOS - -To just build and install AGG into the standard AmigaOS SDK -ready for use type: - make -f Makefile.AmigaOS install - -If you just want to build one demo (e.g. lion) use: - make -f Makefile.AmigaOS bin/lion - -If you have any questions about the AmigaOS port please -contact Steven Solie (ssolie@telus.net) for help. - ---------------------------------- - -To build all examples using SDL (Mac or Linux) just type: - -cd /examples/sdl -make - -Individual examples can be built with - -make aa_test - -In the same way the native Carbon examples can be built with - -cd /examples/macosx_carbon -make - -In both cases the static library will be built (if it was not already) -from the existing global Makefile in /src/. - -The Makefiles for both SDL and Carbon will also attempt to download the -required .bmp files if they are not found in the system for a given -example. If the files could not be fetched (wget) the user will receive -a message explaining where to download the samples from (sphere.bmp, -etc.) Since all programs reside in the same directory there is no need -to duplicate the .bmp files for each program that needs to use them. - ---------------------------------- diff -Nru corsix-th-0.30/agg/src/agg_arc.cpp corsix-th-0.62/agg/src/agg_arc.cpp --- corsix-th-0.30/agg/src/agg_arc.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_arc.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Arc vertex generator -// -//---------------------------------------------------------------------------- - -#include -#include "agg_arc.h" - - -namespace agg -{ - //------------------------------------------------------------------------ - arc::arc(double x, double y, - double rx, double ry, - double a1, double a2, - bool ccw) : - m_x(x), m_y(y), m_rx(rx), m_ry(ry), m_scale(1.0) - { - normalize(a1, a2, ccw); - } - - //------------------------------------------------------------------------ - void arc::init(double x, double y, - double rx, double ry, - double a1, double a2, - bool ccw) - { - m_x = x; m_y = y; - m_rx = rx; m_ry = ry; - normalize(a1, a2, ccw); - } - - //------------------------------------------------------------------------ - void arc::approximation_scale(double s) - { - m_scale = s; - if(m_initialized) - { - normalize(m_start, m_end, m_ccw); - } - } - - //------------------------------------------------------------------------ - void arc::rewind(unsigned) - { - m_path_cmd = path_cmd_move_to; - m_angle = m_start; - } - - //------------------------------------------------------------------------ - unsigned arc::vertex(double* x, double* y) - { - if(is_stop(m_path_cmd)) return path_cmd_stop; - if((m_angle < m_end - m_da/4) != m_ccw) - { - *x = m_x + cos(m_end) * m_rx; - *y = m_y + sin(m_end) * m_ry; - m_path_cmd = path_cmd_stop; - return path_cmd_line_to; - } - - *x = m_x + cos(m_angle) * m_rx; - *y = m_y + sin(m_angle) * m_ry; - - m_angle += m_da; - - unsigned pf = m_path_cmd; - m_path_cmd = path_cmd_line_to; - return pf; - } - - //------------------------------------------------------------------------ - void arc::normalize(double a1, double a2, bool ccw) - { - double ra = (fabs(m_rx) + fabs(m_ry)) / 2; - m_da = acos(ra / (ra + 0.125 / m_scale)) * 2; - if(ccw) - { - while(a2 < a1) a2 += pi * 2.0; - } - else - { - while(a1 < a2) a1 += pi * 2.0; - m_da = -m_da; - } - m_ccw = ccw; - m_start = a1; - m_end = a2; - m_initialized = true; - } - -} diff -Nru corsix-th-0.30/agg/src/agg_arrowhead.cpp corsix-th-0.62/agg/src/agg_arrowhead.cpp --- corsix-th-0.30/agg/src/agg_arrowhead.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_arrowhead.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Simple arrowhead/arrowtail generator -// -//---------------------------------------------------------------------------- - -#include "agg_arrowhead.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - arrowhead::arrowhead() : - m_head_d1(1.0), - m_head_d2(1.0), - m_head_d3(1.0), - m_head_d4(0.0), - m_tail_d1(1.0), - m_tail_d2(1.0), - m_tail_d3(1.0), - m_tail_d4(0.0), - m_head_flag(false), - m_tail_flag(false), - m_curr_id(0), - m_curr_coord(0) - { - } - - - - //------------------------------------------------------------------------ - void arrowhead::rewind(unsigned path_id) - { - m_curr_id = path_id; - m_curr_coord = 0; - if(path_id == 0) - { - if(!m_tail_flag) - { - m_cmd[0] = path_cmd_stop; - return; - } - m_coord[0] = m_tail_d1; m_coord[1] = 0.0; - m_coord[2] = m_tail_d1 - m_tail_d4; m_coord[3] = m_tail_d3; - m_coord[4] = -m_tail_d2 - m_tail_d4; m_coord[5] = m_tail_d3; - m_coord[6] = -m_tail_d2; m_coord[7] = 0.0; - m_coord[8] = -m_tail_d2 - m_tail_d4; m_coord[9] = -m_tail_d3; - m_coord[10] = m_tail_d1 - m_tail_d4; m_coord[11] = -m_tail_d3; - - m_cmd[0] = path_cmd_move_to; - m_cmd[1] = path_cmd_line_to; - m_cmd[2] = path_cmd_line_to; - m_cmd[3] = path_cmd_line_to; - m_cmd[4] = path_cmd_line_to; - m_cmd[5] = path_cmd_line_to; - m_cmd[7] = path_cmd_end_poly | path_flags_close | path_flags_ccw; - m_cmd[6] = path_cmd_stop; - return; - } - - if(path_id == 1) - { - if(!m_head_flag) - { - m_cmd[0] = path_cmd_stop; - return; - } - m_coord[0] = -m_head_d1; m_coord[1] = 0.0; - m_coord[2] = m_head_d2 + m_head_d4; m_coord[3] = -m_head_d3; - m_coord[4] = m_head_d2; m_coord[5] = 0.0; - m_coord[6] = m_head_d2 + m_head_d4; m_coord[7] = m_head_d3; - - m_cmd[0] = path_cmd_move_to; - m_cmd[1] = path_cmd_line_to; - m_cmd[2] = path_cmd_line_to; - m_cmd[3] = path_cmd_line_to; - m_cmd[4] = path_cmd_end_poly | path_flags_close | path_flags_ccw; - m_cmd[5] = path_cmd_stop; - return; - } - } - - - //------------------------------------------------------------------------ - unsigned arrowhead::vertex(double* x, double* y) - { - if(m_curr_id < 2) - { - unsigned curr_idx = m_curr_coord * 2; - *x = m_coord[curr_idx]; - *y = m_coord[curr_idx + 1]; - return m_cmd[m_curr_coord++]; - } - return path_cmd_stop; - } - -} diff -Nru corsix-th-0.30/agg/src/agg_bezier_arc.cpp corsix-th-0.62/agg/src/agg_bezier_arc.cpp --- corsix-th-0.30/agg/src/agg_bezier_arc.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_bezier_arc.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,258 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e., -// 4, 7, 10, or 13 vertices. -// -//---------------------------------------------------------------------------- - - -#include -#include "agg_bezier_arc.h" - - -namespace agg -{ - - // This epsilon is used to prevent us from adding degenerate curves - // (converging to a single point). - // The value isn't very critical. Function arc_to_bezier() has a limit - // of the sweep_angle. If fabs(sweep_angle) exceeds pi/2 the curve - // becomes inaccurate. But slight exceeding is quite appropriate. - //-------------------------------------------------bezier_arc_angle_epsilon - const double bezier_arc_angle_epsilon = 0.01; - - //------------------------------------------------------------arc_to_bezier - void arc_to_bezier(double cx, double cy, double rx, double ry, - double start_angle, double sweep_angle, - double* curve) - { - double x0 = cos(sweep_angle / 2.0); - double y0 = sin(sweep_angle / 2.0); - double tx = (1.0 - x0) * 4.0 / 3.0; - double ty = y0 - tx * x0 / y0; - double px[4]; - double py[4]; - px[0] = x0; - py[0] = -y0; - px[1] = x0 + tx; - py[1] = -ty; - px[2] = x0 + tx; - py[2] = ty; - px[3] = x0; - py[3] = y0; - - double sn = sin(start_angle + sweep_angle / 2.0); - double cs = cos(start_angle + sweep_angle / 2.0); - - unsigned i; - for(i = 0; i < 4; i++) - { - curve[i * 2] = cx + rx * (px[i] * cs - py[i] * sn); - curve[i * 2 + 1] = cy + ry * (px[i] * sn + py[i] * cs); - } - } - - - - //------------------------------------------------------------------------ - void bezier_arc::init(double x, double y, - double rx, double ry, - double start_angle, - double sweep_angle) - { - start_angle = fmod(start_angle, 2.0 * pi); - if(sweep_angle >= 2.0 * pi) sweep_angle = 2.0 * pi; - if(sweep_angle <= -2.0 * pi) sweep_angle = -2.0 * pi; - - if(fabs(sweep_angle) < 1e-10) - { - m_num_vertices = 4; - m_cmd = path_cmd_line_to; - m_vertices[0] = x + rx * cos(start_angle); - m_vertices[1] = y + ry * sin(start_angle); - m_vertices[2] = x + rx * cos(start_angle + sweep_angle); - m_vertices[3] = y + ry * sin(start_angle + sweep_angle); - return; - } - - double total_sweep = 0.0; - double local_sweep = 0.0; - double prev_sweep; - m_num_vertices = 2; - m_cmd = path_cmd_curve4; - bool done = false; - do - { - if(sweep_angle < 0.0) - { - prev_sweep = total_sweep; - local_sweep = -pi * 0.5; - total_sweep -= pi * 0.5; - if(total_sweep <= sweep_angle + bezier_arc_angle_epsilon) - { - local_sweep = sweep_angle - prev_sweep; - done = true; - } - } - else - { - prev_sweep = total_sweep; - local_sweep = pi * 0.5; - total_sweep += pi * 0.5; - if(total_sweep >= sweep_angle - bezier_arc_angle_epsilon) - { - local_sweep = sweep_angle - prev_sweep; - done = true; - } - } - - arc_to_bezier(x, y, rx, ry, - start_angle, - local_sweep, - m_vertices + m_num_vertices - 2); - - m_num_vertices += 6; - start_angle += local_sweep; - } - while(!done && m_num_vertices < 26); - } - - - - - //-------------------------------------------------------------------- - void bezier_arc_svg::init(double x0, double y0, - double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double x2, double y2) - { - m_radii_ok = true; - - if(rx < 0.0) rx = -rx; - if(ry < 0.0) ry = -rx; - - // Calculate the middle point between - // the current and the final points - //------------------------ - double dx2 = (x0 - x2) / 2.0; - double dy2 = (y0 - y2) / 2.0; - - double cos_a = cos(angle); - double sin_a = sin(angle); - - // Calculate (x1, y1) - //------------------------ - double x1 = cos_a * dx2 + sin_a * dy2; - double y1 = -sin_a * dx2 + cos_a * dy2; - - // Ensure radii are large enough - //------------------------ - double prx = rx * rx; - double pry = ry * ry; - double px1 = x1 * x1; - double py1 = y1 * y1; - - // Check that radii are large enough - //------------------------ - double radii_check = px1/prx + py1/pry; - if(radii_check > 1.0) - { - rx = sqrt(radii_check) * rx; - ry = sqrt(radii_check) * ry; - prx = rx * rx; - pry = ry * ry; - if(radii_check > 10.0) m_radii_ok = false; - } - - // Calculate (cx1, cy1) - //------------------------ - double sign = (large_arc_flag == sweep_flag) ? -1.0 : 1.0; - double sq = (prx*pry - prx*py1 - pry*px1) / (prx*py1 + pry*px1); - double coef = sign * sqrt((sq < 0) ? 0 : sq); - double cx1 = coef * ((rx * y1) / ry); - double cy1 = coef * -((ry * x1) / rx); - - // - // Calculate (cx, cy) from (cx1, cy1) - //------------------------ - double sx2 = (x0 + x2) / 2.0; - double sy2 = (y0 + y2) / 2.0; - double cx = sx2 + (cos_a * cx1 - sin_a * cy1); - double cy = sy2 + (sin_a * cx1 + cos_a * cy1); - - // Calculate the start_angle (angle1) and the sweep_angle (dangle) - //------------------------ - double ux = (x1 - cx1) / rx; - double uy = (y1 - cy1) / ry; - double vx = (-x1 - cx1) / rx; - double vy = (-y1 - cy1) / ry; - double p, n; - - // Calculate the angle start - //------------------------ - n = sqrt(ux*ux + uy*uy); - p = ux; // (1 * ux) + (0 * uy) - sign = (uy < 0) ? -1.0 : 1.0; - double v = p / n; - if(v < -1.0) v = -1.0; - if(v > 1.0) v = 1.0; - double start_angle = sign * acos(v); - - // Calculate the sweep angle - //------------------------ - n = sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)); - p = ux * vx + uy * vy; - sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0; - v = p / n; - if(v < -1.0) v = -1.0; - if(v > 1.0) v = 1.0; - double sweep_angle = sign * acos(v); - if(!sweep_flag && sweep_angle > 0) - { - sweep_angle -= pi * 2.0; - } - else - if (sweep_flag && sweep_angle < 0) - { - sweep_angle += pi * 2.0; - } - - // We can now build and transform the resulting arc - //------------------------ - m_arc.init(0.0, 0.0, rx, ry, start_angle, sweep_angle); - trans_affine mtx = trans_affine_rotation(angle); - mtx *= trans_affine_translation(cx, cy); - - for(unsigned i = 2; i < m_arc.num_vertices()-2; i += 2) - { - mtx.transform(m_arc.vertices() + i, m_arc.vertices() + i + 1); - } - - // We must make sure that the starting and ending points - // exactly coincide with the initial (x0,y0) and (x2,y2) - m_arc.vertices()[0] = x0; - m_arc.vertices()[1] = y0; - if(m_arc.num_vertices() > 2) - { - m_arc.vertices()[m_arc.num_vertices() - 2] = x2; - m_arc.vertices()[m_arc.num_vertices() - 1] = y2; - } - } - - -} diff -Nru corsix-th-0.30/agg/src/agg_bspline.cpp corsix-th-0.62/agg/src/agg_bspline.cpp --- corsix-th-0.30/agg/src/agg_bspline.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_bspline.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,284 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class bspline -// -//---------------------------------------------------------------------------- - -#include "agg_bspline.h" - -namespace agg -{ - //------------------------------------------------------------------------ - bspline::bspline() : - m_max(0), - m_num(0), - m_x(0), - m_y(0), - m_last_idx(-1) - { - } - - //------------------------------------------------------------------------ - bspline::bspline(int num) : - m_max(0), - m_num(0), - m_x(0), - m_y(0), - m_last_idx(-1) - { - init(num); - } - - //------------------------------------------------------------------------ - bspline::bspline(int num, const double* x, const double* y) : - m_max(0), - m_num(0), - m_x(0), - m_y(0), - m_last_idx(-1) - { - init(num, x, y); - } - - - //------------------------------------------------------------------------ - void bspline::init(int max) - { - if(max > 2 && max > m_max) - { - m_am.resize(max * 3); - m_max = max; - m_x = &m_am[m_max]; - m_y = &m_am[m_max * 2]; - } - m_num = 0; - m_last_idx = -1; - } - - - //------------------------------------------------------------------------ - void bspline::add_point(double x, double y) - { - if(m_num < m_max) - { - m_x[m_num] = x; - m_y[m_num] = y; - ++m_num; - } - } - - - //------------------------------------------------------------------------ - void bspline::prepare() - { - if(m_num > 2) - { - int i, k, n1; - double* temp; - double* r; - double* s; - double h, p, d, f, e; - - for(k = 0; k < m_num; k++) - { - m_am[k] = 0.0; - } - - n1 = 3 * m_num; - - pod_array al(n1); - temp = &al[0]; - - for(k = 0; k < n1; k++) - { - temp[k] = 0.0; - } - - r = temp + m_num; - s = temp + m_num * 2; - - n1 = m_num - 1; - d = m_x[1] - m_x[0]; - e = (m_y[1] - m_y[0]) / d; - - for(k = 1; k < n1; k++) - { - h = d; - d = m_x[k + 1] - m_x[k]; - f = e; - e = (m_y[k + 1] - m_y[k]) / d; - al[k] = d / (d + h); - r[k] = 1.0 - al[k]; - s[k] = 6.0 * (e - f) / (h + d); - } - - for(k = 1; k < n1; k++) - { - p = 1.0 / (r[k] * al[k - 1] + 2.0); - al[k] *= -p; - s[k] = (s[k] - r[k] * s[k - 1]) * p; - } - - m_am[n1] = 0.0; - al[n1 - 1] = s[n1 - 1]; - m_am[n1 - 1] = al[n1 - 1]; - - for(k = n1 - 2, i = 0; i < m_num - 2; i++, k--) - { - al[k] = al[k] * al[k + 1] + s[k]; - m_am[k] = al[k]; - } - } - m_last_idx = -1; - } - - - - //------------------------------------------------------------------------ - void bspline::init(int num, const double* x, const double* y) - { - if(num > 2) - { - init(num); - int i; - for(i = 0; i < num; i++) - { - add_point(*x++, *y++); - } - prepare(); - } - m_last_idx = -1; - } - - - //------------------------------------------------------------------------ - void bspline::bsearch(int n, const double *x, double x0, int *i) - { - int j = n - 1; - int k; - - for(*i = 0; (j - *i) > 1; ) - { - if(x0 < x[k = (*i + j) >> 1]) j = k; - else *i = k; - } - } - - - - //------------------------------------------------------------------------ - double bspline::interpolation(double x, int i) const - { - int j = i + 1; - double d = m_x[i] - m_x[j]; - double h = x - m_x[j]; - double r = m_x[i] - x; - double p = d * d / 6.0; - return (m_am[j] * r * r * r + m_am[i] * h * h * h) / 6.0 / d + - ((m_y[j] - m_am[j] * p) * r + (m_y[i] - m_am[i] * p) * h) / d; - } - - - //------------------------------------------------------------------------ - double bspline::extrapolation_left(double x) const - { - double d = m_x[1] - m_x[0]; - return (-d * m_am[1] / 6 + (m_y[1] - m_y[0]) / d) * - (x - m_x[0]) + - m_y[0]; - } - - //------------------------------------------------------------------------ - double bspline::extrapolation_right(double x) const - { - double d = m_x[m_num - 1] - m_x[m_num - 2]; - return (d * m_am[m_num - 2] / 6 + (m_y[m_num - 1] - m_y[m_num - 2]) / d) * - (x - m_x[m_num - 1]) + - m_y[m_num - 1]; - } - - //------------------------------------------------------------------------ - double bspline::get(double x) const - { - if(m_num > 2) - { - int i; - - // Extrapolation on the left - if(x < m_x[0]) return extrapolation_left(x); - - // Extrapolation on the right - if(x >= m_x[m_num - 1]) return extrapolation_right(x); - - // Interpolation - bsearch(m_num, m_x, x, &i); - return interpolation(x, i); - } - return 0.0; - } - - - //------------------------------------------------------------------------ - double bspline::get_stateful(double x) const - { - if(m_num > 2) - { - // Extrapolation on the left - if(x < m_x[0]) return extrapolation_left(x); - - // Extrapolation on the right - if(x >= m_x[m_num - 1]) return extrapolation_right(x); - - if(m_last_idx >= 0) - { - // Check if x is not in current range - if(x < m_x[m_last_idx] || x > m_x[m_last_idx + 1]) - { - // Check if x between next points (most probably) - if(m_last_idx < m_num - 2 && - x >= m_x[m_last_idx + 1] && - x <= m_x[m_last_idx + 2]) - { - ++m_last_idx; - } - else - if(m_last_idx > 0 && - x >= m_x[m_last_idx - 1] && - x <= m_x[m_last_idx]) - { - // x is between pevious points - --m_last_idx; - } - else - { - // Else perform full search - bsearch(m_num, m_x, x, &m_last_idx); - } - } - return interpolation(x, m_last_idx); - } - else - { - // Interpolation - bsearch(m_num, m_x, x, &m_last_idx); - return interpolation(x, m_last_idx); - } - } - return 0.0; - } - -} - diff -Nru corsix-th-0.30/agg/src/agg_curves.cpp corsix-th-0.62/agg/src/agg_curves.cpp --- corsix-th-0.30/agg/src/agg_curves.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_curves.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,611 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include -#include "agg_curves.h" -#include "agg_math.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - const double curve_distance_epsilon = 1e-30; - const double curve_collinearity_epsilon = 1e-30; - const double curve_angle_tolerance_epsilon = 0.01; - enum curve_recursion_limit_e { curve_recursion_limit = 32 }; - - - - //------------------------------------------------------------------------ - void curve3_inc::approximation_scale(double s) - { - m_scale = s; - } - - //------------------------------------------------------------------------ - double curve3_inc::approximation_scale() const - { - return m_scale; - } - - //------------------------------------------------------------------------ - void curve3_inc::init(double x1, double y1, - double x2, double y2, - double x3, double y3) - { - m_start_x = x1; - m_start_y = y1; - m_end_x = x3; - m_end_y = y3; - - double dx1 = x2 - x1; - double dy1 = y2 - y1; - double dx2 = x3 - x2; - double dy2 = y3 - y2; - - double len = sqrt(dx1 * dx1 + dy1 * dy1) + sqrt(dx2 * dx2 + dy2 * dy2); - - m_num_steps = uround(len * 0.25 * m_scale); - - if(m_num_steps < 4) - { - m_num_steps = 4; - } - - double subdivide_step = 1.0 / m_num_steps; - double subdivide_step2 = subdivide_step * subdivide_step; - - double tmpx = (x1 - x2 * 2.0 + x3) * subdivide_step2; - double tmpy = (y1 - y2 * 2.0 + y3) * subdivide_step2; - - m_saved_fx = m_fx = x1; - m_saved_fy = m_fy = y1; - - m_saved_dfx = m_dfx = tmpx + (x2 - x1) * (2.0 * subdivide_step); - m_saved_dfy = m_dfy = tmpy + (y2 - y1) * (2.0 * subdivide_step); - - m_ddfx = tmpx * 2.0; - m_ddfy = tmpy * 2.0; - - m_step = m_num_steps; - } - - //------------------------------------------------------------------------ - void curve3_inc::rewind(unsigned) - { - if(m_num_steps == 0) - { - m_step = -1; - return; - } - m_step = m_num_steps; - m_fx = m_saved_fx; - m_fy = m_saved_fy; - m_dfx = m_saved_dfx; - m_dfy = m_saved_dfy; - } - - //------------------------------------------------------------------------ - unsigned curve3_inc::vertex(double* x, double* y) - { - if(m_step < 0) return path_cmd_stop; - if(m_step == m_num_steps) - { - *x = m_start_x; - *y = m_start_y; - --m_step; - return path_cmd_move_to; - } - if(m_step == 0) - { - *x = m_end_x; - *y = m_end_y; - --m_step; - return path_cmd_line_to; - } - m_fx += m_dfx; - m_fy += m_dfy; - m_dfx += m_ddfx; - m_dfy += m_ddfy; - *x = m_fx; - *y = m_fy; - --m_step; - return path_cmd_line_to; - } - - //------------------------------------------------------------------------ - void curve3_div::init(double x1, double y1, - double x2, double y2, - double x3, double y3) - { - m_points.remove_all(); - m_distance_tolerance_square = 0.5 / m_approximation_scale; - m_distance_tolerance_square *= m_distance_tolerance_square; - bezier(x1, y1, x2, y2, x3, y3); - m_count = 0; - } - - //------------------------------------------------------------------------ - void curve3_div::recursive_bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - unsigned level) - { - if(level > curve_recursion_limit) - { - return; - } - - // Calculate all the mid-points of the line segments - //---------------------- - double x12 = (x1 + x2) / 2; - double y12 = (y1 + y2) / 2; - double x23 = (x2 + x3) / 2; - double y23 = (y2 + y3) / 2; - double x123 = (x12 + x23) / 2; - double y123 = (y12 + y23) / 2; - - double dx = x3-x1; - double dy = y3-y1; - double d = fabs(((x2 - x3) * dy - (y2 - y3) * dx)); - double da; - - if(d > curve_collinearity_epsilon) - { - // Regular case - //----------------- - if(d * d <= m_distance_tolerance_square * (dx*dx + dy*dy)) - { - // If the curvature doesn't exceed the distance_tolerance value - // we tend to finish subdivisions. - //---------------------- - if(m_angle_tolerance < curve_angle_tolerance_epsilon) - { - m_points.add(point_d(x123, y123)); - return; - } - - // Angle & Cusp Condition - //---------------------- - da = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1)); - if(da >= pi) da = 2*pi - da; - - if(da < m_angle_tolerance) - { - // Finally we can stop the recursion - //---------------------- - m_points.add(point_d(x123, y123)); - return; - } - } - } - else - { - // Collinear case - //------------------ - da = dx*dx + dy*dy; - if(da == 0) - { - d = calc_sq_distance(x1, y1, x2, y2); - } - else - { - d = ((x2 - x1)*dx + (y2 - y1)*dy) / da; - if(d > 0 && d < 1) - { - // Simple collinear case, 1---2---3 - // We can leave just two endpoints - return; - } - if(d <= 0) d = calc_sq_distance(x2, y2, x1, y1); - else if(d >= 1) d = calc_sq_distance(x2, y2, x3, y3); - else d = calc_sq_distance(x2, y2, x1 + d*dx, y1 + d*dy); - } - if(d < m_distance_tolerance_square) - { - m_points.add(point_d(x2, y2)); - return; - } - } - - // Continue subdivision - //---------------------- - recursive_bezier(x1, y1, x12, y12, x123, y123, level + 1); - recursive_bezier(x123, y123, x23, y23, x3, y3, level + 1); - } - - //------------------------------------------------------------------------ - void curve3_div::bezier(double x1, double y1, - double x2, double y2, - double x3, double y3) - { - m_points.add(point_d(x1, y1)); - recursive_bezier(x1, y1, x2, y2, x3, y3, 0); - m_points.add(point_d(x3, y3)); - } - - - - - - //------------------------------------------------------------------------ - void curve4_inc::approximation_scale(double s) - { - m_scale = s; - } - - //------------------------------------------------------------------------ - double curve4_inc::approximation_scale() const - { - return m_scale; - } - - //------------------------------------------------------------------------ - static double MSC60_fix_ICE(double v) { return v; } - - //------------------------------------------------------------------------ - void curve4_inc::init(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - m_start_x = x1; - m_start_y = y1; - m_end_x = x4; - m_end_y = y4; - - double dx1 = x2 - x1; - double dy1 = y2 - y1; - double dx2 = x3 - x2; - double dy2 = y3 - y2; - double dx3 = x4 - x3; - double dy3 = y4 - y3; - - double len = (sqrt(dx1 * dx1 + dy1 * dy1) + - sqrt(dx2 * dx2 + dy2 * dy2) + - sqrt(dx3 * dx3 + dy3 * dy3)) * 0.25 * m_scale; - -#if defined(_MSC_VER) && _MSC_VER <= 1200 - m_num_steps = uround(MSC60_fix_ICE(len)); -#else - m_num_steps = uround(len); -#endif - - if(m_num_steps < 4) - { - m_num_steps = 4; - } - - double subdivide_step = 1.0 / m_num_steps; - double subdivide_step2 = subdivide_step * subdivide_step; - double subdivide_step3 = subdivide_step * subdivide_step * subdivide_step; - - double pre1 = 3.0 * subdivide_step; - double pre2 = 3.0 * subdivide_step2; - double pre4 = 6.0 * subdivide_step2; - double pre5 = 6.0 * subdivide_step3; - - double tmp1x = x1 - x2 * 2.0 + x3; - double tmp1y = y1 - y2 * 2.0 + y3; - - double tmp2x = (x2 - x3) * 3.0 - x1 + x4; - double tmp2y = (y2 - y3) * 3.0 - y1 + y4; - - m_saved_fx = m_fx = x1; - m_saved_fy = m_fy = y1; - - m_saved_dfx = m_dfx = (x2 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdivide_step3; - m_saved_dfy = m_dfy = (y2 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdivide_step3; - - m_saved_ddfx = m_ddfx = tmp1x * pre4 + tmp2x * pre5; - m_saved_ddfy = m_ddfy = tmp1y * pre4 + tmp2y * pre5; - - m_dddfx = tmp2x * pre5; - m_dddfy = tmp2y * pre5; - - m_step = m_num_steps; - } - - //------------------------------------------------------------------------ - void curve4_inc::rewind(unsigned) - { - if(m_num_steps == 0) - { - m_step = -1; - return; - } - m_step = m_num_steps; - m_fx = m_saved_fx; - m_fy = m_saved_fy; - m_dfx = m_saved_dfx; - m_dfy = m_saved_dfy; - m_ddfx = m_saved_ddfx; - m_ddfy = m_saved_ddfy; - } - - //------------------------------------------------------------------------ - unsigned curve4_inc::vertex(double* x, double* y) - { - if(m_step < 0) return path_cmd_stop; - if(m_step == m_num_steps) - { - *x = m_start_x; - *y = m_start_y; - --m_step; - return path_cmd_move_to; - } - - if(m_step == 0) - { - *x = m_end_x; - *y = m_end_y; - --m_step; - return path_cmd_line_to; - } - - m_fx += m_dfx; - m_fy += m_dfy; - m_dfx += m_ddfx; - m_dfy += m_ddfy; - m_ddfx += m_dddfx; - m_ddfy += m_dddfy; - - *x = m_fx; - *y = m_fy; - --m_step; - return path_cmd_line_to; - } - - - - - //------------------------------------------------------------------------ - void curve4_div::init(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - m_points.remove_all(); - m_distance_tolerance_square = 0.5 / m_approximation_scale; - m_distance_tolerance_square *= m_distance_tolerance_square; - bezier(x1, y1, x2, y2, x3, y3, x4, y4); - m_count = 0; - } - - //------------------------------------------------------------------------ - void curve4_div::recursive_bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4, - unsigned level) - { - if(level > curve_recursion_limit) - { - return; - } - - // Calculate all the mid-points of the line segments - //---------------------- - double x12 = (x1 + x2) / 2; - double y12 = (y1 + y2) / 2; - double x23 = (x2 + x3) / 2; - double y23 = (y2 + y3) / 2; - double x34 = (x3 + x4) / 2; - double y34 = (y3 + y4) / 2; - double x123 = (x12 + x23) / 2; - double y123 = (y12 + y23) / 2; - double x234 = (x23 + x34) / 2; - double y234 = (y23 + y34) / 2; - double x1234 = (x123 + x234) / 2; - double y1234 = (y123 + y234) / 2; - - - // Try to approximate the full cubic curve by a single straight line - //------------------ - double dx = x4-x1; - double dy = y4-y1; - - double d2 = fabs(((x2 - x4) * dy - (y2 - y4) * dx)); - double d3 = fabs(((x3 - x4) * dy - (y3 - y4) * dx)); - double da1, da2, k; - - switch((int(d2 > curve_collinearity_epsilon) << 1) + - int(d3 > curve_collinearity_epsilon)) - { - case 0: - // All collinear OR p1==p4 - //---------------------- - k = dx*dx + dy*dy; - if(k == 0) - { - d2 = calc_sq_distance(x1, y1, x2, y2); - d3 = calc_sq_distance(x4, y4, x3, y3); - } - else - { - k = 1 / k; - da1 = x2 - x1; - da2 = y2 - y1; - d2 = k * (da1*dx + da2*dy); - da1 = x3 - x1; - da2 = y3 - y1; - d3 = k * (da1*dx + da2*dy); - if(d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1) - { - // Simple collinear case, 1---2---3---4 - // We can leave just two endpoints - return; - } - if(d2 <= 0) d2 = calc_sq_distance(x2, y2, x1, y1); - else if(d2 >= 1) d2 = calc_sq_distance(x2, y2, x4, y4); - else d2 = calc_sq_distance(x2, y2, x1 + d2*dx, y1 + d2*dy); - - if(d3 <= 0) d3 = calc_sq_distance(x3, y3, x1, y1); - else if(d3 >= 1) d3 = calc_sq_distance(x3, y3, x4, y4); - else d3 = calc_sq_distance(x3, y3, x1 + d3*dx, y1 + d3*dy); - } - if(d2 > d3) - { - if(d2 < m_distance_tolerance_square) - { - m_points.add(point_d(x2, y2)); - return; - } - } - else - { - if(d3 < m_distance_tolerance_square) - { - m_points.add(point_d(x3, y3)); - return; - } - } - break; - - case 1: - // p1,p2,p4 are collinear, p3 is significant - //---------------------- - if(d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy)) - { - if(m_angle_tolerance < curve_angle_tolerance_epsilon) - { - m_points.add(point_d(x23, y23)); - return; - } - - // Angle Condition - //---------------------- - da1 = fabs(atan2(y4 - y3, x4 - x3) - atan2(y3 - y2, x3 - x2)); - if(da1 >= pi) da1 = 2*pi - da1; - - if(da1 < m_angle_tolerance) - { - m_points.add(point_d(x2, y2)); - m_points.add(point_d(x3, y3)); - return; - } - - if(m_cusp_limit != 0.0) - { - if(da1 > m_cusp_limit) - { - m_points.add(point_d(x3, y3)); - return; - } - } - } - break; - - case 2: - // p1,p3,p4 are collinear, p2 is significant - //---------------------- - if(d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy)) - { - if(m_angle_tolerance < curve_angle_tolerance_epsilon) - { - m_points.add(point_d(x23, y23)); - return; - } - - // Angle Condition - //---------------------- - da1 = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1)); - if(da1 >= pi) da1 = 2*pi - da1; - - if(da1 < m_angle_tolerance) - { - m_points.add(point_d(x2, y2)); - m_points.add(point_d(x3, y3)); - return; - } - - if(m_cusp_limit != 0.0) - { - if(da1 > m_cusp_limit) - { - m_points.add(point_d(x2, y2)); - return; - } - } - } - break; - - case 3: - // Regular case - //----------------- - if((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy)) - { - // If the curvature doesn't exceed the distance_tolerance value - // we tend to finish subdivisions. - //---------------------- - if(m_angle_tolerance < curve_angle_tolerance_epsilon) - { - m_points.add(point_d(x23, y23)); - return; - } - - // Angle & Cusp Condition - //---------------------- - k = atan2(y3 - y2, x3 - x2); - da1 = fabs(k - atan2(y2 - y1, x2 - x1)); - da2 = fabs(atan2(y4 - y3, x4 - x3) - k); - if(da1 >= pi) da1 = 2*pi - da1; - if(da2 >= pi) da2 = 2*pi - da2; - - if(da1 + da2 < m_angle_tolerance) - { - // Finally we can stop the recursion - //---------------------- - m_points.add(point_d(x23, y23)); - return; - } - - if(m_cusp_limit != 0.0) - { - if(da1 > m_cusp_limit) - { - m_points.add(point_d(x2, y2)); - return; - } - - if(da2 > m_cusp_limit) - { - m_points.add(point_d(x3, y3)); - return; - } - } - } - break; - } - - // Continue subdivision - //---------------------- - recursive_bezier(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1); - recursive_bezier(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1); - } - - //------------------------------------------------------------------------ - void curve4_div::bezier(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4) - { - m_points.add(point_d(x1, y1)); - recursive_bezier(x1, y1, x2, y2, x3, y3, x4, y4, 0); - m_points.add(point_d(x4, y4)); - } - -} - diff -Nru corsix-th-0.30/agg/src/agg_embedded_raster_fonts.cpp corsix-th-0.62/agg/src/agg_embedded_raster_fonts.cpp --- corsix-th-0.30/agg/src/agg_embedded_raster_fonts.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_embedded_raster_fonts.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,10426 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include "agg_embedded_raster_fonts.h" - -namespace agg -{ - - const int8u gse4x6[] = - { - 6, 0, 32, 128-32, - - 0x00,0x00,0x07,0x00,0x0e,0x00,0x15,0x00,0x1c,0x00,0x23,0x00,0x2a,0x00,0x31,0x00,0x38,0x00, - 0x3f,0x00,0x46,0x00,0x4d,0x00,0x54,0x00,0x5b,0x00,0x62,0x00,0x69,0x00,0x70,0x00,0x77,0x00, - 0x7e,0x00,0x85,0x00,0x8c,0x00,0x93,0x00,0x9a,0x00,0xa1,0x00,0xa8,0x00,0xaf,0x00,0xb6,0x00, - 0xbd,0x00,0xc4,0x00,0xcb,0x00,0xd2,0x00,0xd9,0x00,0xe0,0x00,0xe7,0x00,0xee,0x00,0xf5,0x00, - 0xfc,0x00,0x03,0x01,0x0a,0x01,0x11,0x01,0x18,0x01,0x1f,0x01,0x26,0x01,0x2d,0x01,0x34,0x01, - 0x3b,0x01,0x42,0x01,0x49,0x01,0x50,0x01,0x57,0x01,0x5e,0x01,0x65,0x01,0x6c,0x01,0x73,0x01, - 0x7a,0x01,0x81,0x01,0x88,0x01,0x8f,0x01,0x96,0x01,0x9d,0x01,0xa4,0x01,0xab,0x01,0xb2,0x01, - 0xb9,0x01,0xc0,0x01,0xc7,0x01,0xce,0x01,0xd5,0x01,0xdc,0x01,0xe3,0x01,0xea,0x01,0xf1,0x01, - 0xf8,0x01,0xff,0x01,0x06,0x02,0x0d,0x02,0x14,0x02,0x1b,0x02,0x22,0x02,0x29,0x02,0x30,0x02, - 0x37,0x02,0x3e,0x02,0x45,0x02,0x4c,0x02,0x53,0x02,0x5a,0x02,0x61,0x02,0x68,0x02,0x6f,0x02, - 0x76,0x02,0x7d,0x02,0x84,0x02,0x8b,0x02,0x92,0x02,0x99,0x02, - - 4, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x21 '!' - 0x40,0x40,0x40,0x00,0x40,0x00, - - 4, // 0x22 '"' - 0xa0,0xa0,0x00,0x00,0x00,0x00, - - 4, // 0x23 '#' - 0x60,0xf0,0x60,0xf0,0x60,0x00, - - 4, // 0x24 '$' - 0x40,0x60,0xc0,0x60,0xc0,0x40, - - 4, // 0x25 '%' - 0xa0,0x20,0x40,0x80,0xa0,0x00, - - 4, // 0x26 '&' - 0xe0,0xa0,0x50,0xa0,0xd0,0x00, - - 4, // 0x27 ''' - 0x40,0x40,0x00,0x00,0x00,0x00, - - 4, // 0x28 '(' - 0x20,0x40,0x40,0x40,0x20,0x00, - - 4, // 0x29 ')' - 0x40,0x20,0x20,0x20,0x40,0x00, - - 4, // 0x2a '*' - 0xa0,0x40,0xe0,0x40,0xa0,0x00, - - 4, // 0x2b '+' - 0x40,0x40,0xe0,0x40,0x40,0x00, - - 4, // 0x2c ',' - 0x00,0x00,0x00,0x40,0x40,0x80, - - 4, // 0x2d '-' - 0x00,0x00,0xe0,0x00,0x00,0x00, - - 4, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x40,0x00, - - 4, // 0x2f '/' - 0x10,0x20,0x20,0x40,0x40,0x80, - - 4, // 0x30 '0' - 0xe0,0xa0,0xa0,0xa0,0xe0,0x00, - - 4, // 0x31 '1' - 0x40,0xc0,0x40,0x40,0xe0,0x00, - - 4, // 0x32 '2' - 0xe0,0xa0,0x20,0x40,0xe0,0x00, - - 4, // 0x33 '3' - 0xe0,0x20,0x40,0x20,0xe0,0x00, - - 4, // 0x34 '4' - 0xa0,0xa0,0xe0,0x20,0x20,0x00, - - 4, // 0x35 '5' - 0xe0,0x80,0xc0,0x20,0xc0,0x00, - - 4, // 0x36 '6' - 0x40,0x80,0xe0,0xa0,0xe0,0x00, - - 4, // 0x37 '7' - 0xe0,0xa0,0x20,0x40,0x40,0x00, - - 4, // 0x38 '8' - 0xe0,0xa0,0x40,0xa0,0xe0,0x00, - - 4, // 0x39 '9' - 0xe0,0xa0,0xe0,0x20,0xc0,0x00, - - 4, // 0x3a ':' - 0x00,0x40,0x00,0x40,0x00,0x00, - - 4, // 0x3b ';' - 0x00,0x40,0x00,0x40,0x40,0x80, - - 4, // 0x3c '<' - 0x20,0x40,0x80,0x40,0x20,0x00, - - 4, // 0x3d '=' - 0x00,0xe0,0x00,0xe0,0x00,0x00, - - 4, // 0x3e '>' - 0x80,0x40,0x20,0x40,0x80,0x00, - - 4, // 0x3f '?' - 0xc0,0x20,0x40,0x00,0x40,0x00, - - 4, // 0x40 '@' - 0x40,0xa0,0xe0,0xe0,0x80,0x60, - - 4, // 0x41 'A' - 0x40,0xa0,0xe0,0xa0,0xa0,0x00, - - 4, // 0x42 'B' - 0xc0,0xa0,0xc0,0xa0,0xc0,0x00, - - 4, // 0x43 'C' - 0x60,0x80,0x80,0x80,0x60,0x00, - - 4, // 0x44 'D' - 0xc0,0xa0,0xa0,0xa0,0xc0,0x00, - - 4, // 0x45 'E' - 0xe0,0x80,0xc0,0x80,0xe0,0x00, - - 4, // 0x46 'F' - 0xe0,0x80,0xc0,0x80,0x80,0x00, - - 4, // 0x47 'G' - 0x60,0x80,0xa0,0xa0,0x40,0x00, - - 4, // 0x48 'H' - 0xa0,0xa0,0xe0,0xa0,0xa0,0x00, - - 4, // 0x49 'I' - 0xe0,0x40,0x40,0x40,0xe0,0x00, - - 4, // 0x4a 'J' - 0x20,0x20,0x20,0x20,0xa0,0x40, - - 4, // 0x4b 'K' - 0xa0,0xa0,0xc0,0xc0,0xa0,0x00, - - 4, // 0x4c 'L' - 0x80,0x80,0x80,0x80,0xe0,0x00, - - 4, // 0x4d 'M' - 0xa0,0xe0,0xa0,0xa0,0xa0,0x00, - - 4, // 0x4e 'N' - 0x90,0xd0,0xb0,0x90,0x90,0x00, - - 4, // 0x4f 'O' - 0x40,0xa0,0xa0,0xa0,0x40,0x00, - - 4, // 0x50 'P' - 0xc0,0xa0,0xa0,0xc0,0x80,0x00, - - 4, // 0x51 'Q' - 0x40,0xa0,0xa0,0xa0,0x60,0x00, - - 4, // 0x52 'R' - 0xc0,0xa0,0xa0,0xc0,0xa0,0x00, - - 4, // 0x53 'S' - 0x60,0x80,0x40,0x20,0xc0,0x00, - - 4, // 0x54 'T' - 0xe0,0x40,0x40,0x40,0x40,0x00, - - 4, // 0x55 'U' - 0xa0,0xa0,0xa0,0xa0,0xe0,0x00, - - 4, // 0x56 'V' - 0xa0,0xa0,0xa0,0xa0,0x40,0x00, - - 4, // 0x57 'W' - 0xa0,0xa0,0xa0,0xe0,0xa0,0x00, - - 4, // 0x58 'X' - 0xa0,0xa0,0x40,0xa0,0xa0,0x00, - - 4, // 0x59 'Y' - 0xa0,0xa0,0x40,0x40,0x40,0x00, - - 4, // 0x5a 'Z' - 0xe0,0x20,0x40,0x80,0xe0,0x00, - - 4, // 0x5b '[' - 0xc0,0x80,0x80,0x80,0xc0,0x00, - - 4, // 0x5c '\' - 0x80,0x40,0x40,0x20,0x20,0x10, - - 4, // 0x5d ']' - 0xc0,0x40,0x40,0x40,0xc0,0x00, - - 4, // 0x5e '^' - 0x40,0xa0,0x00,0x00,0x00,0x00, - - 4, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0xf0, - - 4, // 0x60 '`' - 0x40,0x20,0x00,0x00,0x00,0x00, - - 4, // 0x61 'a' - 0x00,0x60,0xa0,0xa0,0x70,0x00, - - 4, // 0x62 'b' - 0x80,0x80,0xc0,0xa0,0xc0,0x00, - - 4, // 0x63 'c' - 0x00,0x60,0x80,0x80,0x60,0x00, - - 4, // 0x64 'd' - 0x20,0x20,0x60,0xa0,0x60,0x00, - - 4, // 0x65 'e' - 0x00,0x40,0xe0,0x80,0x60,0x00, - - 4, // 0x66 'f' - 0x20,0x40,0xe0,0x40,0x40,0x00, - - 4, // 0x67 'g' - 0x00,0x60,0xa0,0x60,0x20,0xc0, - - 4, // 0x68 'h' - 0x80,0x80,0xc0,0xa0,0xa0,0x00, - - 4, // 0x69 'i' - 0x40,0x00,0xc0,0x40,0xe0,0x00, - - 4, // 0x6a 'j' - 0x40,0x00,0xc0,0x40,0x40,0x80, - - 4, // 0x6b 'k' - 0x80,0x80,0xa0,0xc0,0xa0,0x00, - - 4, // 0x6c 'l' - 0xc0,0x40,0x40,0x40,0xe0,0x00, - - 4, // 0x6d 'm' - 0x00,0xa0,0xf0,0xf0,0x90,0x00, - - 4, // 0x6e 'n' - 0x00,0xc0,0xa0,0xa0,0xa0,0x00, - - 4, // 0x6f 'o' - 0x00,0x40,0xa0,0xa0,0x40,0x00, - - 4, // 0x70 'p' - 0x00,0xc0,0xa0,0xc0,0x80,0x80, - - 4, // 0x71 'q' - 0x00,0x60,0xa0,0x60,0x20,0x20, - - 4, // 0x72 'r' - 0x00,0xa0,0x50,0x40,0x40,0x00, - - 4, // 0x73 's' - 0x00,0x60,0xc0,0x20,0xc0,0x00, - - 4, // 0x74 't' - 0x40,0x40,0xe0,0x40,0x60,0x00, - - 4, // 0x75 'u' - 0x00,0xa0,0xa0,0xa0,0x60,0x00, - - 4, // 0x76 'v' - 0x00,0xa0,0xa0,0xa0,0x40,0x00, - - 4, // 0x77 'w' - 0x00,0xa0,0xa0,0xe0,0xa0,0x00, - - 4, // 0x78 'x' - 0x00,0xa0,0x40,0xa0,0xa0,0x00, - - 4, // 0x79 'y' - 0x00,0xa0,0xa0,0x60,0x20,0xc0, - - 4, // 0x7a 'z' - 0x00,0xe0,0x40,0x80,0xe0,0x00, - - 4, // 0x7b '{' - 0x30,0x20,0xc0,0x20,0x30,0x00, - - 4, // 0x7c '|' - 0x40,0x40,0x00,0x40,0x40,0x40, - - 4, // 0x7d '}' - 0xc0,0x40,0x30,0x40,0xc0,0x00, - - 4, // 0x7e '~' - 0x50,0xa0,0x00,0x00,0x00,0x00, - - 4, // 0x7f '' - 0x00,0x60,0x90,0xf0,0x00,0x00, - 0 - }; - - const int8u gse4x8[] = - { - 8, 0, 32, 128-32, - - 0x00,0x00,0x09,0x00,0x12,0x00,0x1b,0x00,0x24,0x00,0x2d,0x00,0x36,0x00,0x3f,0x00,0x48,0x00, - 0x51,0x00,0x5a,0x00,0x63,0x00,0x6c,0x00,0x75,0x00,0x7e,0x00,0x87,0x00,0x90,0x00,0x99,0x00, - 0xa2,0x00,0xab,0x00,0xb4,0x00,0xbd,0x00,0xc6,0x00,0xcf,0x00,0xd8,0x00,0xe1,0x00,0xea,0x00, - 0xf3,0x00,0xfc,0x00,0x05,0x01,0x0e,0x01,0x17,0x01,0x20,0x01,0x29,0x01,0x32,0x01,0x3b,0x01, - 0x44,0x01,0x4d,0x01,0x56,0x01,0x5f,0x01,0x68,0x01,0x71,0x01,0x7a,0x01,0x83,0x01,0x8c,0x01, - 0x95,0x01,0x9e,0x01,0xa7,0x01,0xb0,0x01,0xb9,0x01,0xc2,0x01,0xcb,0x01,0xd4,0x01,0xdd,0x01, - 0xe6,0x01,0xef,0x01,0xf8,0x01,0x01,0x02,0x0a,0x02,0x13,0x02,0x1c,0x02,0x25,0x02,0x2e,0x02, - 0x37,0x02,0x40,0x02,0x49,0x02,0x52,0x02,0x5b,0x02,0x64,0x02,0x6d,0x02,0x76,0x02,0x7f,0x02, - 0x88,0x02,0x91,0x02,0x9a,0x02,0xa3,0x02,0xac,0x02,0xb5,0x02,0xbe,0x02,0xc7,0x02,0xd0,0x02, - 0xd9,0x02,0xe2,0x02,0xeb,0x02,0xf4,0x02,0xfd,0x02,0x06,0x03,0x0f,0x03,0x18,0x03,0x21,0x03, - 0x2a,0x03,0x33,0x03,0x3c,0x03,0x45,0x03,0x4e,0x03,0x57,0x03, - - 4, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x21 '!' - 0x00,0x40,0x40,0x40,0x40,0x00,0x40,0x00, - - 4, // 0x22 '"' - 0x00,0xa0,0xa0,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x23 '#' - 0x60,0x60,0xf0,0x60,0x60,0xf0,0x60,0x60, - - 4, // 0x24 '$' - 0x40,0x60,0xc0,0xc0,0x60,0x60,0xc0,0x40, - - 4, // 0x25 '%' - 0x00,0xa0,0x20,0x40,0x40,0x80,0xa0,0x00, - - 4, // 0x26 '&' - 0x00,0x40,0xa0,0xa0,0x40,0xb0,0xa0,0x70, - - 4, // 0x27 ''' - 0x00,0x40,0x40,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x28 '(' - 0x20,0x40,0x80,0x80,0x80,0x80,0x40,0x20, - - 4, // 0x29 ')' - 0x80,0x40,0x20,0x20,0x20,0x20,0x40,0x80, - - 4, // 0x2a '*' - 0x00,0xa0,0x40,0xe0,0x40,0xa0,0x00,0x00, - - 4, // 0x2b '+' - 0x00,0x40,0x40,0xe0,0x40,0x40,0x00,0x00, - - 4, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80, - - 4, // 0x2d '-' - 0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00, - - 4, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, - - 4, // 0x2f '/' - 0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80, - - 4, // 0x30 '0' - 0x00,0xe0,0xa0,0xa0,0xa0,0xa0,0xe0,0x00, - - 4, // 0x31 '1' - 0x00,0x40,0xc0,0x40,0x40,0x40,0xe0,0x00, - - 4, // 0x32 '2' - 0x00,0xe0,0xa0,0x20,0x40,0x80,0xe0,0x00, - - 4, // 0x33 '3' - 0x00,0xe0,0x20,0x40,0x20,0x20,0xe0,0x00, - - 4, // 0x34 '4' - 0x00,0x60,0xa0,0xa0,0xf0,0x20,0x20,0x00, - - 4, // 0x35 '5' - 0x00,0xe0,0x80,0xc0,0x20,0x20,0xc0,0x00, - - 4, // 0x36 '6' - 0x00,0x40,0x80,0xe0,0xa0,0xa0,0xe0,0x00, - - 4, // 0x37 '7' - 0x00,0xe0,0xa0,0x20,0x40,0x40,0x40,0x00, - - 4, // 0x38 '8' - 0x00,0xe0,0xa0,0x40,0xa0,0xa0,0xe0,0x00, - - 4, // 0x39 '9' - 0x00,0xe0,0xa0,0xe0,0x20,0x20,0x40,0x00, - - 4, // 0x3a ':' - 0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00, - - 4, // 0x3b ';' - 0x00,0x00,0x40,0x00,0x00,0x40,0x40,0x80, - - 4, // 0x3c '<' - 0x00,0x20,0x40,0x80,0x40,0x20,0x00,0x00, - - 4, // 0x3d '=' - 0x00,0x00,0xe0,0x00,0xe0,0x00,0x00,0x00, - - 4, // 0x3e '>' - 0x00,0x80,0x40,0x20,0x40,0x80,0x00,0x00, - - 4, // 0x3f '?' - 0x00,0x40,0xa0,0x20,0x40,0x00,0x40,0x00, - - 4, // 0x40 '@' - 0x00,0x40,0xa0,0xe0,0xe0,0x80,0x60,0x00, - - 4, // 0x41 'A' - 0x00,0x40,0xa0,0xa0,0xe0,0xa0,0xa0,0x00, - - 4, // 0x42 'B' - 0x00,0xc0,0xa0,0xc0,0xa0,0xa0,0xc0,0x00, - - 4, // 0x43 'C' - 0x00,0x40,0xa0,0x80,0x80,0xa0,0x40,0x00, - - 4, // 0x44 'D' - 0x00,0xc0,0xa0,0xa0,0xa0,0xa0,0xc0,0x00, - - 4, // 0x45 'E' - 0x00,0xe0,0x80,0xc0,0x80,0x80,0xe0,0x00, - - 4, // 0x46 'F' - 0x00,0xe0,0x80,0xc0,0x80,0x80,0x80,0x00, - - 4, // 0x47 'G' - 0x00,0x60,0x80,0xa0,0xa0,0xa0,0x40,0x00, - - 4, // 0x48 'H' - 0x00,0xa0,0xa0,0xe0,0xa0,0xa0,0xa0,0x00, - - 4, // 0x49 'I' - 0x00,0xe0,0x40,0x40,0x40,0x40,0xe0,0x00, - - 4, // 0x4a 'J' - 0x00,0x20,0x20,0x20,0x20,0xa0,0x40,0x00, - - 4, // 0x4b 'K' - 0x00,0xa0,0xa0,0xc0,0xc0,0xa0,0xa0,0x00, - - 4, // 0x4c 'L' - 0x00,0x80,0x80,0x80,0x80,0x80,0xe0,0x00, - - 4, // 0x4d 'M' - 0x00,0xa0,0xe0,0xa0,0xa0,0xa0,0xa0,0x00, - - 4, // 0x4e 'N' - 0x00,0x90,0x90,0xd0,0xb0,0x90,0x90,0x00, - - 4, // 0x4f 'O' - 0x00,0x40,0xa0,0xa0,0xa0,0xa0,0x40,0x00, - - 4, // 0x50 'P' - 0x00,0xc0,0xa0,0xa0,0xc0,0x80,0x80,0x00, - - 4, // 0x51 'Q' - 0x00,0x40,0xa0,0xa0,0xa0,0xa0,0x60,0x00, - - 4, // 0x52 'R' - 0x00,0xc0,0xa0,0xa0,0xc0,0xc0,0xa0,0x00, - - 4, // 0x53 'S' - 0x00,0x60,0x80,0x40,0x20,0x20,0xc0,0x00, - - 4, // 0x54 'T' - 0x00,0xe0,0x40,0x40,0x40,0x40,0x40,0x00, - - 4, // 0x55 'U' - 0x00,0xa0,0xa0,0xa0,0xa0,0xa0,0x40,0x00, - - 4, // 0x56 'V' - 0x00,0xa0,0xa0,0xa0,0xa0,0x40,0x40,0x00, - - 4, // 0x57 'W' - 0x00,0xa0,0xa0,0xa0,0xa0,0xe0,0xa0,0x00, - - 4, // 0x58 'X' - 0x00,0xa0,0xa0,0x40,0xa0,0xa0,0xa0,0x00, - - 4, // 0x59 'Y' - 0x00,0xa0,0xa0,0x40,0x40,0x40,0x40,0x00, - - 4, // 0x5a 'Z' - 0x00,0xe0,0x20,0x40,0x40,0x80,0xe0,0x00, - - 4, // 0x5b '[' - 0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, - - 4, // 0x5c '\' - 0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10, - - 4, // 0x5d ']' - 0xc0,0x40,0x40,0x40,0x40,0x40,0x40,0xc0, - - 4, // 0x5e '^' - 0x00,0x40,0xa0,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, - - 4, // 0x60 '`' - 0x00,0x40,0x20,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x61 'a' - 0x00,0x00,0x60,0xa0,0xa0,0xa0,0x70,0x00, - - 4, // 0x62 'b' - 0x00,0x80,0x80,0xc0,0xa0,0xa0,0xc0,0x00, - - 4, // 0x63 'c' - 0x00,0x00,0x40,0xa0,0x80,0xa0,0x40,0x00, - - 4, // 0x64 'd' - 0x00,0x20,0x20,0x60,0xa0,0xa0,0x60,0x00, - - 4, // 0x65 'e' - 0x00,0x00,0x40,0xa0,0xe0,0x80,0x60,0x00, - - 4, // 0x66 'f' - 0x00,0x20,0x40,0x40,0xe0,0x40,0x40,0x00, - - 4, // 0x67 'g' - 0x00,0x00,0x60,0xa0,0xa0,0x60,0x20,0xc0, - - 4, // 0x68 'h' - 0x00,0x80,0x80,0xc0,0xa0,0xa0,0xa0,0x00, - - 4, // 0x69 'i' - 0x00,0x40,0x00,0xc0,0x40,0x40,0xe0,0x00, - - 4, // 0x6a 'j' - 0x00,0x40,0x00,0xc0,0x40,0x40,0x40,0x80, - - 4, // 0x6b 'k' - 0x00,0x80,0x80,0xa0,0xc0,0xc0,0xa0,0x00, - - 4, // 0x6c 'l' - 0x00,0xc0,0x40,0x40,0x40,0x40,0xe0,0x00, - - 4, // 0x6d 'm' - 0x00,0x00,0xa0,0xf0,0xf0,0xf0,0x90,0x00, - - 4, // 0x6e 'n' - 0x00,0x00,0xc0,0xa0,0xa0,0xa0,0xa0,0x00, - - 4, // 0x6f 'o' - 0x00,0x00,0x40,0xa0,0xa0,0xa0,0x40,0x00, - - 4, // 0x70 'p' - 0x00,0x00,0xc0,0xa0,0xa0,0xc0,0x80,0x80, - - 4, // 0x71 'q' - 0x00,0x00,0x60,0xa0,0xa0,0x60,0x20,0x20, - - 4, // 0x72 'r' - 0x00,0x00,0xa0,0x50,0x40,0x40,0x40,0x00, - - 4, // 0x73 's' - 0x00,0x00,0x60,0x80,0x40,0x20,0xc0,0x00, - - 4, // 0x74 't' - 0x00,0x40,0x40,0xe0,0x40,0x40,0x20,0x00, - - 4, // 0x75 'u' - 0x00,0x00,0xa0,0xa0,0xa0,0xa0,0x60,0x00, - - 4, // 0x76 'v' - 0x00,0x00,0xa0,0xa0,0xa0,0x40,0x40,0x00, - - 4, // 0x77 'w' - 0x00,0x00,0xa0,0xa0,0xa0,0xe0,0xa0,0x00, - - 4, // 0x78 'x' - 0x00,0x00,0xa0,0xa0,0x40,0xa0,0xa0,0x00, - - 4, // 0x79 'y' - 0x00,0x00,0xa0,0xa0,0xa0,0x60,0x20,0xc0, - - 4, // 0x7a 'z' - 0x00,0x00,0xe0,0x20,0x40,0x80,0xe0,0x00, - - 4, // 0x7b '{' - 0x10,0x20,0x20,0xc0,0x20,0x20,0x10,0x00, - - 4, // 0x7c '|' - 0x00,0x40,0x40,0x40,0x00,0x40,0x40,0x40, - - 4, // 0x7d '}' - 0x80,0x40,0x40,0x30,0x40,0x40,0x80,0x00, - - 4, // 0x7e '~' - 0x00,0x50,0xa0,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x7f '' - 0x00,0x00,0x00,0x60,0x90,0xf0,0x00,0x00, - 0 - }; - - const int8u gse5x7[] = - { - 7, 0, 32, 128-32, - - 0x00,0x00,0x08,0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x38,0x00,0x40,0x00, - 0x48,0x00,0x50,0x00,0x58,0x00,0x60,0x00,0x68,0x00,0x70,0x00,0x78,0x00,0x80,0x00,0x88,0x00, - 0x90,0x00,0x98,0x00,0xa0,0x00,0xa8,0x00,0xb0,0x00,0xb8,0x00,0xc0,0x00,0xc8,0x00,0xd0,0x00, - 0xd8,0x00,0xe0,0x00,0xe8,0x00,0xf0,0x00,0xf8,0x00,0x00,0x01,0x08,0x01,0x10,0x01,0x18,0x01, - 0x20,0x01,0x28,0x01,0x30,0x01,0x38,0x01,0x40,0x01,0x48,0x01,0x50,0x01,0x58,0x01,0x60,0x01, - 0x68,0x01,0x70,0x01,0x78,0x01,0x80,0x01,0x88,0x01,0x90,0x01,0x98,0x01,0xa0,0x01,0xa8,0x01, - 0xb0,0x01,0xb8,0x01,0xc0,0x01,0xc8,0x01,0xd0,0x01,0xd8,0x01,0xe0,0x01,0xe8,0x01,0xf0,0x01, - 0xf8,0x01,0x00,0x02,0x08,0x02,0x10,0x02,0x18,0x02,0x20,0x02,0x28,0x02,0x30,0x02,0x38,0x02, - 0x40,0x02,0x48,0x02,0x50,0x02,0x58,0x02,0x60,0x02,0x68,0x02,0x70,0x02,0x78,0x02,0x80,0x02, - 0x88,0x02,0x90,0x02,0x98,0x02,0xa0,0x02,0xa8,0x02,0xb0,0x02,0xb8,0x02,0xc0,0x02,0xc8,0x02, - 0xd0,0x02,0xd8,0x02,0xe0,0x02,0xe8,0x02,0xf0,0x02,0xf8,0x02, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x00,0x20,0x00, - - 5, // 0x22 '"' - 0x00,0x50,0x50,0x00,0x00,0x00,0x00, - - 5, // 0x23 '#' - 0x00,0x50,0xf8,0x50,0xf8,0x50,0x00, - - 5, // 0x24 '$' - 0x20,0x78,0xa0,0x70,0x28,0xf0,0x20, - - 5, // 0x25 '%' - 0x00,0x88,0x10,0x20,0x40,0x88,0x00, - - 5, // 0x26 '&' - 0x00,0x40,0xa0,0x68,0x90,0x68,0x00, - - 5, // 0x27 ''' - 0x00,0x20,0x20,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x10,0x20,0x40,0x40,0x40,0x20,0x10, - - 5, // 0x29 ')' - 0x80,0x40,0x20,0x20,0x20,0x40,0x80, - - 5, // 0x2a '*' - 0x00,0x20,0xa8,0x70,0xa8,0x20,0x00, - - 5, // 0x2b '+' - 0x00,0x20,0x20,0xf8,0x20,0x20,0x00, - - 5, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x20,0x20,0x40, - - 5, // 0x2d '-' - 0x00,0x00,0x00,0xf0,0x00,0x00,0x00, - - 5, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x40,0x00, - - 5, // 0x2f '/' - 0x00,0x08,0x10,0x20,0x40,0x80,0x00, - - 5, // 0x30 '0' - 0x00,0x60,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x31 '1' - 0x00,0x20,0x60,0x20,0x20,0x70,0x00, - - 5, // 0x32 '2' - 0x00,0x60,0x90,0x20,0x40,0xf0,0x00, - - 5, // 0x33 '3' - 0x00,0xf0,0x20,0x60,0x10,0xe0,0x00, - - 5, // 0x34 '4' - 0x00,0x30,0x50,0x90,0xf0,0x10,0x00, - - 5, // 0x35 '5' - 0x00,0xf0,0x80,0xe0,0x10,0xe0,0x00, - - 5, // 0x36 '6' - 0x00,0x60,0x80,0xe0,0x90,0x60,0x00, - - 5, // 0x37 '7' - 0x00,0xf0,0x90,0x20,0x40,0x40,0x00, - - 5, // 0x38 '8' - 0x00,0x60,0x90,0x60,0x90,0x60,0x00, - - 5, // 0x39 '9' - 0x00,0x60,0x90,0x70,0x10,0x60,0x00, - - 5, // 0x3a ':' - 0x00,0x00,0x20,0x00,0x20,0x00,0x00, - - 5, // 0x3b ';' - 0x00,0x00,0x20,0x00,0x20,0x20,0x40, - - 5, // 0x3c '<' - 0x00,0x10,0x20,0x40,0x20,0x10,0x00, - - 5, // 0x3d '=' - 0x00,0x00,0xf0,0x00,0xf0,0x00,0x00, - - 5, // 0x3e '>' - 0x00,0x80,0x40,0x20,0x40,0x80,0x00, - - 5, // 0x3f '?' - 0x00,0x60,0x90,0x20,0x00,0x20,0x00, - - 5, // 0x40 '@' - 0x00,0x60,0x90,0xb0,0x80,0x70,0x00, - - 5, // 0x41 'A' - 0x00,0x60,0x90,0xf0,0x90,0x90,0x00, - - 5, // 0x42 'B' - 0x00,0xe0,0x90,0xe0,0x90,0xe0,0x00, - - 5, // 0x43 'C' - 0x00,0x60,0x90,0x80,0x90,0x60,0x00, - - 5, // 0x44 'D' - 0x00,0xe0,0x90,0x90,0x90,0xe0,0x00, - - 5, // 0x45 'E' - 0x00,0xf0,0x80,0xe0,0x80,0xf0,0x00, - - 5, // 0x46 'F' - 0x00,0xf0,0x80,0xe0,0x80,0x80,0x00, - - 5, // 0x47 'G' - 0x00,0x70,0x80,0xb0,0x90,0x60,0x00, - - 5, // 0x48 'H' - 0x00,0x90,0x90,0xf0,0x90,0x90,0x00, - - 5, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x4a 'J' - 0x00,0x70,0x20,0x20,0xa0,0x40,0x00, - - 5, // 0x4b 'K' - 0x00,0x90,0xa0,0xc0,0xa0,0x90,0x00, - - 5, // 0x4c 'L' - 0x00,0x80,0x80,0x80,0x80,0xf0,0x00, - - 5, // 0x4d 'M' - 0x00,0x90,0xf0,0x90,0x90,0x90,0x00, - - 5, // 0x4e 'N' - 0x00,0x90,0xd0,0xb0,0x90,0x90,0x00, - - 5, // 0x4f 'O' - 0x00,0x60,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x50 'P' - 0x00,0xe0,0x90,0xe0,0x80,0x80,0x00, - - 5, // 0x51 'Q' - 0x00,0x60,0x90,0x90,0xa0,0x50,0x00, - - 5, // 0x52 'R' - 0x00,0xe0,0x90,0xe0,0xa0,0x90,0x00, - - 5, // 0x53 'S' - 0x00,0x70,0x80,0x60,0x10,0xe0,0x00, - - 5, // 0x54 'T' - 0x00,0x70,0x20,0x20,0x20,0x20,0x00, - - 5, // 0x55 'U' - 0x00,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x56 'V' - 0x00,0x50,0x50,0x50,0x20,0x20,0x00, - - 5, // 0x57 'W' - 0x00,0x90,0x90,0x90,0xf0,0x90,0x00, - - 5, // 0x58 'X' - 0x00,0x90,0x90,0x60,0x90,0x90,0x00, - - 5, // 0x59 'Y' - 0x00,0x50,0x50,0x20,0x20,0x20,0x00, - - 5, // 0x5a 'Z' - 0x00,0xf0,0x10,0x20,0x40,0xf0,0x00, - - 5, // 0x5b '[' - 0x70,0x40,0x40,0x40,0x40,0x40,0x70, - - 5, // 0x5c '\' - 0x00,0x80,0x40,0x20,0x10,0x08,0x00, - - 5, // 0x5d ']' - 0xe0,0x20,0x20,0x20,0x20,0x20,0xe0, - - 5, // 0x5e '^' - 0x00,0x20,0x50,0x00,0x00,0x00,0x00, - - 5, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0xf8,0x00, - - 5, // 0x60 '`' - 0x00,0x40,0x20,0x00,0x00,0x00,0x00, - - 5, // 0x61 'a' - 0x00,0x00,0x60,0xa0,0xa0,0x50,0x00, - - 5, // 0x62 'b' - 0x00,0x80,0x80,0xe0,0x90,0xe0,0x00, - - 5, // 0x63 'c' - 0x00,0x00,0x70,0x80,0x80,0x70,0x00, - - 5, // 0x64 'd' - 0x00,0x10,0x10,0x70,0x90,0x70,0x00, - - 5, // 0x65 'e' - 0x00,0x00,0x60,0xf0,0x80,0x70,0x00, - - 5, // 0x66 'f' - 0x00,0x30,0x40,0xe0,0x40,0x40,0x00, - - 5, // 0x67 'g' - 0x00,0x00,0x70,0x90,0x70,0x10,0x60, - - 5, // 0x68 'h' - 0x00,0x80,0x80,0xe0,0x90,0x90,0x00, - - 5, // 0x69 'i' - 0x20,0x00,0x60,0x20,0x20,0x70,0x00, - - 5, // 0x6a 'j' - 0x20,0x00,0x60,0x20,0x20,0xa0,0x40, - - 5, // 0x6b 'k' - 0x80,0x80,0x90,0xa0,0xe0,0x90,0x00, - - 5, // 0x6c 'l' - 0x00,0x60,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x6d 'm' - 0x00,0x00,0xa0,0xf0,0xf0,0x90,0x00, - - 5, // 0x6e 'n' - 0x00,0x00,0xa0,0xd0,0x90,0x90,0x00, - - 5, // 0x6f 'o' - 0x00,0x00,0x60,0x90,0x90,0x60,0x00, - - 5, // 0x70 'p' - 0x00,0x00,0xe0,0x90,0xe0,0x80,0x80, - - 5, // 0x71 'q' - 0x00,0x00,0x70,0x90,0x70,0x10,0x10, - - 5, // 0x72 'r' - 0x00,0x00,0xe0,0x90,0x80,0x80,0x00, - - 5, // 0x73 's' - 0x00,0x00,0x70,0xe0,0x10,0xe0,0x00, - - 5, // 0x74 't' - 0x40,0x40,0xe0,0x40,0x40,0x70,0x00, - - 5, // 0x75 'u' - 0x00,0x00,0x90,0x90,0x90,0x70,0x00, - - 5, // 0x76 'v' - 0x00,0x00,0x50,0x50,0x50,0x20,0x00, - - 5, // 0x77 'w' - 0x00,0x00,0x90,0x90,0xf0,0x90,0x00, - - 5, // 0x78 'x' - 0x00,0x00,0x90,0x60,0x60,0x90,0x00, - - 5, // 0x79 'y' - 0x00,0x00,0x90,0x90,0x70,0x10,0x60, - - 5, // 0x7a 'z' - 0x00,0x00,0xf0,0x20,0x40,0xf0,0x00, - - 5, // 0x7b '{' - 0x10,0x20,0x20,0xc0,0x20,0x20,0x10, - - 5, // 0x7c '|' - 0x20,0x20,0x20,0x00,0x20,0x20,0x20, - - 5, // 0x7d '}' - 0x40,0x20,0x20,0x18,0x20,0x20,0x40, - - 5, // 0x7e '~' - 0x00,0x40,0xa8,0x10,0x00,0x00,0x00, - - 5, // 0x7f '' - 0x00,0x00,0x20,0x50,0x88,0xf8,0x00, - 0 - }; - - const int8u gse5x9[] = - { - 9, 0, 32, 128-32, - - 0x00,0x00,0x0a,0x00,0x14,0x00,0x1e,0x00,0x28,0x00,0x32,0x00,0x3c,0x00,0x46,0x00,0x50,0x00, - 0x5a,0x00,0x64,0x00,0x6e,0x00,0x78,0x00,0x82,0x00,0x8c,0x00,0x96,0x00,0xa0,0x00,0xaa,0x00, - 0xb4,0x00,0xbe,0x00,0xc8,0x00,0xd2,0x00,0xdc,0x00,0xe6,0x00,0xf0,0x00,0xfa,0x00,0x04,0x01, - 0x0e,0x01,0x18,0x01,0x22,0x01,0x2c,0x01,0x36,0x01,0x40,0x01,0x4a,0x01,0x54,0x01,0x5e,0x01, - 0x68,0x01,0x72,0x01,0x7c,0x01,0x86,0x01,0x90,0x01,0x9a,0x01,0xa4,0x01,0xae,0x01,0xb8,0x01, - 0xc2,0x01,0xcc,0x01,0xd6,0x01,0xe0,0x01,0xea,0x01,0xf4,0x01,0xfe,0x01,0x08,0x02,0x12,0x02, - 0x1c,0x02,0x26,0x02,0x30,0x02,0x3a,0x02,0x44,0x02,0x4e,0x02,0x58,0x02,0x62,0x02,0x6c,0x02, - 0x76,0x02,0x80,0x02,0x8a,0x02,0x94,0x02,0x9e,0x02,0xa8,0x02,0xb2,0x02,0xbc,0x02,0xc6,0x02, - 0xd0,0x02,0xda,0x02,0xe4,0x02,0xee,0x02,0xf8,0x02,0x02,0x03,0x0c,0x03,0x16,0x03,0x20,0x03, - 0x2a,0x03,0x34,0x03,0x3e,0x03,0x48,0x03,0x52,0x03,0x5c,0x03,0x66,0x03,0x70,0x03,0x7a,0x03, - 0x84,0x03,0x8e,0x03,0x98,0x03,0xa2,0x03,0xac,0x03,0xb6,0x03, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00, - - 5, // 0x22 '"' - 0x00,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x23 '#' - 0x00,0x50,0x50,0xf8,0x50,0xf8,0x50,0x50,0x00, - - 5, // 0x24 '$' - 0x00,0x20,0x78,0xa0,0x70,0x28,0xf0,0x20,0x00, - - 5, // 0x25 '%' - 0x00,0xc8,0xc8,0x10,0x20,0x40,0x98,0x98,0x00, - - 5, // 0x26 '&' - 0x00,0x40,0xa0,0xa0,0x40,0xa8,0x90,0x68,0x00, - - 5, // 0x27 ''' - 0x00,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x10,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x10, - - 5, // 0x29 ')' - 0x80,0x40,0x20,0x20,0x20,0x20,0x20,0x40,0x80, - - 5, // 0x2a '*' - 0x00,0x00,0x20,0xa8,0x70,0xa8,0x20,0x00,0x00, - - 5, // 0x2b '+' - 0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00, - - 5, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x40, - - 5, // 0x2d '-' - 0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00, - - 5, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, - - 5, // 0x2f '/' - 0x00,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80, - - 5, // 0x30 '0' - 0x00,0x60,0x90,0xb0,0xd0,0x90,0x90,0x60,0x00, - - 5, // 0x31 '1' - 0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x32 '2' - 0x00,0x60,0x90,0x10,0x20,0x40,0x80,0xf0,0x00, - - 5, // 0x33 '3' - 0x00,0xf0,0x10,0x20,0x60,0x10,0x90,0x60,0x00, - - 5, // 0x34 '4' - 0x00,0x30,0x50,0x90,0x90,0xf8,0x10,0x10,0x00, - - 5, // 0x35 '5' - 0x00,0xf0,0x80,0xe0,0x10,0x10,0x10,0xe0,0x00, - - 5, // 0x36 '6' - 0x00,0x60,0x80,0xe0,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x37 '7' - 0x00,0xf0,0x90,0x10,0x20,0x40,0x40,0x40,0x00, - - 5, // 0x38 '8' - 0x00,0x60,0x90,0x90,0x60,0x90,0x90,0x60,0x00, - - 5, // 0x39 '9' - 0x00,0x60,0x90,0x90,0x70,0x10,0x90,0x60,0x00, - - 5, // 0x3a ':' - 0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00, - - 5, // 0x3b ';' - 0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x20,0x40, - - 5, // 0x3c '<' - 0x00,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00, - - 5, // 0x3d '=' - 0x00,0x00,0x00,0xf0,0x00,0xf0,0x00,0x00,0x00, - - 5, // 0x3e '>' - 0x00,0x80,0x40,0x20,0x10,0x20,0x40,0x80,0x00, - - 5, // 0x3f '?' - 0x00,0x60,0x90,0x10,0x20,0x20,0x00,0x20,0x00, - - 5, // 0x40 '@' - 0x00,0x60,0x90,0xb0,0xb0,0xb0,0x80,0x70,0x00, - - 5, // 0x41 'A' - 0x00,0x60,0x90,0x90,0xf0,0x90,0x90,0x90,0x00, - - 5, // 0x42 'B' - 0x00,0xe0,0x90,0x90,0xe0,0x90,0x90,0xe0,0x00, - - 5, // 0x43 'C' - 0x00,0x60,0x90,0x80,0x80,0x80,0x90,0x60,0x00, - - 5, // 0x44 'D' - 0x00,0xe0,0x90,0x90,0x90,0x90,0x90,0xe0,0x00, - - 5, // 0x45 'E' - 0x00,0xf0,0x80,0x80,0xe0,0x80,0x80,0xf0,0x00, - - 5, // 0x46 'F' - 0x00,0xf0,0x80,0x80,0xe0,0x80,0x80,0x80,0x00, - - 5, // 0x47 'G' - 0x00,0x60,0x90,0x80,0xb0,0x90,0x90,0x60,0x00, - - 5, // 0x48 'H' - 0x00,0x90,0x90,0x90,0xf0,0x90,0x90,0x90,0x00, - - 5, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x4a 'J' - 0x00,0x70,0x20,0x20,0x20,0x20,0xa0,0x40,0x00, - - 5, // 0x4b 'K' - 0x00,0x90,0x90,0xa0,0xc0,0xa0,0x90,0x90,0x00, - - 5, // 0x4c 'L' - 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xf0,0x00, - - 5, // 0x4d 'M' - 0x00,0x90,0xf0,0x90,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x4e 'N' - 0x00,0x90,0x90,0xd0,0xb0,0x90,0x90,0x90,0x00, - - 5, // 0x4f 'O' - 0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x50 'P' - 0x00,0xe0,0x90,0x90,0xe0,0x80,0x80,0x80,0x00, - - 5, // 0x51 'Q' - 0x00,0x60,0x90,0x90,0x90,0x90,0xa0,0x50,0x00, - - 5, // 0x52 'R' - 0x00,0xe0,0x90,0x90,0xe0,0xa0,0x90,0x90,0x00, - - 5, // 0x53 'S' - 0x00,0x60,0x90,0x80,0x60,0x10,0x90,0x60,0x00, - - 5, // 0x54 'T' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x00, - - 5, // 0x55 'U' - 0x00,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x56 'V' - 0x00,0x50,0x50,0x50,0x50,0x50,0x20,0x20,0x00, - - 5, // 0x57 'W' - 0x00,0x90,0x90,0x90,0x90,0x90,0xf0,0x90,0x00, - - 5, // 0x58 'X' - 0x00,0x90,0x90,0x60,0x60,0x90,0x90,0x90,0x00, - - 5, // 0x59 'Y' - 0x00,0x50,0x50,0x50,0x20,0x20,0x20,0x20,0x00, - - 5, // 0x5a 'Z' - 0x00,0xf0,0x10,0x10,0x20,0x40,0x80,0xf0,0x00, - - 5, // 0x5b '[' - 0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x70,0x00, - - 5, // 0x5c '\' - 0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x00, - - 5, // 0x5d ']' - 0xe0,0x20,0x20,0x20,0x20,0x20,0x20,0xe0,0x00, - - 5, // 0x5e '^' - 0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00, - - 5, // 0x60 '`' - 0x00,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x61 'a' - 0x00,0x00,0x60,0x10,0x70,0x90,0x90,0x70,0x00, - - 5, // 0x62 'b' - 0x00,0x80,0x80,0xe0,0x90,0x90,0x90,0xe0,0x00, - - 5, // 0x63 'c' - 0x00,0x00,0x60,0x90,0x80,0x80,0x90,0x60,0x00, - - 5, // 0x64 'd' - 0x00,0x10,0x10,0x70,0x90,0x90,0x90,0x70,0x00, - - 5, // 0x65 'e' - 0x00,0x00,0x60,0x90,0xf0,0x80,0x80,0x70,0x00, - - 5, // 0x66 'f' - 0x00,0x30,0x40,0x40,0xe0,0x40,0x40,0x40,0x00, - - 5, // 0x67 'g' - 0x00,0x00,0x70,0x90,0x90,0x70,0x10,0x90,0x60, - - 5, // 0x68 'h' - 0x00,0x80,0x80,0xe0,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x69 'i' - 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x6a 'j' - 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0xa0,0x40, - - 5, // 0x6b 'k' - 0x00,0x80,0x80,0x90,0xa0,0xc0,0xa0,0x90,0x00, - - 5, // 0x6c 'l' - 0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x6d 'm' - 0x00,0x00,0xa0,0xf0,0xf0,0xf0,0x90,0x90,0x00, - - 5, // 0x6e 'n' - 0x00,0x00,0xa0,0xd0,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x6f 'o' - 0x00,0x00,0x60,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x70 'p' - 0x00,0x00,0xe0,0x90,0x90,0x90,0xe0,0x80,0x80, - - 5, // 0x71 'q' - 0x00,0x00,0x70,0x90,0x90,0x90,0x70,0x10,0x10, - - 5, // 0x72 'r' - 0x00,0x00,0xe0,0x90,0x80,0x80,0x80,0x80,0x00, - - 5, // 0x73 's' - 0x00,0x00,0x60,0x90,0x40,0x20,0x90,0x60,0x00, - - 5, // 0x74 't' - 0x00,0x40,0x40,0xe0,0x40,0x40,0x50,0x20,0x00, - - 5, // 0x75 'u' - 0x00,0x00,0x90,0x90,0x90,0x90,0x90,0x70,0x00, - - 5, // 0x76 'v' - 0x00,0x00,0x50,0x50,0x50,0x50,0x20,0x20,0x00, - - 5, // 0x77 'w' - 0x00,0x00,0x90,0x90,0x90,0x90,0xf0,0x90,0x00, - - 5, // 0x78 'x' - 0x00,0x00,0x90,0x90,0x60,0x60,0x90,0x90,0x00, - - 5, // 0x79 'y' - 0x00,0x00,0x90,0x90,0x90,0x90,0x70,0x10,0xe0, - - 5, // 0x7a 'z' - 0x00,0x00,0xf0,0x10,0x20,0x40,0x80,0xf0,0x00, - - 5, // 0x7b '{' - 0x10,0x20,0x20,0x20,0xc0,0x20,0x20,0x20,0x10, - - 5, // 0x7c '|' - 0x00,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00, - - 5, // 0x7d '}' - 0x80,0x40,0x40,0x40,0x30,0x40,0x40,0x40,0x80, - - 5, // 0x7e '~' - 0x00,0x40,0xa8,0x10,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x7f '' - 0x00,0x00,0x00,0x20,0x50,0x88,0xf8,0x00,0x00, - 0 - }; - - const int8u gse6x12[] = - { - 12, 0, 32, 128-32, - - 0x00,0x00,0x0d,0x00,0x1a,0x00,0x27,0x00,0x34,0x00,0x41,0x00,0x4e,0x00,0x5b,0x00,0x68,0x00, - 0x75,0x00,0x82,0x00,0x8f,0x00,0x9c,0x00,0xa9,0x00,0xb6,0x00,0xc3,0x00,0xd0,0x00,0xdd,0x00, - 0xea,0x00,0xf7,0x00,0x04,0x01,0x11,0x01,0x1e,0x01,0x2b,0x01,0x38,0x01,0x45,0x01,0x52,0x01, - 0x5f,0x01,0x6c,0x01,0x79,0x01,0x86,0x01,0x93,0x01,0xa0,0x01,0xad,0x01,0xba,0x01,0xc7,0x01, - 0xd4,0x01,0xe1,0x01,0xee,0x01,0xfb,0x01,0x08,0x02,0x15,0x02,0x22,0x02,0x2f,0x02,0x3c,0x02, - 0x49,0x02,0x56,0x02,0x63,0x02,0x70,0x02,0x7d,0x02,0x8a,0x02,0x97,0x02,0xa4,0x02,0xb1,0x02, - 0xbe,0x02,0xcb,0x02,0xd8,0x02,0xe5,0x02,0xf2,0x02,0xff,0x02,0x0c,0x03,0x19,0x03,0x26,0x03, - 0x33,0x03,0x40,0x03,0x4d,0x03,0x5a,0x03,0x67,0x03,0x74,0x03,0x81,0x03,0x8e,0x03,0x9b,0x03, - 0xa8,0x03,0xb5,0x03,0xc2,0x03,0xcf,0x03,0xdc,0x03,0xe9,0x03,0xf6,0x03,0x03,0x04,0x10,0x04, - 0x1d,0x04,0x2a,0x04,0x37,0x04,0x44,0x04,0x51,0x04,0x5e,0x04,0x6b,0x04,0x78,0x04,0x85,0x04, - 0x92,0x04,0x9f,0x04,0xac,0x04,0xb9,0x04,0xc6,0x04,0xd3,0x04, - - 6, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, - - 6, // 0x22 '"' - 0x00,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x23 '#' - 0x00,0x50,0x50,0xf8,0x50,0x50,0x50,0xf8,0x50,0x50,0x00,0x00, - - 6, // 0x24 '$' - 0x00,0x20,0x70,0xa8,0xa0,0x70,0x28,0xa8,0x70,0x20,0x00,0x00, - - 6, // 0x25 '%' - 0x00,0xc8,0xd8,0x10,0x30,0x20,0x60,0x40,0xd8,0x98,0x00,0x00, - - 6, // 0x26 '&' - 0x00,0x60,0x90,0x90,0x90,0x60,0xa8,0x90,0x90,0x68,0x00,0x00, - - 6, // 0x27 ''' - 0x00,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x28 '(' - 0x00,0x10,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x10,0x00,0x00, - - 6, // 0x29 ')' - 0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x40,0x00,0x00, - - 6, // 0x2a '*' - 0x00,0x00,0x00,0x50,0x20,0xf8,0x20,0x50,0x00,0x00,0x00,0x00, - - 6, // 0x2b '+' - 0x00,0x00,0x20,0x20,0x20,0xf8,0x20,0x20,0x20,0x00,0x00,0x00, - - 6, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x40, - - 6, // 0x2d '-' - 0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00, - - 6, // 0x2f '/' - 0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x00,0x00, - - 6, // 0x30 '0' - 0x00,0x70,0x88,0x88,0x98,0xa8,0xc8,0x88,0x88,0x70,0x00,0x00, - - 6, // 0x31 '1' - 0x00,0x20,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 6, // 0x32 '2' - 0x00,0x70,0x88,0x88,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,0x00, - - 6, // 0x33 '3' - 0x00,0xf8,0x10,0x20,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00, - - 6, // 0x34 '4' - 0x00,0x10,0x20,0x40,0x90,0x90,0xf8,0x10,0x10,0x10,0x00,0x00, - - 6, // 0x35 '5' - 0x00,0xf8,0x80,0x80,0xf0,0x08,0x08,0x08,0x88,0x70,0x00,0x00, - - 6, // 0x36 '6' - 0x00,0x70,0x88,0x80,0x80,0xf0,0x88,0x88,0x88,0x70,0x00,0x00, - - 6, // 0x37 '7' - 0x00,0xf8,0x88,0x08,0x08,0x10,0x20,0x20,0x20,0x20,0x00,0x00, - - 6, // 0x38 '8' - 0x00,0x70,0x88,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00, - - 6, // 0x39 '9' - 0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x08,0x88,0x70,0x00,0x00, - - 6, // 0x3a ':' - 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00, - - 6, // 0x3b ';' - 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x20,0x20,0x40, - - 6, // 0x3c '<' - 0x00,0x08,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x08,0x00,0x00, - - 6, // 0x3d '=' - 0x00,0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x3e '>' - 0x00,0x80,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x80,0x00,0x00, - - 6, // 0x3f '?' - 0x00,0x70,0x88,0x88,0x08,0x10,0x20,0x20,0x00,0x20,0x00,0x00, - - 6, // 0x40 '@' - 0x00,0x70,0x88,0x88,0xb8,0xb8,0xb0,0x80,0x88,0x70,0x00,0x00, - - 6, // 0x41 'A' - 0x00,0x20,0x50,0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, - - 6, // 0x42 'B' - 0x00,0xf0,0x88,0x88,0x88,0xf0,0x88,0x88,0x88,0xf0,0x00,0x00, - - 6, // 0x43 'C' - 0x00,0x70,0x88,0x88,0x80,0x80,0x80,0x88,0x88,0x70,0x00,0x00, - - 6, // 0x44 'D' - 0x00,0xe0,0x90,0x88,0x88,0x88,0x88,0x88,0x90,0xe0,0x00,0x00, - - 6, // 0x45 'E' - 0x00,0xf8,0x80,0x80,0x80,0xf0,0x80,0x80,0x80,0xf8,0x00,0x00, - - 6, // 0x46 'F' - 0x00,0xf8,0x80,0x80,0x80,0xf0,0x80,0x80,0x80,0x80,0x00,0x00, - - 6, // 0x47 'G' - 0x00,0x70,0x88,0x80,0x80,0xb8,0x88,0x88,0x88,0x70,0x00,0x00, - - 6, // 0x48 'H' - 0x00,0x88,0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x88,0x00,0x00, - - 6, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 6, // 0x4a 'J' - 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0x60,0x00,0x00, - - 6, // 0x4b 'K' - 0x00,0x88,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x88,0x00,0x00, - - 6, // 0x4c 'L' - 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00,0x00, - - 6, // 0x4d 'M' - 0x00,0x88,0x88,0xd8,0xa8,0x88,0x88,0x88,0x88,0x88,0x00,0x00, - - 6, // 0x4e 'N' - 0x00,0x88,0x88,0xc8,0xa8,0x98,0x88,0x88,0x88,0x88,0x00,0x00, - - 6, // 0x4f 'O' - 0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, - - 6, // 0x50 'P' - 0x00,0xf0,0x88,0x88,0x88,0xf0,0x80,0x80,0x80,0x80,0x00,0x00, - - 6, // 0x51 'Q' - 0x00,0x70,0x88,0x88,0x88,0x88,0x88,0xa8,0x90,0x68,0x00,0x00, - - 6, // 0x52 'R' - 0x00,0xf0,0x88,0x88,0x88,0x88,0xf0,0xa0,0x90,0x88,0x00,0x00, - - 6, // 0x53 'S' - 0x00,0x70,0x88,0x80,0x80,0x70,0x08,0x08,0x88,0x70,0x00,0x00, - - 6, // 0x54 'T' - 0x00,0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, - - 6, // 0x55 'U' - 0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, - - 6, // 0x56 'V' - 0x00,0x88,0x88,0x88,0x88,0x88,0x50,0x50,0x20,0x20,0x00,0x00, - - 6, // 0x57 'W' - 0x00,0x88,0x88,0x88,0x88,0x88,0xa8,0xa8,0xd8,0x88,0x00,0x00, - - 6, // 0x58 'X' - 0x00,0x88,0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x88,0x00,0x00, - - 6, // 0x59 'Y' - 0x00,0x88,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x20,0x00,0x00, - - 6, // 0x5a 'Z' - 0x00,0xf8,0x08,0x08,0x10,0x20,0x40,0x80,0x80,0xf8,0x00,0x00, - - 6, // 0x5b '[' - 0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70,0x00, - - 6, // 0x5c '\' - 0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x00,0x00, - - 6, // 0x5d ']' - 0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, - - 6, // 0x5e '^' - 0x00,0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00, - - 6, // 0x60 '`' - 0x00,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x61 'a' - 0x00,0x00,0x00,0x70,0x88,0x08,0x78,0x88,0x88,0x78,0x00,0x00, - - 6, // 0x62 'b' - 0x00,0x80,0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0xf0,0x00,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00,0x00, - - 6, // 0x64 'd' - 0x00,0x08,0x08,0x08,0x78,0x88,0x88,0x88,0x88,0x78,0x00,0x00, - - 6, // 0x65 'e' - 0x00,0x00,0x00,0x70,0x88,0x88,0xf8,0x80,0x80,0x78,0x00,0x00, - - 6, // 0x66 'f' - 0x00,0x18,0x20,0x20,0xf8,0x20,0x20,0x20,0x20,0x20,0x00,0x00, - - 6, // 0x67 'g' - 0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x88,0x78,0x08,0x08,0xf0, - - 6, // 0x68 'h' - 0x00,0x80,0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x88,0x00,0x00, - - 6, // 0x69 'i' - 0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 6, // 0x6a 'j' - 0x00,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x90,0x60, - - 6, // 0x6b 'k' - 0x00,0x80,0x80,0x80,0x88,0x90,0xa0,0xd0,0x88,0x88,0x00,0x00, - - 6, // 0x6c 'l' - 0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 6, // 0x6d 'm' - 0x00,0x00,0x00,0xd0,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0x00,0x00, - - 6, // 0x6e 'n' - 0x00,0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x88,0x88,0x00,0x00, - - 6, // 0x6f 'o' - 0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, - - 6, // 0x70 'p' - 0x00,0x00,0x00,0xf0,0x88,0x88,0x88,0x88,0xf0,0x80,0x80,0x80, - - 6, // 0x71 'q' - 0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x88,0x78,0x08,0x08,0x08, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0xb0,0xc8,0x88,0x80,0x80,0x80,0x80,0x00,0x00, - - 6, // 0x73 's' - 0x00,0x00,0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,0x00, - - 6, // 0x74 't' - 0x00,0x40,0x40,0x40,0xe0,0x40,0x40,0x40,0x48,0x30,0x00,0x00, - - 6, // 0x75 'u' - 0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x78,0x00,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x50,0x20,0x20,0x00,0x00, - - 6, // 0x77 'w' - 0x00,0x00,0x00,0x88,0x88,0x88,0xa8,0xa8,0xd8,0x88,0x00,0x00, - - 6, // 0x78 'x' - 0x00,0x00,0x00,0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,0x00, - - 6, // 0x79 'y' - 0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x88,0x78,0x08,0x10,0xe0, - - 6, // 0x7a 'z' - 0x00,0x00,0x00,0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,0x00, - - 6, // 0x7b '{' - 0x18,0x20,0x20,0x20,0x20,0xc0,0x20,0x20,0x20,0x20,0x18,0x00, - - 6, // 0x7c '|' - 0x00,0x20,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x20,0x00,0x00, - - 6, // 0x7d '}' - 0xc0,0x20,0x20,0x20,0x20,0x18,0x20,0x20,0x20,0x20,0xc0,0x00, - - 6, // 0x7e '~' - 0x00,0x00,0x40,0xa8,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x7f '' - 0x00,0x00,0x00,0x00,0x20,0x50,0x88,0xf8,0x00,0x00,0x00,0x00, - 0 - }; - - const int8u gse6x9[] = - { - 9, 0, 32, 128-32, - - 0x00,0x00,0x0a,0x00,0x14,0x00,0x1e,0x00,0x28,0x00,0x32,0x00,0x3c,0x00,0x46,0x00,0x50,0x00, - 0x5a,0x00,0x64,0x00,0x6e,0x00,0x78,0x00,0x82,0x00,0x8c,0x00,0x96,0x00,0xa0,0x00,0xaa,0x00, - 0xb4,0x00,0xbe,0x00,0xc8,0x00,0xd2,0x00,0xdc,0x00,0xe6,0x00,0xf0,0x00,0xfa,0x00,0x04,0x01, - 0x0e,0x01,0x18,0x01,0x22,0x01,0x2c,0x01,0x36,0x01,0x40,0x01,0x4a,0x01,0x54,0x01,0x5e,0x01, - 0x68,0x01,0x72,0x01,0x7c,0x01,0x86,0x01,0x90,0x01,0x9a,0x01,0xa4,0x01,0xae,0x01,0xb8,0x01, - 0xc2,0x01,0xcc,0x01,0xd6,0x01,0xe0,0x01,0xea,0x01,0xf4,0x01,0xfe,0x01,0x08,0x02,0x12,0x02, - 0x1c,0x02,0x26,0x02,0x30,0x02,0x3a,0x02,0x44,0x02,0x4e,0x02,0x58,0x02,0x62,0x02,0x6c,0x02, - 0x76,0x02,0x80,0x02,0x8a,0x02,0x94,0x02,0x9e,0x02,0xa8,0x02,0xb2,0x02,0xbc,0x02,0xc6,0x02, - 0xd0,0x02,0xda,0x02,0xe4,0x02,0xee,0x02,0xf8,0x02,0x02,0x03,0x0c,0x03,0x16,0x03,0x20,0x03, - 0x2a,0x03,0x34,0x03,0x3e,0x03,0x48,0x03,0x52,0x03,0x5c,0x03,0x66,0x03,0x70,0x03,0x7a,0x03, - 0x84,0x03,0x8e,0x03,0x98,0x03,0xa2,0x03,0xac,0x03,0xb6,0x03, - - 6, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00, - - 6, // 0x22 '"' - 0x00,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x23 '#' - 0x00,0x50,0x50,0xf8,0x50,0xf8,0x50,0x50,0x00, - - 6, // 0x24 '$' - 0x00,0x70,0xa8,0xa0,0x70,0x28,0xa8,0x70,0x00, - - 6, // 0x25 '%' - 0x00,0xc8,0xc8,0x10,0x20,0x40,0x98,0x98,0x00, - - 6, // 0x26 '&' - 0x00,0x60,0x90,0x90,0x60,0xa8,0x90,0x68,0x00, - - 6, // 0x27 ''' - 0x00,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x28 '(' - 0x10,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x10, - - 6, // 0x29 ')' - 0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x40, - - 6, // 0x2a '*' - 0x00,0x00,0x20,0xa8,0x70,0xa8,0x20,0x00,0x00, - - 6, // 0x2b '+' - 0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00, - - 6, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x40, - - 6, // 0x2d '-' - 0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00, - - 6, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, - - 6, // 0x2f '/' - 0x00,0x08,0x08,0x10,0x20,0x40,0x80,0x80,0x00, - - 6, // 0x30 '0' - 0x00,0x70,0x88,0x98,0xa8,0xc8,0x88,0x70,0x00, - - 6, // 0x31 '1' - 0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00, - - 6, // 0x32 '2' - 0x00,0x70,0x88,0x08,0x10,0x20,0x40,0xf8,0x00, - - 6, // 0x33 '3' - 0x00,0xf8,0x10,0x20,0x70,0x08,0x88,0x70,0x00, - - 6, // 0x34 '4' - 0x00,0x10,0x20,0x40,0x90,0xf8,0x10,0x10,0x00, - - 6, // 0x35 '5' - 0x00,0xf8,0x80,0xf0,0x08,0x08,0x88,0x70,0x00, - - 6, // 0x36 '6' - 0x00,0x70,0x88,0x80,0xf0,0x88,0x88,0x70,0x00, - - 6, // 0x37 '7' - 0x00,0xf8,0x08,0x08,0x10,0x20,0x40,0x40,0x00, - - 6, // 0x38 '8' - 0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00, - - 6, // 0x39 '9' - 0x00,0x70,0x88,0x88,0x78,0x08,0x88,0x70,0x00, - - 6, // 0x3a ':' - 0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00, - - 6, // 0x3b ';' - 0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x20,0x40, - - 6, // 0x3c '<' - 0x00,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00, - - 6, // 0x3d '=' - 0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00, - - 6, // 0x3e '>' - 0x00,0x80,0x40,0x20,0x10,0x20,0x40,0x80,0x00, - - 6, // 0x3f '?' - 0x00,0x70,0x88,0x08,0x10,0x20,0x00,0x20,0x00, - - 6, // 0x40 '@' - 0x00,0x70,0x88,0x88,0xb8,0xb8,0x80,0x70,0x00, - - 6, // 0x41 'A' - 0x00,0x20,0x50,0x88,0x88,0xf8,0x88,0x88,0x00, - - 6, // 0x42 'B' - 0x00,0xf0,0x88,0x88,0xf0,0x88,0x88,0xf0,0x00, - - 6, // 0x43 'C' - 0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00, - - 6, // 0x44 'D' - 0x00,0xe0,0x90,0x88,0x88,0x88,0x90,0xe0,0x00, - - 6, // 0x45 'E' - 0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00, - - 6, // 0x46 'F' - 0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00, - - 6, // 0x47 'G' - 0x00,0x70,0x88,0x80,0xb8,0x88,0x88,0x70,0x00, - - 6, // 0x48 'H' - 0x00,0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00, - - 6, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00, - - 6, // 0x4a 'J' - 0x00,0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00, - - 6, // 0x4b 'K' - 0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00, - - 6, // 0x4c 'L' - 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00, - - 6, // 0x4d 'M' - 0x00,0x88,0xd8,0xa8,0x88,0x88,0x88,0x88,0x00, - - 6, // 0x4e 'N' - 0x00,0x88,0x88,0xc8,0xa8,0x98,0x88,0x88,0x00, - - 6, // 0x4f 'O' - 0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, - - 6, // 0x50 'P' - 0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00, - - 6, // 0x51 'Q' - 0x00,0x70,0x88,0x88,0x88,0xa8,0x90,0x68,0x00, - - 6, // 0x52 'R' - 0x00,0xf0,0x88,0x88,0x88,0xf0,0x90,0x88,0x00, - - 6, // 0x53 'S' - 0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00, - - 6, // 0x54 'T' - 0x00,0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00, - - 6, // 0x55 'U' - 0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00, - - 6, // 0x56 'V' - 0x00,0x88,0x88,0x88,0x50,0x50,0x20,0x20,0x00, - - 6, // 0x57 'W' - 0x00,0x88,0x88,0x88,0xa8,0xa8,0xd8,0x88,0x00, - - 6, // 0x58 'X' - 0x00,0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00, - - 6, // 0x59 'Y' - 0x00,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00, - - 6, // 0x5a 'Z' - 0x00,0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00, - - 6, // 0x5b '[' - 0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70, - - 6, // 0x5c '\' - 0x00,0x80,0x80,0x40,0x20,0x10,0x08,0x08,0x00, - - 6, // 0x5d ']' - 0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70, - - 6, // 0x5e '^' - 0x00,0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00, - - 6, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00, - - 6, // 0x60 '`' - 0x00,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x61 'a' - 0x00,0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00, - - 6, // 0x62 'b' - 0x00,0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00, - - 6, // 0x64 'd' - 0x00,0x08,0x08,0x78,0x88,0x88,0x88,0x78,0x00, - - 6, // 0x65 'e' - 0x00,0x00,0x00,0x70,0x88,0xf8,0x80,0x78,0x00, - - 6, // 0x66 'f' - 0x00,0x18,0x20,0x20,0xf8,0x20,0x20,0x20,0x00, - - 6, // 0x67 'g' - 0x00,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x70, - - 6, // 0x68 'h' - 0x00,0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x00, - - 6, // 0x69 'i' - 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00, - - 6, // 0x6a 'j' - 0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x90,0x60, - - 6, // 0x6b 'k' - 0x00,0x00,0x80,0x88,0x90,0xa0,0xd0,0x88,0x00, - - 6, // 0x6c 'l' - 0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00, - - 6, // 0x6d 'm' - 0x00,0x00,0x00,0xd0,0xa8,0xa8,0xa8,0xa8,0x00, - - 6, // 0x6e 'n' - 0x00,0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00, - - 6, // 0x6f 'o' - 0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, - - 6, // 0x70 'p' - 0x00,0x00,0x00,0xf0,0x88,0x88,0xf0,0x80,0x80, - - 6, // 0x71 'q' - 0x00,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x08, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0xb8,0xc0,0x80,0x80,0x80,0x00, - - 6, // 0x73 's' - 0x00,0x00,0x00,0x78,0x80,0x70,0x08,0xf0,0x00, - - 6, // 0x74 't' - 0x00,0x40,0x40,0xe0,0x40,0x40,0x48,0x30,0x00, - - 6, // 0x75 'u' - 0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x78,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00, - - 6, // 0x77 'w' - 0x00,0x00,0x00,0x88,0x88,0xa8,0xd8,0x88,0x00, - - 6, // 0x78 'x' - 0x00,0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00, - - 6, // 0x79 'y' - 0x00,0x00,0x00,0x88,0x88,0x88,0x78,0x08,0x70, - - 6, // 0x7a 'z' - 0x00,0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00, - - 6, // 0x7b '{' - 0x18,0x20,0x20,0x20,0xc0,0x20,0x20,0x20,0x18, - - 6, // 0x7c '|' - 0x00,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00, - - 6, // 0x7d '}' - 0xc0,0x20,0x20,0x20,0x18,0x20,0x20,0x20,0xc0, - - 6, // 0x7e '~' - 0x00,0x40,0xa8,0x10,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x7f '' - 0x00,0x00,0x00,0x20,0x50,0x88,0xf8,0x00,0x00, - 0 - }; - - const int8u gse7x11[] = - { - 11, 0, 32, 128-32, - - 0x00,0x00,0x0c,0x00,0x18,0x00,0x24,0x00,0x30,0x00,0x3c,0x00,0x48,0x00,0x54,0x00,0x60,0x00, - 0x6c,0x00,0x78,0x00,0x84,0x00,0x90,0x00,0x9c,0x00,0xa8,0x00,0xb4,0x00,0xc0,0x00,0xcc,0x00, - 0xd8,0x00,0xe4,0x00,0xf0,0x00,0xfc,0x00,0x08,0x01,0x14,0x01,0x20,0x01,0x2c,0x01,0x38,0x01, - 0x44,0x01,0x50,0x01,0x5c,0x01,0x68,0x01,0x74,0x01,0x80,0x01,0x8c,0x01,0x98,0x01,0xa4,0x01, - 0xb0,0x01,0xbc,0x01,0xc8,0x01,0xd4,0x01,0xe0,0x01,0xec,0x01,0xf8,0x01,0x04,0x02,0x10,0x02, - 0x1c,0x02,0x28,0x02,0x34,0x02,0x40,0x02,0x4c,0x02,0x58,0x02,0x64,0x02,0x70,0x02,0x7c,0x02, - 0x88,0x02,0x94,0x02,0xa0,0x02,0xac,0x02,0xb8,0x02,0xc4,0x02,0xd0,0x02,0xdc,0x02,0xe8,0x02, - 0xf4,0x02,0x00,0x03,0x0c,0x03,0x18,0x03,0x24,0x03,0x30,0x03,0x3c,0x03,0x48,0x03,0x54,0x03, - 0x60,0x03,0x6c,0x03,0x78,0x03,0x84,0x03,0x90,0x03,0x9c,0x03,0xa8,0x03,0xb4,0x03,0xc0,0x03, - 0xcc,0x03,0xd8,0x03,0xe4,0x03,0xf0,0x03,0xfc,0x03,0x08,0x04,0x14,0x04,0x20,0x04,0x2c,0x04, - 0x38,0x04,0x44,0x04,0x50,0x04,0x5c,0x04,0x68,0x04,0x74,0x04, - - 7, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x21 '!' - 0x00,0x10,0x38,0x38,0x38,0x10,0x10,0x00,0x10,0x00,0x00, - - 7, // 0x22 '"' - 0x00,0x00,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x23 '#' - 0x00,0x48,0x48,0xfc,0x48,0x48,0xfc,0x48,0x48,0x00,0x00, - - 7, // 0x24 '$' - 0x00,0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x10,0x00, - - 7, // 0x25 '%' - 0x00,0x00,0x42,0xa4,0x48,0x10,0x24,0x4a,0x84,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x30,0x48,0x48,0x30,0x60,0x94,0x98,0x6c,0x00,0x00, - - 7, // 0x27 ''' - 0x00,0x20,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x08,0x04,0x00,0x00, - - 7, // 0x29 ')' - 0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x20,0x40,0x00,0x00, - - 7, // 0x2a '*' - 0x00,0x00,0x00,0x20,0xa8,0x70,0xa8,0x20,0x00,0x00,0x00, - - 7, // 0x2b '+' - 0x00,0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x60, - - 7, // 0x2d '-' - 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00, - - 7, // 0x2f '/' - 0x00,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,0x00, - - 7, // 0x30 '0' - 0x00,0x38,0x44,0x4c,0x54,0x64,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x31 '1' - 0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x38,0x44,0x04,0x08,0x10,0x20,0x44,0x7c,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x7c,0x48,0x10,0x38,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x34 '4' - 0x00,0x08,0x10,0x20,0x48,0x48,0x7c,0x08,0x1c,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x7c,0x40,0x40,0x78,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x18,0x20,0x40,0x78,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x37 '7' - 0x00,0x7c,0x44,0x04,0x08,0x10,0x10,0x10,0x10,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x38,0x44,0x44,0x38,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x38,0x44,0x44,0x44,0x3c,0x04,0x08,0x30,0x00,0x00, - - 7, // 0x3a ':' - 0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00, - - 7, // 0x3b ';' - 0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x30,0x60,0x00, - - 7, // 0x3c '<' - 0x00,0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00,0x00, - - 7, // 0x3d '=' - 0x00,0x00,0x00,0x00,0xfc,0x00,0xfc,0x00,0x00,0x00,0x00, - - 7, // 0x3e '>' - 0x00,0x00,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x00, - - 7, // 0x3f '?' - 0x00,0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00, - - 7, // 0x40 '@' - 0x00,0x30,0x48,0x04,0x34,0x54,0x54,0x54,0x28,0x00,0x00, - - 7, // 0x41 'A' - 0x00,0x10,0x28,0x44,0x44,0x7c,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x78,0x44,0x44,0x78,0x44,0x44,0x44,0x78,0x00,0x00, - - 7, // 0x43 'C' - 0x00,0x38,0x44,0x40,0x40,0x40,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x48,0x70,0x00,0x00, - - 7, // 0x45 'E' - 0x00,0x7c,0x40,0x40,0x70,0x40,0x40,0x40,0x7c,0x00,0x00, - - 7, // 0x46 'F' - 0x00,0x7c,0x40,0x40,0x70,0x40,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x38,0x44,0x40,0x40,0x5c,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x49 'I' - 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x4a 'J' - 0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x48,0x30,0x00,0x00, - - 7, // 0x4b 'K' - 0x00,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x44,0x00,0x00, - - 7, // 0x4c 'L' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7c,0x00,0x00, - - 7, // 0x4d 'M' - 0x00,0x44,0x6c,0x54,0x54,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x4e 'N' - 0x00,0x44,0x44,0x64,0x54,0x4c,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x4f 'O' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x51 'Q' - 0x00,0x38,0x44,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00, - - 7, // 0x52 'R' - 0x00,0x78,0x44,0x44,0x44,0x78,0x50,0x48,0x44,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0x7c,0x54,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x56 'V' - 0x00,0x44,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00, - - 7, // 0x57 'W' - 0x00,0x44,0x44,0x44,0x44,0x54,0x54,0x6c,0x44,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x5a 'Z' - 0x00,0x7c,0x04,0x08,0x10,0x20,0x40,0x44,0x7c,0x00,0x00, - - 7, // 0x5b '[' - 0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00,0x00, - - 7, // 0x5c '\' - 0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x00,0x00, - - 7, // 0x5d ']' - 0x00,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x38,0x00,0x00, - - 7, // 0x5e '^' - 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, - - 7, // 0x60 '`' - 0x00,0x20,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x38,0x04,0x3c,0x44,0x44,0x3c,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x78,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x04,0x04,0x3c,0x44,0x44,0x44,0x44,0x3c,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x38,0x44,0x7c,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x66 'f' - 0x00,0x18,0x24,0x20,0x70,0x20,0x20,0x20,0x70,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x3c,0x44,0x44,0x44,0x3c,0x04,0x44,0x38, - - 7, // 0x68 'h' - 0x00,0x40,0x40,0x40,0x58,0x64,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x69 'i' - 0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x6a 'j' - 0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x48,0x30,0x00, - - 7, // 0x6b 'k' - 0x00,0x40,0x40,0x44,0x48,0x50,0x68,0x44,0x44,0x00,0x00, - - 7, // 0x6c 'l' - 0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x6d 'm' - 0x00,0x00,0x00,0xa8,0x54,0x54,0x54,0x54,0x54,0x00,0x00, - - 7, // 0x6e 'n' - 0x00,0x00,0x00,0xb8,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x6f 'o' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x3c,0x44,0x44,0x44,0x44,0x3c,0x04,0x04, - - 7, // 0x72 'r' - 0x00,0x00,0x00,0x58,0x64,0x44,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x3c,0x40,0x38,0x04,0x04,0x78,0x00,0x00, - - 7, // 0x74 't' - 0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x24,0x18,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x3a,0x00,0x00, - - 7, // 0x76 'v' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x28,0x10,0x00,0x00, - - 7, // 0x77 'w' - 0x00,0x00,0x00,0x44,0x44,0x54,0x54,0x6c,0x44,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x44,0x44,0x44,0x3c,0x04,0x08,0x30,0x00, - - 7, // 0x7a 'z' - 0x00,0x00,0x00,0x7c,0x08,0x10,0x20,0x44,0x7c,0x00,0x00, - - 7, // 0x7b '{' - 0x00,0x0c,0x10,0x10,0x10,0x60,0x10,0x10,0x0c,0x00,0x00, - - 7, // 0x7c '|' - 0x00,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x20,0x00,0x00, - - 7, // 0x7d '}' - 0x00,0x60,0x10,0x10,0x10,0x0c,0x10,0x10,0x60,0x00,0x00, - - 7, // 0x7e '~' - 0x00,0x00,0x64,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x7f '' - 0x00,0x00,0x00,0x10,0x28,0x44,0x44,0x7c,0x00,0x00,0x00, - 0 - }; - - const int8u gse7x11_bold[] = - { - 11, 0, 32, 128-32, - - 0x00,0x00,0x0c,0x00,0x18,0x00,0x24,0x00,0x30,0x00,0x3c,0x00,0x48,0x00,0x54,0x00,0x60,0x00, - 0x6c,0x00,0x78,0x00,0x84,0x00,0x90,0x00,0x9c,0x00,0xa8,0x00,0xb4,0x00,0xc0,0x00,0xcc,0x00, - 0xd8,0x00,0xe4,0x00,0xf0,0x00,0xfc,0x00,0x08,0x01,0x14,0x01,0x20,0x01,0x2c,0x01,0x38,0x01, - 0x44,0x01,0x50,0x01,0x5c,0x01,0x68,0x01,0x74,0x01,0x80,0x01,0x8c,0x01,0x98,0x01,0xa4,0x01, - 0xb0,0x01,0xbc,0x01,0xc8,0x01,0xd4,0x01,0xe0,0x01,0xec,0x01,0xf8,0x01,0x04,0x02,0x10,0x02, - 0x1c,0x02,0x28,0x02,0x34,0x02,0x40,0x02,0x4c,0x02,0x58,0x02,0x64,0x02,0x70,0x02,0x7c,0x02, - 0x88,0x02,0x94,0x02,0xa0,0x02,0xac,0x02,0xb8,0x02,0xc4,0x02,0xd0,0x02,0xdc,0x02,0xe8,0x02, - 0xf4,0x02,0x00,0x03,0x0c,0x03,0x18,0x03,0x24,0x03,0x30,0x03,0x3c,0x03,0x48,0x03,0x54,0x03, - 0x60,0x03,0x6c,0x03,0x78,0x03,0x84,0x03,0x90,0x03,0x9c,0x03,0xa8,0x03,0xb4,0x03,0xc0,0x03, - 0xcc,0x03,0xd8,0x03,0xe4,0x03,0xf0,0x03,0xfc,0x03,0x08,0x04,0x14,0x04,0x20,0x04,0x2c,0x04, - 0x38,0x04,0x44,0x04,0x50,0x04,0x5c,0x04,0x68,0x04,0x74,0x04, - - 7, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x21 '!' - 0x00,0x30,0x30,0x30,0x30,0x30,0x00,0x30,0x30,0x00,0x00, - - 7, // 0x22 '"' - 0x00,0x6c,0x6c,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x23 '#' - 0x00,0x48,0x48,0xfc,0x48,0x48,0xfc,0x48,0x48,0x00,0x00, - - 7, // 0x24 '$' - 0x30,0x30,0x78,0xcc,0xc0,0x78,0x0c,0xcc,0x78,0x30,0x30, - - 7, // 0x25 '%' - 0x00,0x00,0xc4,0x0c,0x18,0x30,0x60,0xc0,0x8c,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x30,0x58,0x58,0x30,0x74,0xdc,0xd8,0x6c,0x00,0x00, - - 7, // 0x27 ''' - 0x00,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x00,0x0c,0x18,0x30,0x30,0x30,0x30,0x18,0x0c,0x00,0x00, - - 7, // 0x29 ')' - 0x00,0xc0,0x60,0x30,0x30,0x30,0x30,0x60,0xc0,0x00,0x00, - - 7, // 0x2a '*' - 0x00,0x00,0x00,0x20,0xa8,0x70,0xa8,0x20,0x00,0x00,0x00, - - 7, // 0x2b '+' - 0x00,0x00,0x00,0x30,0x30,0xfc,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00, - - 7, // 0x2d '-' - 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00, - - 7, // 0x2f '/' - 0x00,0x0c,0x0c,0x18,0x18,0x30,0x30,0x60,0x60,0x00,0x00, - - 7, // 0x30 '0' - 0x00,0x78,0xcc,0xcc,0xdc,0xec,0xcc,0xcc,0x78,0x00,0x00, - - 7, // 0x31 '1' - 0x00,0x30,0x70,0xf0,0x30,0x30,0x30,0x30,0xfc,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x78,0xcc,0xcc,0x18,0x30,0x60,0xcc,0xfc,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0xfc,0x98,0x30,0x78,0x0c,0x0c,0xcc,0x78,0x00,0x00, - - 7, // 0x34 '4' - 0x00,0x18,0x30,0x68,0xd8,0xd8,0xfc,0x18,0x3c,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0xfc,0xc0,0xc0,0xf8,0x0c,0x0c,0xcc,0x78,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x38,0x60,0xc0,0xf8,0xcc,0xcc,0xcc,0x78,0x00,0x00, - - 7, // 0x37 '7' - 0x00,0xfc,0x8c,0x0c,0x18,0x30,0x30,0x30,0x30,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x78,0xcc,0xcc,0x78,0xcc,0xcc,0xcc,0x78,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x78,0xcc,0xcc,0xcc,0x7c,0x0c,0x18,0x70,0x00,0x00, - - 7, // 0x3a ':' - 0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x3b ';' - 0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x30,0x60,0x00, - - 7, // 0x3c '<' - 0x00,0x00,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x00,0x00, - - 7, // 0x3d '=' - 0x00,0x00,0x00,0x00,0xfc,0x00,0xfc,0x00,0x00,0x00,0x00, - - 7, // 0x3e '>' - 0x00,0x00,0x60,0x30,0x18,0x0c,0x18,0x30,0x60,0x00,0x00, - - 7, // 0x3f '?' - 0x00,0x78,0xcc,0xcc,0x18,0x30,0x30,0x00,0x30,0x00,0x00, - - 7, // 0x40 '@' - 0x00,0x70,0x88,0x04,0x74,0xb4,0xb4,0xb4,0x68,0x00,0x00, - - 7, // 0x41 'A' - 0x00,0x30,0x78,0xcc,0xcc,0xfc,0xcc,0xcc,0xcc,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0xf8,0xcc,0xcc,0xf8,0xcc,0xcc,0xcc,0xf8,0x00,0x00, - - 7, // 0x43 'C' - 0x00,0x78,0xcc,0xc0,0xc0,0xc0,0xc0,0xcc,0x78,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0xf0,0xd8,0xcc,0xcc,0xcc,0xcc,0xd8,0xf0,0x00,0x00, - - 7, // 0x45 'E' - 0x00,0xfc,0xc4,0xd0,0xf0,0xd0,0xc0,0xc4,0xfc,0x00,0x00, - - 7, // 0x46 'F' - 0x00,0xfc,0xc4,0xd0,0xf0,0xd0,0xc0,0xc0,0xc0,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x78,0xcc,0xc0,0xc0,0xdc,0xcc,0xcc,0x78,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0xcc,0xcc,0xcc,0xfc,0xcc,0xcc,0xcc,0xcc,0x00,0x00, - - 7, // 0x49 'I' - 0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00, - - 7, // 0x4a 'J' - 0x00,0x3c,0x18,0x18,0x18,0x18,0xd8,0xd8,0x70,0x00,0x00, - - 7, // 0x4b 'K' - 0x00,0xcc,0xcc,0xd8,0xf0,0xd8,0xcc,0xcc,0xcc,0x00,0x00, - - 7, // 0x4c 'L' - 0x00,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc4,0xfc,0x00,0x00, - - 7, // 0x4d 'M' - 0x00,0x84,0xcc,0xfc,0xb4,0xcc,0xcc,0xcc,0xcc,0x00,0x00, - - 7, // 0x4e 'N' - 0x00,0xcc,0xcc,0xec,0xfc,0xdc,0xcc,0xcc,0xcc,0x00,0x00, - - 7, // 0x4f 'O' - 0x00,0x78,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0xf8,0xcc,0xcc,0xcc,0xf8,0xc0,0xc0,0xc0,0x00,0x00, - - 7, // 0x51 'Q' - 0x00,0x78,0xcc,0xcc,0xcc,0xcc,0xdc,0x78,0x18,0x0c,0x00, - - 7, // 0x52 'R' - 0x00,0xf8,0xcc,0xcc,0xcc,0xf8,0xd8,0xcc,0xcc,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x78,0xcc,0xe0,0x70,0x38,0x1c,0xcc,0x78,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0xfc,0xb4,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00, - - 7, // 0x56 'V' - 0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x30,0x00,0x00, - - 7, // 0x57 'W' - 0x00,0xcc,0xcc,0xcc,0xcc,0xb4,0xfc,0xcc,0x84,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0xcc,0xcc,0x78,0x30,0x78,0xcc,0xcc,0xcc,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0xcc,0xcc,0xcc,0x78,0x30,0x30,0x30,0x78,0x00,0x00, - - 7, // 0x5a 'Z' - 0x00,0xfc,0x8c,0x18,0x30,0x60,0xc0,0xc4,0xfc,0x00,0x00, - - 7, // 0x5b '[' - 0x00,0x78,0x60,0x60,0x60,0x60,0x60,0x60,0x78,0x00,0x00, - - 7, // 0x5c '\' - 0x00,0x60,0x60,0x30,0x30,0x18,0x18,0x0c,0x0c,0x00,0x00, - - 7, // 0x5d ']' - 0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x00,0x00, - - 7, // 0x5e '^' - 0x00,0x10,0x38,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, - - 7, // 0x60 '`' - 0x00,0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x70,0x18,0x78,0xd8,0xd8,0x6c,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x60,0x60,0x60,0x78,0x6c,0x6c,0x6c,0x78,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x78,0xcc,0xc0,0xc0,0xcc,0x78,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x18,0x18,0x18,0x78,0xd8,0xd8,0xd8,0x6c,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x78,0xcc,0xfc,0xc0,0xcc,0x78,0x00,0x00, - - 7, // 0x66 'f' - 0x00,0x18,0x34,0x30,0x78,0x30,0x30,0x30,0x78,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x6c,0xd8,0xd8,0xd8,0x78,0x18,0xd8,0x70, - - 7, // 0x68 'h' - 0x00,0xc0,0xc0,0xd8,0xec,0xcc,0xcc,0xcc,0xcc,0x00,0x00, - - 7, // 0x69 'i' - 0x00,0x30,0x00,0x70,0x30,0x30,0x30,0x30,0x78,0x00,0x00, - - 7, // 0x6a 'j' - 0x00,0x0c,0x00,0x1c,0x0c,0x0c,0x0c,0x0c,0x6c,0x6c,0x38, - - 7, // 0x6b 'k' - 0x00,0xc0,0xc0,0xcc,0xcc,0xd8,0xf0,0xd8,0xcc,0x00,0x00, - - 7, // 0x6c 'l' - 0x00,0x70,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00, - - 7, // 0x6d 'm' - 0x00,0x00,0x00,0xe8,0xfc,0xd4,0xd4,0xc4,0xc4,0x00,0x00, - - 7, // 0x6e 'n' - 0x00,0x00,0x00,0xd8,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00, - - 7, // 0x6f 'o' - 0x00,0x00,0x00,0x78,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0xf8,0xcc,0xcc,0xcc,0xf8,0xc0,0xc0,0xc0, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x7c,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x0c, - - 7, // 0x72 'r' - 0x00,0x00,0x00,0xd8,0xec,0xcc,0xc0,0xc0,0xc0,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x78,0xcc,0x60,0x18,0xcc,0x78,0x00,0x00, - - 7, // 0x74 't' - 0x00,0x20,0x60,0x60,0xf0,0x60,0x60,0x68,0x30,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0xd8,0xd8,0xd8,0xd8,0xd8,0x6c,0x00,0x00, - - 7, // 0x76 'v' - 0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0x78,0x30,0x00,0x00, - - 7, // 0x77 'w' - 0x00,0x00,0x00,0xcc,0xcc,0xb4,0xfc,0xcc,0x84,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0xcc,0x78,0x30,0x78,0xcc,0xcc,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x18,0xf0, - - 7, // 0x7a 'z' - 0x00,0x00,0x00,0xfc,0x98,0x30,0x60,0xc4,0xfc,0x00,0x00, - - 7, // 0x7b '{' - 0x1c,0x30,0x30,0x30,0xe0,0x30,0x30,0x30,0x1c,0x00,0x00, - - 7, // 0x7c '|' - 0x30,0x30,0x30,0x30,0x00,0x30,0x30,0x30,0x30,0x00,0x00, - - 7, // 0x7d '}' - 0xe0,0x30,0x30,0x30,0x1c,0x30,0x30,0x30,0xe0,0x00,0x00, - - 7, // 0x7e '~' - 0x00,0x34,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x7f '' - 0x00,0x00,0x00,0x30,0x78,0xcc,0xcc,0xfc,0x00,0x00,0x00, - 0 - }; - - const int8u gse7x15[] = - { - 15, 0, 32, 128-32, - - 0x00,0x00,0x10,0x00,0x20,0x00,0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,0x70,0x00,0x80,0x00, - 0x90,0x00,0xa0,0x00,0xb0,0x00,0xc0,0x00,0xd0,0x00,0xe0,0x00,0xf0,0x00,0x00,0x01,0x10,0x01, - 0x20,0x01,0x30,0x01,0x40,0x01,0x50,0x01,0x60,0x01,0x70,0x01,0x80,0x01,0x90,0x01,0xa0,0x01, - 0xb0,0x01,0xc0,0x01,0xd0,0x01,0xe0,0x01,0xf0,0x01,0x00,0x02,0x10,0x02,0x20,0x02,0x30,0x02, - 0x40,0x02,0x50,0x02,0x60,0x02,0x70,0x02,0x80,0x02,0x90,0x02,0xa0,0x02,0xb0,0x02,0xc0,0x02, - 0xd0,0x02,0xe0,0x02,0xf0,0x02,0x00,0x03,0x10,0x03,0x20,0x03,0x30,0x03,0x40,0x03,0x50,0x03, - 0x60,0x03,0x70,0x03,0x80,0x03,0x90,0x03,0xa0,0x03,0xb0,0x03,0xc0,0x03,0xd0,0x03,0xe0,0x03, - 0xf0,0x03,0x00,0x04,0x10,0x04,0x20,0x04,0x30,0x04,0x40,0x04,0x50,0x04,0x60,0x04,0x70,0x04, - 0x80,0x04,0x90,0x04,0xa0,0x04,0xb0,0x04,0xc0,0x04,0xd0,0x04,0xe0,0x04,0xf0,0x04,0x00,0x05, - 0x10,0x05,0x20,0x05,0x30,0x05,0x40,0x05,0x50,0x05,0x60,0x05,0x70,0x05,0x80,0x05,0x90,0x05, - 0xa0,0x05,0xb0,0x05,0xc0,0x05,0xd0,0x05,0xe0,0x05,0xf0,0x05, - - 7, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x21 '!' - 0x00,0x00,0x10,0x38,0x38,0x38,0x38,0x10,0x10,0x00,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x22 '"' - 0x00,0x00,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x23 '#' - 0x00,0x00,0x48,0x48,0x48,0xfc,0x48,0x48,0xfc,0x48,0x48,0x48,0x00,0x00,0x00, - - 7, // 0x24 '$' - 0x00,0x00,0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x54,0x38,0x10,0x00,0x00,0x00, - - 7, // 0x25 '%' - 0x00,0x00,0x44,0x44,0x08,0x08,0x10,0x10,0x20,0x20,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x00,0x00,0x30,0x48,0x48,0x30,0x60,0x94,0x98,0x90,0x6c,0x00,0x00,0x00, - - 7, // 0x27 ''' - 0x00,0x00,0x20,0x20,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x00,0x04,0x08,0x10,0x20,0x20,0x20,0x20,0x20,0x10,0x08,0x04,0x00,0x00,0x00, - - 7, // 0x29 ')' - 0x00,0x40,0x20,0x10,0x08,0x08,0x08,0x08,0x08,0x10,0x20,0x40,0x00,0x00,0x00, - - 7, // 0x2a '*' - 0x00,0x00,0x00,0x00,0x00,0x20,0xa8,0x70,0xa8,0x20,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2b '+' - 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x00,0x00,0x00,0x00, - - 7, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x60,0x00, - - 7, // 0x2d '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x2f '/' - 0x00,0x00,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x30 '0' - 0x00,0x00,0x38,0x44,0x44,0x4c,0x54,0x64,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x31 '1' - 0x00,0x00,0x10,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x00,0x38,0x44,0x44,0x04,0x08,0x10,0x20,0x40,0x44,0x7c,0x00,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x00,0x7c,0x44,0x08,0x10,0x38,0x04,0x04,0x04,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x34 '4' - 0x00,0x00,0x08,0x10,0x20,0x40,0x48,0x48,0x7c,0x08,0x08,0x1c,0x00,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x00,0x7c,0x40,0x40,0x40,0x78,0x04,0x04,0x04,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x00,0x18,0x20,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x37 '7' - 0x00,0x00,0x7c,0x44,0x04,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x00,0x38,0x44,0x44,0x44,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x3c,0x04,0x04,0x08,0x30,0x00,0x00,0x00, - - 7, // 0x3a ':' - 0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00, - - 7, // 0x3b ';' - 0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00, - - 7, // 0x3c '<' - 0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00,0x00, - - 7, // 0x3d '=' - 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x3e '>' - 0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x00, - - 7, // 0x3f '?' - 0x00,0x00,0x78,0x84,0x84,0x84,0x08,0x10,0x20,0x20,0x00,0x20,0x00,0x00,0x00, - - 7, // 0x40 '@' - 0x00,0x00,0x00,0x30,0x48,0x04,0x34,0x54,0x54,0x54,0x54,0x28,0x00,0x00,0x00, - - 7, // 0x41 'A' - 0x00,0x00,0x10,0x28,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x00,0x78,0x44,0x44,0x44,0x78,0x44,0x44,0x44,0x44,0x78,0x00,0x00,0x00, - - 7, // 0x43 'C' - 0x00,0x00,0x38,0x44,0x44,0x40,0x40,0x40,0x40,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x44,0x44,0x48,0x70,0x00,0x00,0x00, - - 7, // 0x45 'E' - 0x00,0x00,0x7c,0x40,0x40,0x40,0x70,0x40,0x40,0x40,0x40,0x7c,0x00,0x00,0x00, - - 7, // 0x46 'F' - 0x00,0x00,0x7c,0x40,0x40,0x40,0x70,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x5c,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0x00,0x44,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x49 'I' - 0x00,0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, - - 7, // 0x4a 'J' - 0x00,0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x48,0x30,0x00,0x00,0x00, - - 7, // 0x4b 'K' - 0x00,0x00,0x44,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x4c 'L' - 0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7c,0x00,0x00,0x00, - - 7, // 0x4d 'M' - 0x00,0x00,0x44,0x6c,0x54,0x54,0x44,0x44,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x4e 'N' - 0x00,0x00,0x44,0x44,0x44,0x64,0x54,0x4c,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x4f 'O' - 0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x51 'Q' - 0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00,0x00, - - 7, // 0x52 'R' - 0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x50,0x48,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x00,0x38,0x44,0x44,0x40,0x38,0x04,0x04,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0x00,0x7c,0x54,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x56 'V' - 0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x57 'W' - 0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x54,0x54,0x6c,0x44,0x00,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x00,0x44,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x00,0x44,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, - - 7, // 0x5a 'Z' - 0x00,0x00,0x7c,0x04,0x04,0x08,0x10,0x20,0x40,0x40,0x40,0x7c,0x00,0x00,0x00, - - 7, // 0x5b '[' - 0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00,0x00, - - 7, // 0x5c '\' - 0x00,0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x00,0x00,0x00, - - 7, // 0x5d ']' - 0x00,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x38,0x00,0x00, - - 7, // 0x5e '^' - 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, - - 7, // 0x60 '`' - 0x00,0x20,0x20,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x38,0x44,0x04,0x3c,0x44,0x44,0x44,0x3a,0x00,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x00,0x40,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x00,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x40,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x00,0x04,0x04,0x04,0x3c,0x44,0x44,0x44,0x44,0x44,0x3a,0x00,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x38,0x44,0x44,0x7c,0x40,0x40,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x66 'f' - 0x00,0x00,0x18,0x24,0x20,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x3a,0x44,0x44,0x44,0x44,0x44,0x3c,0x04,0x44,0x38,0x00, - - 7, // 0x68 'h' - 0x00,0x00,0x40,0x40,0x40,0x58,0x64,0x44,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x69 'i' - 0x00,0x00,0x10,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, - - 7, // 0x6a 'j' - 0x00,0x00,0x08,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x48,0x48,0x30,0x00, - - 7, // 0x6b 'k' - 0x00,0x00,0x40,0x40,0x44,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00,0x00, - - 7, // 0x6c 'l' - 0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, - - 7, // 0x6d 'm' - 0x00,0x00,0x00,0x00,0xa8,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x00,0x00,0x00, - - 7, // 0x6e 'n' - 0x00,0x00,0x00,0x00,0xb8,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x6f 'o' - 0x00,0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x00, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x3c,0x44,0x44,0x44,0x44,0x44,0x3c,0x04,0x04,0x04,0x00, - - 7, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x58,0x64,0x44,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x74 't' - 0x00,0x00,0x20,0x20,0x20,0x70,0x20,0x20,0x20,0x20,0x24,0x18,0x00,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x3a,0x00,0x00,0x00, - - 7, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x54,0x54,0x6c,0x44,0x00,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3c,0x04,0x08,0x70,0x00, - - 7, // 0x7a 'z' - 0x00,0x00,0x00,0x00,0x7c,0x04,0x08,0x10,0x20,0x40,0x40,0x7c,0x00,0x00,0x00, - - 7, // 0x7b '{' - 0x00,0x0c,0x10,0x10,0x10,0x10,0x10,0x60,0x10,0x10,0x10,0x10,0x0c,0x00,0x00, - - 7, // 0x7c '|' - 0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x00, - - 7, // 0x7d '}' - 0x00,0x60,0x10,0x10,0x10,0x10,0x10,0x0c,0x10,0x10,0x10,0x10,0x60,0x00,0x00, - - 7, // 0x7e '~' - 0x00,0x00,0x64,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x7f '' - 0x00,0x00,0x00,0x00,0x00,0x10,0x28,0x44,0x44,0x7c,0x00,0x00,0x00,0x00,0x00, - 0 - }; - - const int8u gse7x15_bold[] = - { - 15, 0, 32, 128-32, - - 0x00,0x00,0x10,0x00,0x20,0x00,0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,0x70,0x00,0x80,0x00, - 0x90,0x00,0xa0,0x00,0xb0,0x00,0xc0,0x00,0xd0,0x00,0xe0,0x00,0xf0,0x00,0x00,0x01,0x10,0x01, - 0x20,0x01,0x30,0x01,0x40,0x01,0x50,0x01,0x60,0x01,0x70,0x01,0x80,0x01,0x90,0x01,0xa0,0x01, - 0xb0,0x01,0xc0,0x01,0xd0,0x01,0xe0,0x01,0xf0,0x01,0x00,0x02,0x10,0x02,0x20,0x02,0x30,0x02, - 0x40,0x02,0x50,0x02,0x60,0x02,0x70,0x02,0x80,0x02,0x90,0x02,0xa0,0x02,0xb0,0x02,0xc0,0x02, - 0xd0,0x02,0xe0,0x02,0xf0,0x02,0x00,0x03,0x10,0x03,0x20,0x03,0x30,0x03,0x40,0x03,0x50,0x03, - 0x60,0x03,0x70,0x03,0x80,0x03,0x90,0x03,0xa0,0x03,0xb0,0x03,0xc0,0x03,0xd0,0x03,0xe0,0x03, - 0xf0,0x03,0x00,0x04,0x10,0x04,0x20,0x04,0x30,0x04,0x40,0x04,0x50,0x04,0x60,0x04,0x70,0x04, - 0x80,0x04,0x90,0x04,0xa0,0x04,0xb0,0x04,0xc0,0x04,0xd0,0x04,0xe0,0x04,0xf0,0x04,0x00,0x05, - 0x10,0x05,0x20,0x05,0x30,0x05,0x40,0x05,0x50,0x05,0x60,0x05,0x70,0x05,0x80,0x05,0x90,0x05, - 0xa0,0x05,0xb0,0x05,0xc0,0x05,0xd0,0x05,0xe0,0x05,0xf0,0x05, - - 7, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x21 '!' - 0x00,0x00,0x00,0x30,0x78,0x78,0x78,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x22 '"' - 0x00,0x00,0x6c,0x6c,0x6c,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x23 '#' - 0x00,0x00,0x48,0x48,0x48,0xfc,0x48,0x48,0xfc,0x48,0x48,0x48,0x00,0x00,0x00, - - 7, // 0x24 '$' - 0x00,0x30,0x30,0x78,0xcc,0xe0,0x70,0x38,0x1c,0xcc,0x78,0x30,0x30,0x00,0x00, - - 7, // 0x25 '%' - 0x00,0x00,0x00,0x64,0x6c,0x08,0x18,0x10,0x30,0x20,0x6c,0x4c,0x00,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x00,0x00,0x30,0x58,0x58,0x30,0x74,0xdc,0xd8,0xd8,0x6c,0x00,0x00,0x00, - - 7, // 0x27 ''' - 0x00,0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x00,0x0c,0x18,0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x18,0x0c,0x00,0x00,0x00, - - 7, // 0x29 ')' - 0x00,0xc0,0x60,0x30,0x18,0x18,0x18,0x18,0x18,0x30,0x60,0xc0,0x00,0x00,0x00, - - 7, // 0x2a '*' - 0x00,0x00,0x00,0x00,0x00,0x20,0xa8,0x70,0xa8,0x20,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2b '+' - 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0xfc,0x30,0x30,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x60,0x00, - - 7, // 0x2d '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x2f '/' - 0x00,0x00,0x0c,0x0c,0x18,0x18,0x30,0x30,0x60,0x60,0xc0,0xc0,0x00,0x00,0x00, - - 7, // 0x30 '0' - 0x00,0x00,0x78,0xcc,0xcc,0xcc,0xdc,0xec,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x31 '1' - 0x00,0x00,0x30,0x30,0x70,0xf0,0x30,0x30,0x30,0x30,0x30,0xfc,0x00,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x00,0x78,0xcc,0xcc,0x0c,0x18,0x30,0x60,0xc0,0xcc,0xfc,0x00,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x00,0xfc,0x8c,0x18,0x30,0x78,0x0c,0x0c,0x0c,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x34 '4' - 0x00,0x00,0x18,0x30,0x60,0xc8,0xd8,0xd8,0xfc,0x18,0x18,0x3c,0x00,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x00,0xfc,0xc0,0xc0,0xc0,0xf8,0x0c,0x0c,0x0c,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x00,0x38,0x60,0xc0,0xc0,0xf8,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x37 '7' - 0x00,0x00,0xfc,0x8c,0x0c,0x0c,0x18,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x00,0x78,0xcc,0xcc,0xcc,0x78,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x00,0x78,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x18,0x70,0x00,0x00,0x00, - - 7, // 0x3a ':' - 0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00, - - 7, // 0x3b ';' - 0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x60,0x00, - - 7, // 0x3c '<' - 0x00,0x00,0x00,0x0c,0x18,0x30,0x60,0xc0,0x60,0x30,0x18,0x0c,0x00,0x00,0x00, - - 7, // 0x3d '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x3e '>' - 0x00,0x00,0x00,0xc0,0x60,0x30,0x18,0x0c,0x18,0x30,0x60,0xc0,0x00,0x00,0x00, - - 7, // 0x3f '?' - 0x00,0x00,0x78,0xcc,0xcc,0x18,0x30,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x40 '@' - 0x00,0x00,0x00,0x70,0x88,0x04,0x74,0xb4,0xb4,0xb4,0xb4,0x68,0x00,0x00,0x00, - - 7, // 0x41 'A' - 0x00,0x00,0x30,0x78,0xcc,0xcc,0xcc,0xfc,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x00,0xf8,0xcc,0xcc,0xcc,0xf8,0xcc,0xcc,0xcc,0xcc,0xf8,0x00,0x00,0x00, - - 7, // 0x43 'C' - 0x00,0x00,0x78,0xcc,0xc4,0xc0,0xc0,0xc0,0xc0,0xc4,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0x00,0xf0,0xd8,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xd8,0xf0,0x00,0x00,0x00, - - 7, // 0x45 'E' - 0x00,0x00,0xfc,0xc4,0xc0,0xd0,0xf0,0xd0,0xc0,0xc0,0xc4,0xfc,0x00,0x00,0x00, - - 7, // 0x46 'F' - 0x00,0x00,0xfc,0xc4,0xc0,0xd0,0xf0,0xd0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x00,0x78,0xcc,0xc0,0xc0,0xc0,0xdc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xfc,0xcc,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x49 'I' - 0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00, - - 7, // 0x4a 'J' - 0x00,0x00,0x3c,0x18,0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0x70,0x00,0x00,0x00, - - 7, // 0x4b 'K' - 0x00,0x00,0xcc,0xcc,0xd8,0xd8,0xf0,0xd8,0xd8,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x4c 'L' - 0x00,0x00,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc4,0xfc,0x00,0x00,0x00, - - 7, // 0x4d 'M' - 0x00,0x00,0x84,0xcc,0xfc,0xb4,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x4e 'N' - 0x00,0x00,0xcc,0xcc,0xcc,0xec,0xfc,0xdc,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x4f 'O' - 0x00,0x00,0x78,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x00,0xf8,0xcc,0xcc,0xcc,0xcc,0xf8,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00, - - 7, // 0x51 'Q' - 0x00,0x00,0x78,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xdc,0x78,0x18,0x0c,0x00,0x00, - - 7, // 0x52 'R' - 0x00,0x00,0xf8,0xcc,0xcc,0xcc,0xcc,0xf8,0xd8,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x00,0x78,0xcc,0xcc,0xe0,0x70,0x38,0x1c,0xcc,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0x00,0xfc,0xb4,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x56 'V' - 0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x30,0x00,0x00,0x00, - - 7, // 0x57 'W' - 0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xb4,0xfc,0xcc,0x84,0x00,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x00,0xcc,0xcc,0xcc,0x78,0x30,0x78,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x00,0xcc,0xcc,0xcc,0xcc,0x78,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00, - - 7, // 0x5a 'Z' - 0x00,0x00,0xfc,0x8c,0x0c,0x18,0x30,0x60,0xc0,0xc0,0xc4,0xfc,0x00,0x00,0x00, - - 7, // 0x5b '[' - 0x00,0x78,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x78,0x00,0x00, - - 7, // 0x5c '\' - 0x00,0x00,0xc0,0xc0,0x60,0x60,0x30,0x30,0x18,0x18,0x0c,0x0c,0x00,0x00,0x00, - - 7, // 0x5d ']' - 0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x00,0x00, - - 7, // 0x5e '^' - 0x00,0x10,0x38,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, - - 7, // 0x60 '`' - 0x00,0x30,0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x70,0xd8,0x18,0x78,0xd8,0xd8,0xd8,0x6c,0x00,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x00,0x60,0x60,0x60,0x78,0x6c,0x6c,0x6c,0x6c,0x6c,0x78,0x00,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x78,0xcc,0xc0,0xc0,0xc0,0xc0,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x00,0x18,0x18,0x18,0x78,0xd8,0xd8,0xd8,0xd8,0xd8,0x6c,0x00,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x78,0xcc,0xcc,0xfc,0xc0,0xc0,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x66 'f' - 0x00,0x00,0x30,0x68,0x60,0x60,0xf0,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x6c,0xd8,0xd8,0xd8,0xd8,0xd8,0x78,0x18,0xd8,0x70,0x00, - - 7, // 0x68 'h' - 0x00,0x00,0xc0,0xc0,0xc0,0xd8,0xec,0xcc,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x69 'i' - 0x00,0x00,0x30,0x30,0x00,0x70,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00, - - 7, // 0x6a 'j' - 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0x70,0x00, - - 7, // 0x6b 'k' - 0x00,0x00,0xc0,0xc0,0xcc,0xcc,0xcc,0xd8,0xf0,0xd8,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x6c 'l' - 0x00,0x00,0x70,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00, - - 7, // 0x6d 'm' - 0x00,0x00,0x00,0x00,0xe8,0xfc,0xd4,0xd4,0xd4,0xc4,0xc4,0xc4,0x00,0x00,0x00, - - 7, // 0x6e 'n' - 0x00,0x00,0x00,0x00,0xd8,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00, - - 7, // 0x6f 'o' - 0x00,0x00,0x00,0x00,0x78,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0x00,0xf8,0xcc,0xcc,0xcc,0xcc,0xcc,0xf8,0xc0,0xc0,0xc0,0x00, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x7c,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x0c,0x00, - - 7, // 0x72 'r' - 0x00,0x00,0x00,0x00,0xd8,0xec,0xcc,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x00,0x78,0xcc,0xe0,0x70,0x38,0x1c,0xcc,0x78,0x00,0x00,0x00, - - 7, // 0x74 't' - 0x00,0x00,0x20,0x60,0x60,0xf0,0x60,0x60,0x60,0x60,0x6c,0x38,0x00,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0x00,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0x6c,0x00,0x00,0x00, - - 7, // 0x76 'v' - 0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x30,0x00,0x00,0x00, - - 7, // 0x77 'w' - 0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xb4,0xfc,0xcc,0x84,0x00,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x00,0xcc,0xcc,0x78,0x30,0x78,0xcc,0xcc,0xcc,0x00,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x18,0xf0,0x00, - - 7, // 0x7a 'z' - 0x00,0x00,0x00,0x00,0xfc,0x8c,0x18,0x30,0x60,0xc0,0xc4,0xfc,0x00,0x00,0x00, - - 7, // 0x7b '{' - 0x00,0x1c,0x30,0x30,0x30,0x30,0x30,0xe0,0x30,0x30,0x30,0x30,0x1c,0x00,0x00, - - 7, // 0x7c '|' - 0x00,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x30,0x30,0x30,0x30,0x30,0x00,0x00, - - 7, // 0x7d '}' - 0x00,0xe0,0x30,0x30,0x30,0x30,0x30,0x1c,0x30,0x30,0x30,0x30,0xe0,0x00,0x00, - - 7, // 0x7e '~' - 0x00,0x00,0x34,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x7f '' - 0x00,0x00,0x00,0x00,0x00,0x30,0x78,0xcc,0xcc,0xfc,0x00,0x00,0x00,0x00,0x00, - 0 - }; - - const int8u gse8x16[] = - { - 16, 0, 32, 128-32, - - 0x00,0x00,0x11,0x00,0x22,0x00,0x33,0x00,0x44,0x00,0x55,0x00,0x66,0x00,0x77,0x00,0x88,0x00, - 0x99,0x00,0xaa,0x00,0xbb,0x00,0xcc,0x00,0xdd,0x00,0xee,0x00,0xff,0x00,0x10,0x01,0x21,0x01, - 0x32,0x01,0x43,0x01,0x54,0x01,0x65,0x01,0x76,0x01,0x87,0x01,0x98,0x01,0xa9,0x01,0xba,0x01, - 0xcb,0x01,0xdc,0x01,0xed,0x01,0xfe,0x01,0x0f,0x02,0x20,0x02,0x31,0x02,0x42,0x02,0x53,0x02, - 0x64,0x02,0x75,0x02,0x86,0x02,0x97,0x02,0xa8,0x02,0xb9,0x02,0xca,0x02,0xdb,0x02,0xec,0x02, - 0xfd,0x02,0x0e,0x03,0x1f,0x03,0x30,0x03,0x41,0x03,0x52,0x03,0x63,0x03,0x74,0x03,0x85,0x03, - 0x96,0x03,0xa7,0x03,0xb8,0x03,0xc9,0x03,0xda,0x03,0xeb,0x03,0xfc,0x03,0x0d,0x04,0x1e,0x04, - 0x2f,0x04,0x40,0x04,0x51,0x04,0x62,0x04,0x73,0x04,0x84,0x04,0x95,0x04,0xa6,0x04,0xb7,0x04, - 0xc8,0x04,0xd9,0x04,0xea,0x04,0xfb,0x04,0x0c,0x05,0x1d,0x05,0x2e,0x05,0x3f,0x05,0x50,0x05, - 0x61,0x05,0x72,0x05,0x83,0x05,0x94,0x05,0xa5,0x05,0xb6,0x05,0xc7,0x05,0xd8,0x05,0xe9,0x05, - 0xfa,0x05,0x0b,0x06,0x1c,0x06,0x2d,0x06,0x3e,0x06,0x4f,0x06, - - 8, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x21 '!' - 0x00,0x00,0x10,0x38,0x38,0x38,0x38,0x10,0x10,0x00,0x10,0x10,0x00,0x00,0x00,0x00, - - 8, // 0x22 '"' - 0x00,0x24,0x24,0x24,0x24,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x23 '#' - 0x00,0x00,0x24,0x24,0x24,0x7e,0x24,0x24,0x7e,0x24,0x24,0x24,0x00,0x00,0x00,0x00, - - 8, // 0x24 '$' - 0x00,0x14,0x14,0x3e,0x55,0x54,0x54,0x3e,0x15,0x15,0x55,0x3e,0x14,0x14,0x00,0x00, - - 8, // 0x25 '%' - 0x00,0x00,0x32,0x56,0x6c,0x04,0x08,0x08,0x10,0x13,0x25,0x26,0x00,0x00,0x00,0x00, - - 8, // 0x26 '&' - 0x00,0x00,0x18,0x24,0x24,0x24,0x18,0x28,0x45,0x46,0x44,0x3b,0x00,0x00,0x00,0x00, - - 8, // 0x27 ''' - 0x00,0x00,0x08,0x08,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x28 '(' - 0x00,0x04,0x08,0x10,0x10,0x20,0x20,0x20,0x20,0x10,0x10,0x08,0x04,0x00,0x00,0x00, - - 8, // 0x29 ')' - 0x00,0x10,0x08,0x04,0x04,0x02,0x02,0x02,0x02,0x04,0x04,0x08,0x10,0x00,0x00,0x00, - - 8, // 0x2a '*' - 0x00,0x00,0x00,0x00,0x66,0x24,0x18,0xff,0x18,0x24,0x66,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x2b '+' - 0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x7f,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x20,0x00, - - 8, // 0x2d '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, - - 8, // 0x2f '/' - 0x00,0x02,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,0x00,0x00, - - 8, // 0x30 '0' - 0x00,0x00,0x3c,0x42,0x42,0x46,0x4a,0x52,0x62,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x31 '1' - 0x00,0x00,0x08,0x08,0x18,0x38,0x08,0x08,0x08,0x08,0x08,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x32 '2' - 0x00,0x00,0x3c,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x42,0x7e,0x00,0x00,0x00,0x00, - - 8, // 0x33 '3' - 0x00,0x00,0x7e,0x42,0x04,0x08,0x1c,0x02,0x02,0x02,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x34 '4' - 0x00,0x00,0x04,0x08,0x10,0x24,0x44,0x44,0x7e,0x04,0x04,0x0e,0x00,0x00,0x00,0x00, - - 8, // 0x35 '5' - 0x00,0x00,0x7e,0x42,0x40,0x40,0x7c,0x02,0x02,0x02,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x36 '6' - 0x00,0x00,0x1c,0x20,0x40,0x40,0x7c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x37 '7' - 0x00,0x00,0x7e,0x42,0x42,0x02,0x04,0x08,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00, - - 8, // 0x38 '8' - 0x00,0x00,0x3c,0x42,0x42,0x42,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x39 '9' - 0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3e,0x02,0x02,0x04,0x38,0x00,0x00,0x00,0x00, - - 8, // 0x3a ':' - 0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x3b ';' - 0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x60,0x40,0x00, - - 8, // 0x3c '<' - 0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00, - - 8, // 0x3d '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x3e '>' - 0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x20,0x00,0x00,0x00,0x00, - - 8, // 0x3f '?' - 0x00,0x00,0x3c,0x42,0x42,0x42,0x04,0x08,0x08,0x00,0x08,0x08,0x00,0x00,0x00,0x00, - - 8, // 0x40 '@' - 0x00,0x00,0x3c,0x42,0x01,0x39,0x49,0x49,0x49,0x49,0x49,0x36,0x00,0x00,0x00,0x00, - - 8, // 0x41 'A' - 0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x42,0x00,0x00,0x00,0x00, - - 8, // 0x42 'B' - 0x00,0x00,0x7c,0x22,0x22,0x22,0x3c,0x22,0x22,0x22,0x22,0x7c,0x00,0x00,0x00,0x00, - - 8, // 0x43 'C' - 0x00,0x00,0x3c,0x42,0x42,0x40,0x40,0x40,0x40,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x44 'D' - 0x00,0x00,0x7c,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x7c,0x00,0x00,0x00,0x00, - - 8, // 0x45 'E' - 0x00,0x00,0x7e,0x22,0x20,0x28,0x38,0x28,0x20,0x20,0x22,0x7e,0x00,0x00,0x00,0x00, - - 8, // 0x46 'F' - 0x00,0x00,0x7e,0x22,0x20,0x28,0x38,0x28,0x20,0x20,0x20,0x70,0x00,0x00,0x00,0x00, - - 8, // 0x47 'G' - 0x00,0x00,0x3c,0x42,0x42,0x40,0x40,0x4e,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x48 'H' - 0x00,0x00,0x42,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00,0x00, - - 8, // 0x49 'I' - 0x00,0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1c,0x00,0x00,0x00,0x00, - - 8, // 0x4a 'J' - 0x00,0x00,0x0e,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00,0x00,0x00, - - 8, // 0x4b 'K' - 0x00,0x00,0x62,0x22,0x24,0x28,0x30,0x28,0x24,0x22,0x22,0x62,0x00,0x00,0x00,0x00, - - 8, // 0x4c 'L' - 0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x22,0x7e,0x00,0x00,0x00,0x00, - - 8, // 0x4d 'M' - 0x00,0x00,0x41,0x63,0x55,0x49,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00, - - 8, // 0x4e 'N' - 0x00,0x00,0x42,0x42,0x62,0x52,0x4a,0x46,0x42,0x42,0x42,0x42,0x00,0x00,0x00,0x00, - - 8, // 0x4f 'O' - 0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x50 'P' - 0x00,0x00,0x7c,0x22,0x22,0x22,0x22,0x3c,0x20,0x20,0x20,0x70,0x00,0x00,0x00,0x00, - - 8, // 0x51 'Q' - 0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x42,0x42,0x4a,0x44,0x3a,0x02,0x00,0x00,0x00, - - 8, // 0x52 'R' - 0x00,0x00,0x7c,0x22,0x22,0x22,0x22,0x3c,0x28,0x24,0x22,0x62,0x00,0x00,0x00,0x00, - - 8, // 0x53 'S' - 0x00,0x00,0x3c,0x42,0x42,0x40,0x30,0x0c,0x02,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x54 'T' - 0x00,0x00,0x7f,0x49,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1c,0x00,0x00,0x00,0x00, - - 8, // 0x55 'U' - 0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x56 'V' - 0x00,0x00,0x41,0x41,0x41,0x41,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00,0x00,0x00, - - 8, // 0x57 'W' - 0x00,0x00,0x41,0x41,0x41,0x41,0x41,0x49,0x49,0x55,0x63,0x41,0x00,0x00,0x00,0x00, - - 8, // 0x58 'X' - 0x00,0x00,0x42,0x42,0x42,0x24,0x18,0x18,0x24,0x42,0x42,0x42,0x00,0x00,0x00,0x00, - - 8, // 0x59 'Y' - 0x00,0x00,0x22,0x22,0x22,0x22,0x14,0x08,0x08,0x08,0x08,0x1c,0x00,0x00,0x00,0x00, - - 8, // 0x5a 'Z' - 0x00,0x00,0x7e,0x42,0x02,0x04,0x08,0x10,0x20,0x40,0x42,0x7e,0x00,0x00,0x00,0x00, - - 8, // 0x5b '[' - 0x00,0x1e,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1e,0x00,0x00,0x00, - - 8, // 0x5c '\' - 0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x02,0x02,0x00,0x00,0x00, - - 8, // 0x5d ']' - 0x00,0x3c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x3c,0x00,0x00,0x00, - - 8, // 0x5e '^' - 0x00,0x00,0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00, - - 8, // 0x60 '`' - 0x00,0x00,0x08,0x08,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x04,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x62 'b' - 0x00,0x00,0x60,0x20,0x20,0x38,0x24,0x22,0x22,0x22,0x22,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x3c,0x42,0x40,0x40,0x40,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x64 'd' - 0x00,0x00,0x0c,0x04,0x04,0x1c,0x24,0x44,0x44,0x44,0x44,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x7e,0x40,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x66 'f' - 0x00,0x00,0x0c,0x12,0x10,0x10,0x38,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00, - - 8, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x3e,0x44,0x44,0x44,0x44,0x44,0x3c,0x04,0x44,0x38,0x00, - - 8, // 0x68 'h' - 0x00,0x00,0x60,0x20,0x20,0x2c,0x32,0x22,0x22,0x22,0x22,0x62,0x00,0x00,0x00,0x00, - - 8, // 0x69 'i' - 0x00,0x00,0x08,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x1c,0x00,0x00,0x00,0x00, - - 8, // 0x6a 'j' - 0x00,0x00,0x04,0x04,0x00,0x0c,0x04,0x04,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00, - - 8, // 0x6b 'k' - 0x00,0x00,0x60,0x20,0x20,0x22,0x24,0x28,0x38,0x24,0x22,0x62,0x00,0x00,0x00,0x00, - - 8, // 0x6c 'l' - 0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1c,0x00,0x00,0x00,0x00, - - 8, // 0x6d 'm' - 0x00,0x00,0x00,0x00,0x00,0x76,0x49,0x49,0x49,0x49,0x41,0x41,0x00,0x00,0x00,0x00, - - 8, // 0x6e 'n' - 0x00,0x00,0x00,0x00,0x00,0x5c,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00, - - 8, // 0x6f 'o' - 0x00,0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x7c,0x22,0x22,0x22,0x22,0x22,0x3c,0x20,0x20,0x70,0x00, - - 8, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x3e,0x44,0x44,0x44,0x44,0x44,0x3c,0x04,0x04,0x0e,0x00, - - 8, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x7c,0x22,0x22,0x20,0x20,0x20,0x70,0x00,0x00,0x00,0x00, - - 8, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x3c,0x42,0x40,0x3c,0x02,0x42,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x74 't' - 0x00,0x00,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x12,0x0c,0x00,0x00,0x00,0x00, - - 8, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x41,0x41,0x41,0x41,0x22,0x14,0x08,0x00,0x00,0x00,0x00, - - 8, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x41,0x41,0x41,0x49,0x49,0x55,0x22,0x00,0x00,0x00,0x00, - - 8, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x00,0x00,0x00,0x00, - - 8, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x3e,0x02,0x04,0x78,0x00, - - 8, // 0x7a 'z' - 0x00,0x00,0x00,0x00,0x00,0x7e,0x44,0x08,0x10,0x20,0x42,0x7e,0x00,0x00,0x00,0x00, - - 8, // 0x7b '{' - 0x00,0x06,0x08,0x08,0x08,0x08,0x08,0x30,0x08,0x08,0x08,0x08,0x08,0x06,0x00,0x00, - - 8, // 0x7c '|' - 0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00, - - 8, // 0x7d '}' - 0x00,0x30,0x08,0x08,0x08,0x08,0x08,0x06,0x08,0x08,0x08,0x08,0x08,0x30,0x00,0x00, - - 8, // 0x7e '~' - 0x00,0x00,0x39,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x7f '' - 0x00,0x00,0x00,0x00,0x00,0x08,0x14,0x22,0x41,0x41,0x7f,0x00,0x00,0x00,0x00,0x00, - 0 - }; - - const int8u gse8x16_bold[] = - { - 16, 0, 32, 128-32, - - 0x00,0x00,0x11,0x00,0x22,0x00,0x33,0x00,0x44,0x00,0x55,0x00,0x66,0x00,0x77,0x00,0x88,0x00, - 0x99,0x00,0xaa,0x00,0xbb,0x00,0xcc,0x00,0xdd,0x00,0xee,0x00,0xff,0x00,0x10,0x01,0x21,0x01, - 0x32,0x01,0x43,0x01,0x54,0x01,0x65,0x01,0x76,0x01,0x87,0x01,0x98,0x01,0xa9,0x01,0xba,0x01, - 0xcb,0x01,0xdc,0x01,0xed,0x01,0xfe,0x01,0x0f,0x02,0x20,0x02,0x31,0x02,0x42,0x02,0x53,0x02, - 0x64,0x02,0x75,0x02,0x86,0x02,0x97,0x02,0xa8,0x02,0xb9,0x02,0xca,0x02,0xdb,0x02,0xec,0x02, - 0xfd,0x02,0x0e,0x03,0x1f,0x03,0x30,0x03,0x41,0x03,0x52,0x03,0x63,0x03,0x74,0x03,0x85,0x03, - 0x96,0x03,0xa7,0x03,0xb8,0x03,0xc9,0x03,0xda,0x03,0xeb,0x03,0xfc,0x03,0x0d,0x04,0x1e,0x04, - 0x2f,0x04,0x40,0x04,0x51,0x04,0x62,0x04,0x73,0x04,0x84,0x04,0x95,0x04,0xa6,0x04,0xb7,0x04, - 0xc8,0x04,0xd9,0x04,0xea,0x04,0xfb,0x04,0x0c,0x05,0x1d,0x05,0x2e,0x05,0x3f,0x05,0x50,0x05, - 0x61,0x05,0x72,0x05,0x83,0x05,0x94,0x05,0xa5,0x05,0xb6,0x05,0xc7,0x05,0xd8,0x05,0xe9,0x05, - 0xfa,0x05,0x0b,0x06,0x1c,0x06,0x2d,0x06,0x3e,0x06,0x4f,0x06, - - 8, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x21 '!' - 0x00,0x00,0x18,0x3c,0x3c,0x3c,0x3c,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, - - 8, // 0x22 '"' - 0x00,0x66,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x23 '#' - 0x00,0x00,0x66,0x66,0x66,0xff,0x66,0x66,0xff,0x66,0x66,0x66,0x00,0x00,0x00,0x00, - - 8, // 0x24 '$' - 0x00,0x08,0x08,0x3e,0x6b,0x6b,0x68,0x3e,0x0b,0x6b,0x6b,0x3e,0x08,0x08,0x00,0x00, - - 8, // 0x25 '%' - 0x00,0x00,0x66,0xbe,0xcc,0x0c,0x18,0x18,0x30,0x33,0x65,0x66,0x00,0x00,0x00,0x00, - - 8, // 0x26 '&' - 0x00,0x00,0x1c,0x36,0x36,0x36,0x1c,0x3b,0x6e,0x66,0x66,0x3b,0x00,0x00,0x00,0x00, - - 8, // 0x27 ''' - 0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x28 '(' - 0x00,0x06,0x0c,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0c,0x06,0x00,0x00,0x00, - - 8, // 0x29 ')' - 0x00,0x30,0x18,0x0c,0x0c,0x06,0x06,0x06,0x06,0x0c,0x0c,0x18,0x30,0x00,0x00,0x00, - - 8, // 0x2a '*' - 0x00,0x00,0x00,0x00,0x66,0x24,0x18,0xff,0x18,0x24,0x66,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x2b '+' - 0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x2c ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x20,0x00, - - 8, // 0x2d '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x2e '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, - - 8, // 0x2f '/' - 0x00,0x03,0x03,0x06,0x06,0x0c,0x0c,0x18,0x18,0x30,0x30,0x60,0x60,0x00,0x00,0x00, - - 8, // 0x30 '0' - 0x00,0x00,0x3e,0x63,0x63,0x67,0x6b,0x73,0x63,0x63,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x31 '1' - 0x00,0x00,0x0c,0x0c,0x1c,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3f,0x00,0x00,0x00,0x00, - - 8, // 0x32 '2' - 0x00,0x00,0x3e,0x63,0x63,0x03,0x06,0x0c,0x18,0x30,0x61,0x7f,0x00,0x00,0x00,0x00, - - 8, // 0x33 '3' - 0x00,0x00,0x7f,0x43,0x06,0x0c,0x1e,0x03,0x03,0x03,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x34 '4' - 0x00,0x00,0x06,0x0c,0x18,0x32,0x66,0x66,0x7f,0x06,0x06,0x0f,0x00,0x00,0x00,0x00, - - 8, // 0x35 '5' - 0x00,0x00,0x7f,0x61,0x60,0x60,0x7e,0x03,0x03,0x03,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x36 '6' - 0x00,0x00,0x1e,0x30,0x60,0x60,0x7e,0x63,0x63,0x63,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x37 '7' - 0x00,0x00,0x7f,0x63,0x63,0x03,0x06,0x0c,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, - - 8, // 0x38 '8' - 0x00,0x00,0x3e,0x63,0x63,0x63,0x3e,0x63,0x63,0x63,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x39 '9' - 0x00,0x00,0x3e,0x63,0x63,0x63,0x63,0x3f,0x03,0x03,0x06,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x3a ':' - 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x3b ';' - 0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x60,0x40,0x00, - - 8, // 0x3c '<' - 0x00,0x00,0x00,0x06,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00, - - 8, // 0x3d '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x3e '>' - 0x00,0x00,0x00,0x30,0x18,0x0c,0x06,0x03,0x06,0x0c,0x18,0x30,0x00,0x00,0x00,0x00, - - 8, // 0x3f '?' - 0x00,0x00,0x3e,0x63,0x63,0x63,0x06,0x0c,0x0c,0x00,0x0c,0x0c,0x00,0x00,0x00,0x00, - - 8, // 0x40 '@' - 0x00,0x00,0x7c,0x86,0x03,0x73,0xdb,0xdb,0xdb,0xdb,0xdb,0x6e,0x00,0x00,0x00,0x00, - - 8, // 0x41 'A' - 0x00,0x00,0x08,0x1c,0x36,0x63,0x63,0x63,0x7f,0x63,0x63,0x63,0x00,0x00,0x00,0x00, - - 8, // 0x42 'B' - 0x00,0x00,0x7e,0x33,0x33,0x33,0x3e,0x33,0x33,0x33,0x33,0x7e,0x00,0x00,0x00,0x00, - - 8, // 0x43 'C' - 0x00,0x00,0x1e,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1e,0x00,0x00,0x00,0x00, - - 8, // 0x44 'D' - 0x00,0x00,0x7c,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7c,0x00,0x00,0x00,0x00, - - 8, // 0x45 'E' - 0x00,0x00,0x7f,0x33,0x31,0x34,0x3c,0x34,0x30,0x31,0x33,0x7f,0x00,0x00,0x00,0x00, - - 8, // 0x46 'F' - 0x00,0x00,0x7f,0x33,0x31,0x34,0x3c,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00, - - 8, // 0x47 'G' - 0x00,0x00,0x1f,0x33,0x61,0x60,0x60,0x6f,0x63,0x63,0x33,0x1e,0x00,0x00,0x00,0x00, - - 8, // 0x48 'H' - 0x00,0x00,0x63,0x63,0x63,0x63,0x7f,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00, - - 8, // 0x49 'I' - 0x00,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00, - - 8, // 0x4a 'J' - 0x00,0x00,0x0f,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x4b 'K' - 0x00,0x00,0x73,0x33,0x36,0x36,0x3c,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00, - - 8, // 0x4c 'L' - 0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7f,0x00,0x00,0x00,0x00, - - 8, // 0x4d 'M' - 0x00,0x00,0x63,0x63,0x77,0x77,0x7f,0x6b,0x6b,0x63,0x63,0x63,0x00,0x00,0x00,0x00, - - 8, // 0x4e 'N' - 0x00,0x00,0x63,0x63,0x73,0x7b,0x6f,0x67,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00, - - 8, // 0x4f 'O' - 0x00,0x00,0x1c,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1c,0x00,0x00,0x00,0x00, - - 8, // 0x50 'P' - 0x00,0x00,0x7e,0x33,0x33,0x33,0x33,0x3e,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00, - - 8, // 0x51 'Q' - 0x00,0x00,0x1c,0x36,0x63,0x63,0x63,0x63,0x63,0x6f,0x36,0x1e,0x03,0x00,0x00,0x00, - - 8, // 0x52 'R' - 0x00,0x00,0x7e,0x33,0x33,0x33,0x33,0x3e,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00, - - 8, // 0x53 'S' - 0x00,0x00,0x3e,0x63,0x63,0x30,0x18,0x0c,0x06,0x63,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x54 'T' - 0x00,0x00,0x3f,0x3f,0x2d,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00, - - 8, // 0x55 'U' - 0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x56 'V' - 0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1c,0x08,0x00,0x00,0x00,0x00, - - 8, // 0x57 'W' - 0x00,0x00,0x63,0x63,0x63,0x6b,0x6b,0x7f,0x77,0x77,0x63,0x63,0x00,0x00,0x00,0x00, - - 8, // 0x58 'X' - 0x00,0x00,0x63,0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x63,0x63,0x00,0x00,0x00,0x00, - - 8, // 0x59 'Y' - 0x00,0x00,0x33,0x33,0x33,0x33,0x1e,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00, - - 8, // 0x5a 'Z' - 0x00,0x00,0x7f,0x63,0x43,0x06,0x0c,0x18,0x30,0x61,0x63,0x7f,0x00,0x00,0x00,0x00, - - 8, // 0x5b '[' - 0x00,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00, - - 8, // 0x5c '\' - 0x00,0x60,0x60,0x30,0x30,0x18,0x18,0x0c,0x0c,0x06,0x06,0x03,0x03,0x00,0x00,0x00, - - 8, // 0x5d ']' - 0x00,0x7c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x7c,0x00,0x00,0x00, - - 8, // 0x5e '^' - 0x00,0x00,0x08,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x5f '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00, - - 8, // 0x60 '`' - 0x00,0x00,0x18,0x18,0x18,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x06,0x3e,0x66,0x66,0x3b,0x00,0x00,0x00,0x00, - - 8, // 0x62 'b' - 0x00,0x00,0x70,0x30,0x30,0x3c,0x36,0x33,0x33,0x33,0x33,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x3e,0x63,0x63,0x60,0x60,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x64 'd' - 0x00,0x00,0x0e,0x06,0x06,0x1e,0x36,0x66,0x66,0x66,0x66,0x3b,0x00,0x00,0x00,0x00, - - 8, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x3e,0x63,0x63,0x7f,0x60,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x66 'f' - 0x00,0x00,0x0e,0x1b,0x1b,0x18,0x3c,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, - - 8, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x3b,0x66,0x66,0x66,0x66,0x66,0x3e,0x06,0x66,0x3c,0x00, - - 8, // 0x68 'h' - 0x00,0x00,0x70,0x30,0x30,0x36,0x3b,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00, - - 8, // 0x69 'i' - 0x00,0x00,0x0c,0x0c,0x00,0x1c,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00, - - 8, // 0x6a 'j' - 0x00,0x00,0x06,0x06,0x00,0x0e,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3c,0x00,0x00, - - 8, // 0x6b 'k' - 0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3c,0x36,0x33,0x73,0x00,0x00,0x00,0x00, - - 8, // 0x6c 'l' - 0x00,0x00,0x1c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00, - - 8, // 0x6d 'm' - 0x00,0x00,0x00,0x00,0x00,0x76,0x7f,0x6b,0x6b,0x6b,0x63,0x63,0x00,0x00,0x00,0x00, - - 8, // 0x6e 'n' - 0x00,0x00,0x00,0x00,0x00,0x6e,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00, - - 8, // 0x6f 'o' - 0x00,0x00,0x00,0x00,0x00,0x3e,0x63,0x63,0x63,0x63,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x6e,0x33,0x33,0x33,0x33,0x33,0x3e,0x30,0x30,0x78,0x00, - - 8, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x3b,0x66,0x66,0x66,0x66,0x66,0x3e,0x06,0x06,0x0f,0x00, - - 8, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x6e,0x3b,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00, - - 8, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x3e,0x63,0x60,0x3e,0x03,0x63,0x3e,0x00,0x00,0x00,0x00, - - 8, // 0x74 't' - 0x00,0x00,0x08,0x18,0x18,0x7e,0x18,0x18,0x18,0x18,0x1b,0x0e,0x00,0x00,0x00,0x00, - - 8, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3b,0x00,0x00,0x00,0x00, - - 8, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x36,0x1c,0x08,0x00,0x00,0x00,0x00, - - 8, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x6b,0x6b,0x7f,0x36,0x36,0x00,0x00,0x00,0x00, - - 8, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x1c,0x36,0x63,0x63,0x00,0x00,0x00,0x00, - - 8, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x3f,0x03,0x06,0x7c,0x00, - - 8, // 0x7a 'z' - 0x00,0x00,0x00,0x00,0x00,0x7f,0x63,0x06,0x0c,0x18,0x31,0x7f,0x00,0x00,0x00,0x00, - - 8, // 0x7b '{' - 0x00,0x03,0x04,0x0c,0x0c,0x0c,0x08,0x30,0x08,0x0c,0x0c,0x0c,0x04,0x03,0x00,0x00, - - 8, // 0x7c '|' - 0x00,0x00,0x0c,0x0c,0x0c,0x0c,0x0c,0x00,0x0c,0x0c,0x0c,0x0c,0x0c,0x00,0x00,0x00, - - 8, // 0x7d '}' - 0x00,0x60,0x10,0x18,0x18,0x18,0x08,0x06,0x08,0x18,0x18,0x18,0x10,0x60,0x00,0x00, - - 8, // 0x7e '~' - 0x00,0x00,0x3b,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x7f '' - 0x00,0x00,0x00,0x00,0x00,0x08,0x1c,0x36,0x63,0x63,0x7f,0x00,0x00,0x00,0x00,0x00, - 0 - }; - - const int8u mcs11_prop[] = - { - 11, 2, 32, 128-32, - 0x00,0x00,0x0C,0x00,0x18,0x00,0x24,0x00,0x30,0x00,0x3C,0x00,0x48,0x00,0x54,0x00,0x60,0x00, - 0x6C,0x00,0x78,0x00,0x84,0x00,0x90,0x00,0x9C,0x00,0xA8,0x00,0xB4,0x00,0xC0,0x00,0xCC,0x00, - 0xD8,0x00,0xE4,0x00,0xF0,0x00,0xFC,0x00,0x08,0x01,0x14,0x01,0x20,0x01,0x2C,0x01,0x38,0x01, - 0x44,0x01,0x50,0x01,0x5C,0x01,0x68,0x01,0x74,0x01,0x80,0x01,0x8C,0x01,0x98,0x01,0xA4,0x01, - 0xB0,0x01,0xBC,0x01,0xC8,0x01,0xD4,0x01,0xE0,0x01,0xEC,0x01,0xF8,0x01,0x04,0x02,0x10,0x02, - 0x1C,0x02,0x28,0x02,0x34,0x02,0x40,0x02,0x4C,0x02,0x58,0x02,0x64,0x02,0x70,0x02,0x7C,0x02, - 0x88,0x02,0x94,0x02,0xA0,0x02,0xAC,0x02,0xB8,0x02,0xC4,0x02,0xD0,0x02,0xDC,0x02,0xE8,0x02, - 0xF4,0x02,0x00,0x03,0x0C,0x03,0x18,0x03,0x24,0x03,0x30,0x03,0x3C,0x03,0x48,0x03,0x54,0x03, - 0x60,0x03,0x6C,0x03,0x78,0x03,0x84,0x03,0x90,0x03,0x9C,0x03,0xA8,0x03,0xB4,0x03,0xC0,0x03, - 0xCC,0x03,0xD8,0x03,0xE4,0x03,0xF0,0x03,0xFC,0x03,0x08,0x04,0x14,0x04,0x20,0x04,0x2C,0x04, - 0x38,0x04,0x44,0x04,0x50,0x04,0x5C,0x04,0x68,0x04,0x74,0x04, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00, - - 4, // 0x22 '"' - 0x50,0x50,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x23 '#' - 0x00,0x28,0x28,0x7C,0x28,0x28,0x28,0x7C,0x28,0x28,0x00, - - 6, // 0x24 '$' - 0x10,0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x10,0x10, - - 6, // 0x25 '%' - 0x00,0x00,0x68,0xA8,0xD0,0x10,0x20,0x2C,0x54,0x58,0x00, - - 6, // 0x26 '&' - 0x00,0x20,0x50,0x50,0x50,0x20,0x54,0x54,0x48,0x34,0x00, - - 3, // 0x27 ''' - 0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x28 '(' - 0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10, - - 5, // 0x29 ')' - 0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40, - - 6, // 0x2A '*' - 0x00,0x00,0x28,0x7C,0x38,0x7C,0x28,0x00,0x00,0x00,0x00, - - 6, // 0x2B '+' - 0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00, - - 4, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xC0, - - 6, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00, - - 7, // 0x2F '/' - 0x00,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40, - - 6, // 0x30 '0' - 0x00,0x38,0x44,0x44,0x54,0x54,0x54,0x44,0x44,0x38,0x00, - - 4, // 0x31 '1' - 0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, - - 6, // 0x32 '2' - 0x00,0x38,0x44,0x44,0x04,0x08,0x10,0x20,0x40,0x7C,0x00, - - 6, // 0x33 '3' - 0x00,0x38,0x44,0x04,0x04,0x38,0x04,0x04,0x44,0x38,0x00, - - 6, // 0x34 '4' - 0x00,0x08,0x18,0x18,0x28,0x28,0x48,0x7C,0x08,0x08,0x00, - - 6, // 0x35 '5' - 0x00,0x7C,0x40,0x40,0x78,0x44,0x04,0x04,0x44,0x38,0x00, - - 6, // 0x36 '6' - 0x00,0x38,0x44,0x40,0x40,0x78,0x44,0x44,0x44,0x38,0x00, - - 6, // 0x37 '7' - 0x00,0x7C,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x20,0x00, - - 6, // 0x38 '8' - 0x00,0x38,0x44,0x44,0x44,0x38,0x44,0x44,0x44,0x38,0x00, - - 6, // 0x39 '9' - 0x00,0x38,0x44,0x44,0x44,0x3C,0x04,0x04,0x44,0x38,0x00, - - 4, // 0x3A ':' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0x00, - - 4, // 0x3B ';' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0xC0, - - 6, // 0x3C '<' - 0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00, - - 6, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00, - - 6, // 0x3E '>' - 0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00, - - 6, // 0x3F '?' - 0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x10,0x00,0x10,0x00, - - 6, // 0x40 '@' - 0x00,0x38,0x44,0x44,0x5C,0x54,0x54,0x4C,0x40,0x38,0x00, - - 6, // 0x41 'A' - 0x00,0x38,0x44,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x00, - - 6, // 0x42 'B' - 0x00,0x78,0x44,0x44,0x44,0x78,0x44,0x44,0x44,0x78,0x00, - - 6, // 0x43 'C' - 0x00,0x38,0x44,0x40,0x40,0x40,0x40,0x40,0x44,0x38,0x00, - - 6, // 0x44 'D' - 0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x44,0x48,0x70,0x00, - - 6, // 0x45 'E' - 0x00,0x7C,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x7C,0x00, - - 6, // 0x46 'F' - 0x00,0x7C,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00, - - 6, // 0x47 'G' - 0x00,0x38,0x44,0x40,0x40,0x5C,0x44,0x44,0x4C,0x34,0x00, - - 6, // 0x48 'H' - 0x00,0x44,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00, - - 4, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00, - - 6, // 0x4A 'J' - 0x00,0x1C,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x30,0x00, - - 6, // 0x4B 'K' - 0x00,0x44,0x48,0x50,0x60,0x60,0x50,0x48,0x44,0x44,0x00, - - 6, // 0x4C 'L' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00, - - 8, // 0x4D 'M' - 0x00,0x41,0x63,0x55,0x49,0x49,0x41,0x41,0x41,0x41,0x00, - - 7, // 0x4E 'N' - 0x00,0x42,0x42,0x62,0x52,0x4A,0x46,0x42,0x42,0x42,0x00, - - 6, // 0x4F 'O' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00, - - 6, // 0x50 'P' - 0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x40,0x00, - - 6, // 0x51 'Q' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x54,0x48,0x34,0x00, - - 6, // 0x52 'R' - 0x00,0x78,0x44,0x44,0x44,0x78,0x44,0x44,0x44,0x44,0x00, - - 6, // 0x53 'S' - 0x00,0x38,0x44,0x40,0x40,0x38,0x04,0x04,0x44,0x38,0x00, - - 6, // 0x54 'T' - 0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, - - 6, // 0x55 'U' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00, - - 6, // 0x56 'V' - 0x00,0x44,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x00, - - 8, // 0x57 'W' - 0x00,0x41,0x41,0x41,0x41,0x49,0x49,0x49,0x55,0x22,0x00, - - 6, // 0x58 'X' - 0x00,0x44,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x00, - - 6, // 0x59 'Y' - 0x00,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x10,0x00, - - 6, // 0x5A 'Z' - 0x00,0x7C,0x04,0x04,0x08,0x10,0x20,0x40,0x40,0x7C,0x00, - - 5, // 0x5B '[' - 0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30, - - 7, // 0x5C '\' - 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x00, - - 4, // 0x5D ']' - 0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x60, - - 6, // 0x5E '^' - 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00, - - 4, // 0x60 '`' - 0x00,0x40,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x61 'a' - 0x00,0x00,0x00,0x38,0x04,0x3C,0x44,0x44,0x44,0x3C,0x00, - - 6, // 0x62 'b' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00, - - 6, // 0x64 'd' - 0x00,0x04,0x04,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x00, - - 6, // 0x65 'e' - 0x00,0x00,0x00,0x38,0x44,0x44,0x7C,0x40,0x44,0x38,0x00, - - 4, // 0x66 'f' - 0x00,0x10,0x20,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x00, - - 6, // 0x67 'g' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x3C,0x04,0x44,0x38, - - 6, // 0x68 'h' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x44,0x00, - - 2, // 0x69 'i' - 0x00,0x40,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, - - 3, // 0x6A 'j' - 0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0xA0,0x40, - - 5, // 0x6B 'k' - 0x00,0x40,0x40,0x48,0x50,0x60,0x60,0x50,0x48,0x48,0x00, - - 2, // 0x6C 'l' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, - - 8, // 0x6D 'm' - 0x00,0x00,0x00,0x76,0x49,0x49,0x49,0x49,0x41,0x41,0x00, - - 6, // 0x6E 'n' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x44,0x00, - - 6, // 0x6F 'o' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00, - - 6, // 0x70 'p' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40, - - 6, // 0x71 'q' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x3C,0x04,0x04, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x58,0x24,0x20,0x20,0x20,0x20,0x20,0x00, - - 6, // 0x73 's' - 0x00,0x00,0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00, - - 5, // 0x74 't' - 0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x20,0x28,0x10,0x00, - - 6, // 0x75 'u' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x4C,0x34,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00, - - 8, // 0x77 'w' - 0x00,0x00,0x00,0x41,0x41,0x41,0x41,0x49,0x49,0x36,0x00, - - 6, // 0x78 'x' - 0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00, - - 6, // 0x79 'y' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x3C,0x04,0x08,0x70, - - 6, // 0x7A 'z' - 0x00,0x00,0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x7C,0x00, - - 5, // 0x7B '{' - 0x18,0x20,0x20,0x20,0x20,0xC0,0x20,0x20,0x20,0x20,0x18, - - 3, // 0x7C '|' - 0x00,0x40,0x40,0x40,0x40,0x00,0x40,0x40,0x40,0x40,0x00, - - 5, // 0x7D '}' - 0xC0,0x20,0x20,0x20,0x20,0x18,0x20,0x20,0x20,0x20,0xC0, - - 6, // 0x7E '~' - 0x00,0x24,0x54,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x7F '' - 0x00,0x10,0x38,0x6C,0x44,0x44,0x7C,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs11_prop_condensed[] = - { - 11, 2, 32, 128-32, - 0x00,0x00,0x0C,0x00,0x18,0x00,0x24,0x00,0x30,0x00,0x3C,0x00,0x48,0x00,0x54,0x00,0x60,0x00, - 0x6C,0x00,0x78,0x00,0x84,0x00,0x90,0x00,0x9C,0x00,0xA8,0x00,0xB4,0x00,0xC0,0x00,0xCC,0x00, - 0xD8,0x00,0xE4,0x00,0xF0,0x00,0xFC,0x00,0x08,0x01,0x14,0x01,0x20,0x01,0x2C,0x01,0x38,0x01, - 0x44,0x01,0x50,0x01,0x5C,0x01,0x68,0x01,0x74,0x01,0x80,0x01,0x8C,0x01,0x98,0x01,0xA4,0x01, - 0xB0,0x01,0xBC,0x01,0xC8,0x01,0xD4,0x01,0xE0,0x01,0xEC,0x01,0xF8,0x01,0x04,0x02,0x10,0x02, - 0x1C,0x02,0x28,0x02,0x34,0x02,0x40,0x02,0x4C,0x02,0x58,0x02,0x64,0x02,0x70,0x02,0x7C,0x02, - 0x88,0x02,0x94,0x02,0xA0,0x02,0xAC,0x02,0xB8,0x02,0xC4,0x02,0xD0,0x02,0xDC,0x02,0xE8,0x02, - 0xF4,0x02,0x00,0x03,0x0C,0x03,0x18,0x03,0x24,0x03,0x30,0x03,0x3C,0x03,0x48,0x03,0x54,0x03, - 0x60,0x03,0x6C,0x03,0x78,0x03,0x84,0x03,0x90,0x03,0x9C,0x03,0xA8,0x03,0xB4,0x03,0xC0,0x03, - 0xCC,0x03,0xD8,0x03,0xE4,0x03,0xF0,0x03,0xFC,0x03,0x08,0x04,0x14,0x04,0x20,0x04,0x2C,0x04, - 0x38,0x04,0x44,0x04,0x50,0x04,0x5C,0x04,0x68,0x04,0x74,0x04, - - 3, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 3, // 0x21 '!' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x40,0x00, - - 4, // 0x22 '"' - 0x50,0x50,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x23 '#' - 0x00,0x50,0x50,0xF8,0x50,0x50,0x50,0xF8,0x50,0x50,0x00, - - 5, // 0x24 '$' - 0x00,0x40,0x60,0x90,0x80,0x60,0x10,0x90,0x60,0x20,0x00, - - 5, // 0x25 '%' - 0x00,0x00,0x90,0x90,0x20,0x20,0x40,0x40,0x90,0x90,0x00, - - 5, // 0x26 '&' - 0x00,0x40,0xA0,0xA0,0xA0,0x40,0xA8,0x90,0x90,0x68,0x00, - - 5, // 0x27 ''' - 0x00,0x00,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10, - - 4, // 0x29 ')' - 0x80,0x40,0x40,0x20,0x20,0x20,0x20,0x20,0x40,0x40,0x80, - - 5, // 0x2A '*' - 0x00,0x00,0x90,0x60,0xF0,0x60,0x90,0x00,0x00,0x00,0x00, - - 5, // 0x2B '+' - 0x00,0x00,0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00,0x00, - - 4, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xC0, - - 5, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x00, - - 6, // 0x2F '/' - 0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x00, - - 5, // 0x30 '0' - 0x00,0x70,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0xE0,0x00, - - 3, // 0x31 '1' - 0x00,0x40,0xC0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, - - 5, // 0x32 '2' - 0x00,0x60,0x90,0x90,0x10,0x10,0x20,0x40,0x80,0xF0,0x00, - - 5, // 0x33 '3' - 0x00,0x60,0x90,0x10,0x10,0x60,0x10,0x10,0x90,0x60,0x00, - - 5, // 0x34 '4' - 0x00,0x10,0x30,0x30,0x50,0x50,0x90,0xF0,0x10,0x10,0x00, - - 5, // 0x35 '5' - 0x00,0xF0,0x80,0x80,0xE0,0x90,0x10,0x10,0x90,0x60,0x00, - - 5, // 0x36 '6' - 0x00,0x60,0x90,0x80,0x80,0xE0,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x37 '7' - 0x00,0xF0,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x00, - - 5, // 0x38 '8' - 0x00,0x60,0x90,0x90,0x90,0x60,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x39 '9' - 0x00,0x60,0x90,0x90,0x90,0x70,0x10,0x10,0x90,0x60,0x00, - - 4, // 0x3A ':' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0x00, - - 4, // 0x3B ';' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0xC0, - - 6, // 0x3C '<' - 0x00,0x08,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x08,0x00, - - 5, // 0x3D '=' - 0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0xF0,0x00,0x00,0x00, - - 6, // 0x3E '>' - 0x00,0x80,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x80,0x00, - - 5, // 0x3F '?' - 0x00,0x60,0x90,0x10,0x10,0x20,0x40,0x00,0x40,0x00,0x00, - - 5, // 0x40 '@' - 0x00,0x60,0x90,0x90,0xB0,0xB0,0xB0,0x80,0x80,0x70,0x00, - - 5, // 0x41 'A' - 0x00,0x60,0x90,0x90,0x90,0xF0,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x42 'B' - 0x00,0xE0,0x90,0x90,0x90,0xE0,0x90,0x90,0x90,0xE0,0x00, - - 5, // 0x43 'C' - 0x00,0x60,0x90,0x80,0x80,0x80,0x80,0x80,0x90,0x60,0x00, - - 5, // 0x44 'D' - 0x00,0xE0,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0xE0,0x00, - - 5, // 0x45 'E' - 0x00,0xF0,0x80,0x80,0x80,0xF0,0x80,0x80,0x80,0xF0,0x00, - - 5, // 0x46 'F' - 0x00,0xF0,0x80,0x80,0x80,0xF0,0x80,0x80,0x80,0x80,0x00, - - 5, // 0x47 'G' - 0x00,0x70,0x80,0x80,0x80,0xB0,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x48 'H' - 0x00,0x90,0x90,0x90,0x90,0xF0,0x90,0x90,0x90,0x90,0x00, - - 4, // 0x49 'I' - 0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xE0,0x00, - - 5, // 0x4A 'J' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0xA0,0xA0,0x40,0x00, - - 5, // 0x4B 'K' - 0x00,0x90,0x90,0xA0,0xA0,0xC0,0xA0,0xA0,0x90,0x90,0x00, - - 5, // 0x4C 'L' - 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xF0,0x00, - - 6, // 0x4D 'M' - 0x00,0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x88,0x88,0x00, - - 5, // 0x4E 'N' - 0x00,0x90,0x90,0xD0,0xD0,0xB0,0xB0,0x90,0x90,0x90,0x00, - - 5, // 0x4F 'O' - 0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x50 'P' - 0x00,0xE0,0x90,0x90,0x90,0x90,0xE0,0x80,0x80,0x80,0x00, - - 5, // 0x51 'Q' - 0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x30, - - 5, // 0x52 'R' - 0x00,0xE0,0x90,0x90,0x90,0x90,0xE0,0xA0,0x90,0x90,0x00, - - 5, // 0x53 'S' - 0x00,0x60,0x90,0x80,0x80,0x60,0x10,0x10,0x90,0x60,0x00, - - 6, // 0x54 'T' - 0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, - - 5, // 0x55 'U' - 0x00,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x00, - - 6, // 0x56 'V' - 0x00,0x88,0x88,0x88,0x88,0x50,0x50,0x50,0x20,0x20,0x00, - - 6, // 0x57 'W' - 0x00,0x88,0x88,0x88,0xA8,0xA8,0xA8,0xA8,0xA8,0x50,0x00, - - 5, // 0x58 'X' - 0x00,0x90,0x90,0x90,0x60,0x60,0x90,0x90,0x90,0x90,0x00, - - 6, // 0x59 'Y' - 0x00,0x88,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x20,0x00, - - 5, // 0x5A 'Z' - 0x00,0xF0,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0xF0,0x00, - - 4, // 0x5B '[' - 0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x60,0x00, - - 6, // 0x5C '\' - 0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x00, - - 4, // 0x5D ']' - 0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x60,0x00, - - 5, // 0x5E '^' - 0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00, - - 5, // 0x60 '`' - 0x00,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x61 'a' - 0x00,0x00,0x00,0x60,0x90,0x10,0x70,0x90,0x90,0x70,0x00, - - 5, // 0x62 'b' - 0x00,0x80,0x80,0x80,0xE0,0x90,0x90,0x90,0x90,0xE0,0x00, - - 5, // 0x63 'c' - 0x00,0x00,0x00,0x60,0x90,0x80,0x80,0x80,0x90,0x60,0x00, - - 5, // 0x64 'd' - 0x00,0x10,0x10,0x10,0x70,0x90,0x90,0x90,0x90,0x70,0x00, - - 5, // 0x65 'e' - 0x00,0x00,0x00,0x60,0x90,0x90,0xF0,0x80,0x90,0x60,0x00, - - 4, // 0x66 'f' - 0x00,0x20,0x40,0x40,0xE0,0x40,0x40,0x40,0x40,0x40,0x00, - - 5, // 0x67 'g' - 0x00,0x00,0x00,0x70,0x90,0x90,0x90,0x70,0x10,0x90,0x60, - - 5, // 0x68 'h' - 0x00,0x80,0x80,0x80,0xE0,0x90,0x90,0x90,0x90,0x90,0x00, - - 2, // 0x69 'i' - 0x00,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00, - - 4, // 0x6A 'j' - 0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0xA0,0x40, - - 5, // 0x6B 'k' - 0x00,0x80,0x80,0x90,0x90,0xA0,0xC0,0xA0,0x90,0x90,0x00, - - 2, // 0x6C 'l' - 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00, - - 6, // 0x6D 'm' - 0x00,0x00,0x00,0xD0,0xA8,0xA8,0xA8,0x88,0x88,0x88,0x00, - - 5, // 0x6E 'n' - 0x00,0x00,0x00,0xA0,0xD0,0x90,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x6F 'o' - 0x00,0x00,0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x70 'p' - 0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0x90,0xE0,0x80,0x80, - - 5, // 0x71 'q' - 0x00,0x00,0x00,0x70,0x90,0x90,0x90,0x90,0x70,0x10,0x10, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0xB8,0x48,0x40,0x40,0x40,0x40,0x40,0x00, - - 5, // 0x73 's' - 0x00,0x00,0x00,0x60,0x90,0x40,0x20,0x10,0x90,0x60,0x00, - - 4, // 0x74 't' - 0x00,0x40,0x40,0xE0,0x40,0x40,0x40,0x40,0x40,0x20,0x00, - - 5, // 0x75 'u' - 0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x90,0x90,0x70,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x50,0x20,0x20,0x00, - - 6, // 0x77 'w' - 0x00,0x00,0x00,0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00, - - 5, // 0x78 'x' - 0x00,0x00,0x00,0x90,0x90,0x60,0x60,0x90,0x90,0x90,0x00, - - 5, // 0x79 'y' - 0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x70,0x10,0x20,0xC0, - - 5, // 0x7A 'z' - 0x00,0x00,0x00,0xF0,0x10,0x20,0x40,0x80,0x80,0xF0,0x00, - - 5, // 0x7B '{' - 0x30,0x40,0x40,0x40,0x40,0x80,0x40,0x40,0x40,0x40,0x30, - - 3, // 0x7C '|' - 0x00,0x40,0x40,0x40,0x40,0x00,0x40,0x40,0x40,0x40,0x00, - - 5, // 0x7D '}' - 0xC0,0x20,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0xC0, - - 5, // 0x7E '~' - 0x00,0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x7F '' - 0x00,0x20,0x70,0xD8,0x88,0x88,0xF8,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs12_prop[] = - { - 12, 3, 32, 128-32, - 0x00,0x00,0x0D,0x00,0x1A,0x00,0x27,0x00,0x34,0x00,0x41,0x00,0x4E,0x00,0x5B,0x00,0x68,0x00, - 0x75,0x00,0x82,0x00,0x8F,0x00,0x9C,0x00,0xA9,0x00,0xB6,0x00,0xC3,0x00,0xD0,0x00,0xDD,0x00, - 0xEA,0x00,0xF7,0x00,0x04,0x01,0x11,0x01,0x1E,0x01,0x2B,0x01,0x38,0x01,0x45,0x01,0x52,0x01, - 0x5F,0x01,0x6C,0x01,0x79,0x01,0x86,0x01,0x93,0x01,0xA0,0x01,0xAD,0x01,0xBA,0x01,0xC7,0x01, - 0xD4,0x01,0xE1,0x01,0xEE,0x01,0xFB,0x01,0x08,0x02,0x15,0x02,0x22,0x02,0x2F,0x02,0x3C,0x02, - 0x49,0x02,0x62,0x02,0x6F,0x02,0x7C,0x02,0x89,0x02,0x96,0x02,0xA3,0x02,0xB0,0x02,0xBD,0x02, - 0xCA,0x02,0xD7,0x02,0xF0,0x02,0xFD,0x02,0x0A,0x03,0x17,0x03,0x24,0x03,0x31,0x03,0x3E,0x03, - 0x4B,0x03,0x58,0x03,0x65,0x03,0x72,0x03,0x7F,0x03,0x8C,0x03,0x99,0x03,0xA6,0x03,0xB3,0x03, - 0xC0,0x03,0xCD,0x03,0xDA,0x03,0xE7,0x03,0xF4,0x03,0x01,0x04,0x1A,0x04,0x27,0x04,0x34,0x04, - 0x41,0x04,0x4E,0x04,0x5B,0x04,0x68,0x04,0x75,0x04,0x82,0x04,0x8F,0x04,0xA8,0x04,0xB5,0x04, - 0xC2,0x04,0xCF,0x04,0xDC,0x04,0xE9,0x04,0xF6,0x04,0x03,0x05, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, - - 4, // 0x22 '"' - 0x50,0x50,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x23 '#' - 0x28,0x28,0x28,0x7C,0x28,0x28,0x28,0x7C,0x28,0x28,0x28,0x00, - - 6, // 0x24 '$' - 0x10,0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x10,0x10,0x00, - - 7, // 0x25 '%' - 0x32,0x54,0x64,0x08,0x08,0x10,0x10,0x26,0x2A,0x4C,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x30,0x48,0x48,0x48,0x30,0x4A,0x4A,0x44,0x3A,0x00,0x00, - - 3, // 0x27 ''' - 0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10,0x00, - - 5, // 0x29 ')' - 0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40,0x00, - - 6, // 0x2A '*' - 0x00,0x00,0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x00, - - 6, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00, - - 4, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x40,0x80, - - 6, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00, - - 7, // 0x2F '/' - 0x00,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00, - - 7, // 0x30 '0' - 0x00,0x38,0x44,0x44,0x54,0x54,0x54,0x44,0x44,0x38,0x00,0x00, - - 4, // 0x31 '1' - 0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x38,0x44,0x04,0x04,0x38,0x04,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x34 '4' - 0x00,0x08,0x18,0x28,0x28,0x48,0x48,0x7C,0x08,0x08,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x7C,0x40,0x40,0x78,0x44,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x38,0x44,0x40,0x78,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x37 '7' - 0x00,0x7C,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x20,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x38,0x44,0x44,0x44,0x38,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x38,0x44,0x44,0x44,0x3C,0x04,0x04,0x44,0x38,0x00,0x00, - - 4, // 0x3A ':' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0x00,0x00, - - 4, // 0x3B ';' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0x40,0x80, - - 6, // 0x3C '<' - 0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00, - - 6, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,0x00, - - 6, // 0x3E '>' - 0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00, - - 6, // 0x3F '?' - 0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x10,0x00,0x10,0x00,0x00, - - 7, // 0x40 '@' - 0x00,0x38,0x44,0x44,0x5C,0x54,0x54,0x4C,0x40,0x38,0x00,0x00, - - 7, // 0x41 'A' - 0x00,0x38,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x78,0x44,0x44,0x44,0x78,0x44,0x44,0x44,0x78,0x00,0x00, - - 6, // 0x43 'C' - 0x00,0x38,0x44,0x40,0x40,0x40,0x40,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x44,0x48,0x70,0x00,0x00, - - 6, // 0x45 'E' - 0x00,0x7C,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x7C,0x00,0x00, - - 6, // 0x46 'F' - 0x00,0x7C,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x38,0x44,0x40,0x40,0x5C,0x44,0x44,0x4C,0x34,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0x44,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 6, // 0x4A 'J' - 0x00,0x1C,0x08,0x08,0x08,0x08,0x08,0x48,0x48,0x30,0x00,0x00, - - 6, // 0x4B 'K' - 0x00,0x44,0x48,0x50,0x60,0x60,0x50,0x48,0x44,0x44,0x00,0x00, - - 6, // 0x4C 'L' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,0x00, - - 9, // 0x4D 'M' - 0x00,0x00,0x41,0x00,0x63,0x00,0x55,0x00,0x49,0x00,0x49,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x4E 'N' - 0x00,0x44,0x64,0x64,0x54,0x54,0x4C,0x4C,0x44,0x44,0x00,0x00, - - 7, // 0x4F 'O' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x51 'Q' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00, - - 7, // 0x52 'R' - 0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x48,0x44,0x44,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x38,0x44,0x40,0x40,0x38,0x04,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x54 'T' - 0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x56 'V' - 0x00,0x44,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x00,0x00, - - 9, // 0x57 'W' - 0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x49,0x00,0x49,0x00,0x55,0x00,0x22,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x44,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x44,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x00,0x00, - - 6, // 0x5A 'Z' - 0x00,0x7C,0x04,0x04,0x08,0x10,0x20,0x40,0x40,0x7C,0x00,0x00, - - 4, // 0x5B '[' - 0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70,0x00, - - 7, // 0x5C '\' - 0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x00, - - 4, // 0x5D ']' - 0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xE0,0x00, - - 6, // 0x5E '^' - 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00, - - 4, // 0x60 '`' - 0x00,0x40,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x38,0x04,0x3C,0x44,0x44,0x44,0x3C,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x00,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x04,0x04,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x38,0x44,0x44,0x7C,0x40,0x44,0x38,0x00,0x00, - - 4, // 0x66 'f' - 0x00,0x30,0x40,0xE0,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x04,0x78, - - 7, // 0x68 'h' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x40,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 5, // 0x6A 'j' - 0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0x60, - - 6, // 0x6B 'k' - 0x00,0x40,0x40,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 9, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x00,0x49,0x00,0x49,0x00,0x49,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x6E 'n' - 0x00,0x00,0x00,0x58,0x64,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x6F 'o' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x40,0x40, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x04,0x04, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x58,0x24,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,0x00, - - 5, // 0x74 't' - 0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x20,0x20,0x18,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x4C,0x34,0x00,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00, - - 9, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x49,0x00,0x49,0x00,0x49,0x00,0x36,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3C,0x08,0x70, - - 6, // 0x7A 'z' - 0x00,0x00,0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 5, // 0x7B '{' - 0x18,0x20,0x20,0x20,0x20,0xC0,0x20,0x20,0x20,0x20,0x18,0x00, - - 3, // 0x7C '|' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, - - 5, // 0x7D '}' - 0xC0,0x20,0x20,0x20,0x20,0x18,0x20,0x20,0x20,0x20,0xC0,0x00, - - 7, // 0x7E '~' - 0x00,0x60,0x92,0x92,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x7F '' - 0x00,0x10,0x38,0x6C,0x44,0x44,0x7C,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs13_prop[] = - { - 13, 4, 32, 128-32, - 0x00,0x00,0x0E,0x00,0x1C,0x00,0x2A,0x00,0x38,0x00,0x46,0x00,0x54,0x00,0x62,0x00,0x70,0x00, - 0x7E,0x00,0x8C,0x00,0x9A,0x00,0xA8,0x00,0xB6,0x00,0xC4,0x00,0xD2,0x00,0xE0,0x00,0xEE,0x00, - 0xFC,0x00,0x0A,0x01,0x18,0x01,0x26,0x01,0x34,0x01,0x42,0x01,0x50,0x01,0x5E,0x01,0x6C,0x01, - 0x7A,0x01,0x88,0x01,0x96,0x01,0xA4,0x01,0xB2,0x01,0xC0,0x01,0xCE,0x01,0xDC,0x01,0xEA,0x01, - 0xF8,0x01,0x06,0x02,0x14,0x02,0x22,0x02,0x30,0x02,0x3E,0x02,0x4C,0x02,0x5A,0x02,0x68,0x02, - 0x76,0x02,0x91,0x02,0x9F,0x02,0xAD,0x02,0xBB,0x02,0xC9,0x02,0xD7,0x02,0xE5,0x02,0xF3,0x02, - 0x01,0x03,0x0F,0x03,0x2A,0x03,0x38,0x03,0x46,0x03,0x54,0x03,0x62,0x03,0x70,0x03,0x7E,0x03, - 0x8C,0x03,0x9A,0x03,0xA8,0x03,0xB6,0x03,0xC4,0x03,0xD2,0x03,0xE0,0x03,0xEE,0x03,0xFC,0x03, - 0x0A,0x04,0x18,0x04,0x26,0x04,0x34,0x04,0x42,0x04,0x50,0x04,0x6B,0x04,0x79,0x04,0x87,0x04, - 0x95,0x04,0xA3,0x04,0xB1,0x04,0xBF,0x04,0xCD,0x04,0xDB,0x04,0xE9,0x04,0x04,0x05,0x12,0x05, - 0x20,0x05,0x2E,0x05,0x3C,0x05,0x4A,0x05,0x58,0x05,0x66,0x05, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, - - 4, // 0x22 '"' - 0x00,0x50,0x50,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x23 '#' - 0x00,0x28,0x28,0x28,0x7C,0x28,0x28,0x28,0x7C,0x28,0x28,0x28,0x00, - - 6, // 0x24 '$' - 0x00,0x10,0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x10,0x10,0x00, - - 7, // 0x25 '%' - 0x00,0x32,0x54,0x64,0x08,0x08,0x10,0x10,0x26,0x2A,0x4C,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x30,0x48,0x48,0x48,0x30,0x4A,0x4A,0x44,0x3A,0x00,0x00,0x00, - - 3, // 0x27 ''' - 0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10,0x00,0x00, - - 5, // 0x29 ')' - 0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40,0x00,0x00, - - 6, // 0x2A '*' - 0x00,0x00,0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x00,0x00, - - 6, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00,0x00, - - 4, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x20,0x40,0x80, - - 6, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00, - - 7, // 0x2F '/' - 0x00,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,0x00, - - 7, // 0x30 '0' - 0x00,0x38,0x44,0x44,0x54,0x54,0x54,0x44,0x44,0x38,0x00,0x00,0x00, - - 4, // 0x31 '1' - 0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x38,0x44,0x04,0x04,0x38,0x04,0x04,0x44,0x38,0x00,0x00,0x00, - - 6, // 0x34 '4' - 0x00,0x08,0x18,0x28,0x28,0x48,0x48,0x7C,0x08,0x08,0x00,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x7C,0x40,0x40,0x78,0x44,0x04,0x04,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x38,0x44,0x40,0x78,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 6, // 0x37 '7' - 0x00,0x7C,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x20,0x00,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x38,0x44,0x44,0x44,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x38,0x44,0x44,0x44,0x3C,0x04,0x04,0x44,0x38,0x00,0x00,0x00, - - 4, // 0x3A ':' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00, - - 4, // 0x3B ';' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0x20,0x40,0x80, - - 6, // 0x3C '<' - 0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, - - 6, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x3E '>' - 0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, - - 6, // 0x3F '?' - 0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x10,0x00,0x10,0x00,0x00,0x00, - - 7, // 0x40 '@' - 0x00,0x38,0x44,0x44,0x5C,0x54,0x54,0x4C,0x40,0x38,0x00,0x00,0x00, - - 7, // 0x41 'A' - 0x00,0x38,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x78,0x44,0x44,0x44,0x78,0x44,0x44,0x44,0x78,0x00,0x00,0x00, - - 6, // 0x43 'C' - 0x00,0x38,0x44,0x40,0x40,0x40,0x40,0x40,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x44,0x48,0x70,0x00,0x00,0x00, - - 6, // 0x45 'E' - 0x00,0x7C,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x7C,0x00,0x00,0x00, - - 6, // 0x46 'F' - 0x00,0x7C,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x38,0x44,0x40,0x40,0x5C,0x44,0x44,0x4C,0x34,0x00,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0x44,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,0x00, - - 6, // 0x4A 'J' - 0x00,0x1C,0x08,0x08,0x08,0x08,0x08,0x48,0x48,0x30,0x00,0x00,0x00, - - 6, // 0x4B 'K' - 0x00,0x44,0x48,0x50,0x60,0x60,0x50,0x48,0x44,0x44,0x00,0x00,0x00, - - 6, // 0x4C 'L' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,0x00,0x00, - - 9, // 0x4D 'M' - 0x00,0x00,0x41,0x00,0x63,0x00,0x55,0x00,0x49,0x00,0x49,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x4E 'N' - 0x00,0x44,0x64,0x64,0x54,0x54,0x4C,0x4C,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x4F 'O' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x51 'Q' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00,0x00, - - 7, // 0x52 'R' - 0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x48,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x38,0x44,0x40,0x40,0x38,0x04,0x04,0x44,0x38,0x00,0x00,0x00, - - 6, // 0x54 'T' - 0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 6, // 0x56 'V' - 0x00,0x44,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x00,0x00,0x00, - - 9, // 0x57 'W' - 0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x49,0x00,0x49,0x00,0x55,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x44,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x44,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x00,0x00,0x00, - - 6, // 0x5A 'Z' - 0x00,0x7C,0x04,0x04,0x08,0x10,0x20,0x40,0x40,0x7C,0x00,0x00,0x00, - - 4, // 0x5B '[' - 0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70,0x00,0x00, - - 7, // 0x5C '\' - 0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x00,0x00, - - 4, // 0x5D ']' - 0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xE0,0x00,0x00, - - 6, // 0x5E '^' - 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00, - - 4, // 0x60 '`' - 0x00,0x40,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x38,0x04,0x3C,0x44,0x44,0x44,0x3C,0x00,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x00,0x00,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x04,0x04,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x00,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x38,0x44,0x44,0x7C,0x40,0x44,0x38,0x00,0x00,0x00, - - 4, // 0x66 'f' - 0x00,0x30,0x40,0xE0,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x04,0x44,0x38, - - 7, // 0x68 'h' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x40,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 5, // 0x6A 'j' - 0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0x60,0x00, - - 6, // 0x6B 'k' - 0x00,0x40,0x40,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 9, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x00,0x49,0x00,0x49,0x00,0x49,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x6E 'n' - 0x00,0x00,0x00,0x58,0x64,0x44,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x6F 'o' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x40,0x40,0x40, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x04,0x04,0x04, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x58,0x24,0x20,0x20,0x20,0x20,0x70,0x00,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,0x00,0x00, - - 5, // 0x74 't' - 0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x20,0x20,0x18,0x00,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x4C,0x34,0x00,0x00,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00,0x00, - - 9, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x49,0x00,0x49,0x00,0x49,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3C,0x04,0x08,0x70, - - 6, // 0x7A 'z' - 0x00,0x00,0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00,0x00, - - 5, // 0x7B '{' - 0x18,0x20,0x20,0x20,0x20,0xC0,0x20,0x20,0x20,0x20,0x18,0x00,0x00, - - 3, // 0x7C '|' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 5, // 0x7D '}' - 0xC0,0x20,0x20,0x20,0x20,0x18,0x20,0x20,0x20,0x20,0xC0,0x00,0x00, - - 7, // 0x7E '~' - 0x00,0x60,0x92,0x92,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x7F '' - 0x00,0x10,0x38,0x6C,0x44,0x44,0x7C,0x00,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs5x10_mono[] = - { - 10, 2, 32, 128-32, - 0x00,0x00,0x0B,0x00,0x16,0x00,0x21,0x00,0x2C,0x00,0x37,0x00,0x42,0x00,0x4D,0x00,0x58,0x00, - 0x63,0x00,0x6E,0x00,0x79,0x00,0x84,0x00,0x8F,0x00,0x9A,0x00,0xA5,0x00,0xB0,0x00,0xBB,0x00, - 0xC6,0x00,0xD1,0x00,0xDC,0x00,0xE7,0x00,0xF2,0x00,0xFD,0x00,0x08,0x01,0x13,0x01,0x1E,0x01, - 0x29,0x01,0x34,0x01,0x3F,0x01,0x4A,0x01,0x55,0x01,0x60,0x01,0x6B,0x01,0x76,0x01,0x81,0x01, - 0x8C,0x01,0x97,0x01,0xA2,0x01,0xAD,0x01,0xB8,0x01,0xC3,0x01,0xCE,0x01,0xD9,0x01,0xE4,0x01, - 0xEF,0x01,0xFA,0x01,0x05,0x02,0x10,0x02,0x1B,0x02,0x26,0x02,0x31,0x02,0x3C,0x02,0x47,0x02, - 0x52,0x02,0x5D,0x02,0x68,0x02,0x73,0x02,0x7E,0x02,0x89,0x02,0x94,0x02,0x9F,0x02,0xAA,0x02, - 0xB5,0x02,0xC0,0x02,0xCB,0x02,0xD6,0x02,0xE1,0x02,0xEC,0x02,0xF7,0x02,0x02,0x03,0x0D,0x03, - 0x18,0x03,0x23,0x03,0x2E,0x03,0x39,0x03,0x44,0x03,0x4F,0x03,0x5A,0x03,0x65,0x03,0x70,0x03, - 0x7B,0x03,0x86,0x03,0x91,0x03,0x9C,0x03,0xA7,0x03,0xB2,0x03,0xBD,0x03,0xC8,0x03,0xD3,0x03, - 0xDE,0x03,0xE9,0x03,0xF4,0x03,0xFF,0x03,0x0A,0x04,0x15,0x04, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00, - - 5, // 0x22 '"' - 0x00,0x50,0x50,0xA0,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x23 '#' - 0x00,0x50,0x50,0xF8,0x50,0x50,0x50,0xF8,0x50,0x50, - - 5, // 0x24 '$' - 0x00,0x40,0x60,0x90,0x80,0x60,0x10,0x90,0x60,0x20, - - 5, // 0x25 '%' - 0x00,0x00,0x90,0x90,0x20,0x20,0x40,0x40,0x90,0x90, - - 5, // 0x26 '&' - 0x00,0x40,0xA0,0xA0,0xA0,0x40,0xA8,0x90,0x90,0x68, - - 5, // 0x27 ''' - 0x00,0x20,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x20,0x20,0x10, - - 5, // 0x29 ')' - 0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x20,0x20,0x40, - - 5, // 0x2A '*' - 0x00,0x00,0x90,0x60,0xF0,0x60,0x90,0x00,0x00,0x00, - - 5, // 0x2B '+' - 0x00,0x00,0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00, - - 5, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xC0, - - 5, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00, - - 5, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00, - - 5, // 0x2F '/' - 0x00,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x00, - - 5, // 0x30 '0' - 0x00,0x70,0x90,0x90,0x90,0x90,0x90,0x90,0xE0,0x00, - - 5, // 0x31 '1' - 0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x32 '2' - 0x00,0x60,0x90,0x90,0x10,0x20,0x40,0x80,0xF0,0x00, - - 5, // 0x33 '3' - 0x00,0x60,0x90,0x10,0x60,0x10,0x10,0x90,0x60,0x00, - - 5, // 0x34 '4' - 0x00,0x10,0x30,0x50,0x50,0x90,0xF0,0x10,0x10,0x00, - - 5, // 0x35 '5' - 0x00,0xF0,0x80,0x80,0xE0,0x10,0x10,0x90,0x60,0x00, - - 5, // 0x36 '6' - 0x00,0x60,0x80,0x80,0xE0,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x37 '7' - 0x00,0xF0,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x00, - - 5, // 0x38 '8' - 0x00,0x60,0x90,0x90,0x60,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x39 '9' - 0x00,0x60,0x90,0x90,0x90,0x70,0x10,0x10,0x60,0x00, - - 5, // 0x3A ':' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00, - - 5, // 0x3B ';' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0xC0, - - 5, // 0x3C '<' - 0x00,0x08,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x08, - - 5, // 0x3D '=' - 0x00,0x00,0x00,0x00,0xF0,0x00,0xF0,0x00,0x00,0x00, - - 5, // 0x3E '>' - 0x00,0x80,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x80, - - 5, // 0x3F '?' - 0x00,0x60,0x90,0x10,0x10,0x20,0x40,0x00,0x40,0x00, - - 5, // 0x40 '@' - 0x00,0x60,0x90,0x90,0xB0,0xB0,0x80,0x80,0x70,0x00, - - 5, // 0x41 'A' - 0x00,0x60,0x90,0x90,0x90,0xF0,0x90,0x90,0x90,0x00, - - 5, // 0x42 'B' - 0x00,0xE0,0x90,0x90,0xE0,0x90,0x90,0x90,0xE0,0x00, - - 5, // 0x43 'C' - 0x00,0x60,0x90,0x80,0x80,0x80,0x80,0x90,0x60,0x00, - - 5, // 0x44 'D' - 0x00,0xE0,0x90,0x90,0x90,0x90,0x90,0x90,0xE0,0x00, - - 5, // 0x45 'E' - 0x00,0xF0,0x80,0x80,0xF0,0x80,0x80,0x80,0xF0,0x00, - - 5, // 0x46 'F' - 0x00,0xF0,0x80,0x80,0xF0,0x80,0x80,0x80,0x80,0x00, - - 5, // 0x47 'G' - 0x00,0x60,0x90,0x80,0x80,0xB0,0x90,0x90,0x60,0x00, - - 5, // 0x48 'H' - 0x00,0x90,0x90,0x90,0x90,0xF0,0x90,0x90,0x90,0x00, - - 5, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x4A 'J' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0xA0,0x40,0x00, - - 5, // 0x4B 'K' - 0x00,0x90,0xA0,0xA0,0xC0,0xC0,0xA0,0xA0,0x90,0x00, - - 5, // 0x4C 'L' - 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xF0,0x00, - - 5, // 0x4D 'M' - 0x00,0x90,0x90,0xF0,0xF0,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x4E 'N' - 0x00,0x90,0x90,0xD0,0xD0,0xB0,0xB0,0x90,0x90,0x00, - - 5, // 0x4F 'O' - 0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x50 'P' - 0x00,0xE0,0x90,0x90,0x90,0xE0,0x80,0x80,0x80,0x00, - - 5, // 0x51 'Q' - 0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x30, - - 5, // 0x52 'R' - 0x00,0xE0,0x90,0x90,0x90,0xE0,0xA0,0x90,0x90,0x00, - - 5, // 0x53 'S' - 0x00,0x60,0x90,0x80,0x60,0x10,0x90,0x90,0x60,0x00, - - 5, // 0x54 'T' - 0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, - - 5, // 0x55 'U' - 0x00,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x56 'V' - 0x00,0x90,0x90,0x90,0x50,0x50,0x50,0x20,0x20,0x00, - - 5, // 0x57 'W' - 0x00,0x90,0x90,0x90,0x90,0x90,0xF0,0xF0,0x90,0x00, - - 5, // 0x58 'X' - 0x00,0x90,0x90,0x90,0x60,0x60,0x90,0x90,0x90,0x00, - - 5, // 0x59 'Y' - 0x00,0x88,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00, - - 5, // 0x5A 'Z' - 0x00,0xF0,0x10,0x20,0x20,0x40,0x40,0x80,0xF0,0x00, - - 5, // 0x5B '[' - 0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x60, - - 5, // 0x5C '\' - 0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08, - - 5, // 0x5D ']' - 0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x60, - - 5, // 0x5E '^' - 0x00,0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00, - - 5, // 0x60 '`' - 0x00,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x61 'a' - 0x00,0x00,0x00,0x60,0x10,0x70,0x90,0x90,0x70,0x00, - - 5, // 0x62 'b' - 0x00,0x80,0x80,0xE0,0x90,0x90,0x90,0x90,0xE0,0x00, - - 5, // 0x63 'c' - 0x00,0x00,0x00,0x60,0x90,0x80,0x80,0x90,0x60,0x00, - - 5, // 0x64 'd' - 0x00,0x10,0x10,0x70,0x90,0x90,0x90,0x90,0x70,0x00, - - 5, // 0x65 'e' - 0x00,0x00,0x00,0x60,0x90,0x90,0xF0,0x80,0x70,0x00, - - 5, // 0x66 'f' - 0x00,0x30,0x40,0xE0,0x40,0x40,0x40,0x40,0x40,0x00, - - 5, // 0x67 'g' - 0x00,0x00,0x00,0x70,0x90,0x90,0x90,0x70,0x10,0xE0, - - 5, // 0x68 'h' - 0x00,0x80,0x80,0xE0,0x90,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x69 'i' - 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x6A 'j' - 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0xC0, - - 5, // 0x6B 'k' - 0x00,0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x90,0x00, - - 5, // 0x6C 'l' - 0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00, - - 5, // 0x6D 'm' - 0x00,0x00,0x00,0x90,0xF0,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x6E 'n' - 0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0x90,0x90,0x00, - - 5, // 0x6F 'o' - 0x00,0x00,0x00,0x60,0x90,0x90,0x90,0x90,0x60,0x00, - - 5, // 0x70 'p' - 0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0xE0,0x80,0x80, - - 5, // 0x71 'q' - 0x00,0x00,0x00,0x70,0x90,0x90,0x90,0x70,0x10,0x10, - - 5, // 0x72 'r' - 0x00,0x00,0x00,0xB0,0x50,0x40,0x40,0x40,0xE0,0x00, - - 5, // 0x73 's' - 0x00,0x00,0x00,0x60,0x90,0x40,0x20,0x90,0x60,0x00, - - 5, // 0x74 't' - 0x00,0x40,0x40,0xE0,0x40,0x40,0x40,0x50,0x20,0x00, - - 5, // 0x75 'u' - 0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x90,0x70,0x00, - - 5, // 0x76 'v' - 0x00,0x00,0x00,0x90,0x90,0x50,0x50,0x20,0x20,0x00, - - 5, // 0x77 'w' - 0x00,0x00,0x00,0x90,0x90,0x90,0x90,0xF0,0x90,0x00, - - 5, // 0x78 'x' - 0x00,0x00,0x00,0x90,0x90,0x60,0x60,0x90,0x90,0x00, - - 5, // 0x79 'y' - 0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x70,0x10,0xE0, - - 5, // 0x7A 'z' - 0x00,0x00,0x00,0xF0,0x10,0x20,0x40,0x80,0xF0,0x00, - - 5, // 0x7B '{' - 0x30,0x40,0x40,0x40,0x80,0x40,0x40,0x40,0x40,0x30, - - 5, // 0x7C '|' - 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - - 5, // 0x7D '}' - 0xC0,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0xC0, - - 5, // 0x7E '~' - 0x00,0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x7F '' - 0x00,0x20,0x70,0xD8,0x88,0x88,0xF8,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs5x11_mono[] = - { - 11, 3, 32, 128-32, - 0x00,0x00,0x0C,0x00,0x18,0x00,0x24,0x00,0x30,0x00,0x3C,0x00,0x48,0x00,0x54,0x00,0x60,0x00, - 0x6C,0x00,0x78,0x00,0x84,0x00,0x90,0x00,0x9C,0x00,0xA8,0x00,0xB4,0x00,0xC0,0x00,0xCC,0x00, - 0xD8,0x00,0xE4,0x00,0xF0,0x00,0xFC,0x00,0x08,0x01,0x14,0x01,0x20,0x01,0x2C,0x01,0x38,0x01, - 0x44,0x01,0x50,0x01,0x5C,0x01,0x68,0x01,0x74,0x01,0x80,0x01,0x8C,0x01,0x98,0x01,0xA4,0x01, - 0xB0,0x01,0xBC,0x01,0xC8,0x01,0xD4,0x01,0xE0,0x01,0xEC,0x01,0xF8,0x01,0x04,0x02,0x10,0x02, - 0x1C,0x02,0x28,0x02,0x34,0x02,0x40,0x02,0x4C,0x02,0x58,0x02,0x64,0x02,0x70,0x02,0x7C,0x02, - 0x88,0x02,0x94,0x02,0xA0,0x02,0xAC,0x02,0xB8,0x02,0xC4,0x02,0xD0,0x02,0xDC,0x02,0xE8,0x02, - 0xF4,0x02,0x00,0x03,0x0C,0x03,0x18,0x03,0x24,0x03,0x30,0x03,0x3C,0x03,0x48,0x03,0x54,0x03, - 0x60,0x03,0x6C,0x03,0x78,0x03,0x84,0x03,0x90,0x03,0x9C,0x03,0xA8,0x03,0xB4,0x03,0xC0,0x03, - 0xCC,0x03,0xD8,0x03,0xE4,0x03,0xF0,0x03,0xFC,0x03,0x08,0x04,0x14,0x04,0x20,0x04,0x2C,0x04, - 0x38,0x04,0x44,0x04,0x50,0x04,0x5C,0x04,0x68,0x04,0x74,0x04, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, - - 5, // 0x22 '"' - 0x00,0x50,0x50,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x23 '#' - 0x00,0x50,0x50,0xF8,0x50,0x50,0x50,0xF8,0x50,0x50,0x00, - - 5, // 0x24 '$' - 0x00,0x40,0x60,0x90,0x80,0x60,0x10,0x90,0x60,0x20,0x00, - - 5, // 0x25 '%' - 0x00,0x00,0x90,0x90,0x20,0x20,0x40,0x40,0x90,0x90,0x00, - - 5, // 0x26 '&' - 0x00,0x40,0xA0,0xA0,0x40,0xA8,0x90,0x90,0x68,0x00,0x00, - - 5, // 0x27 ''' - 0x00,0x20,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x00,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x20,0x20,0x10, - - 5, // 0x29 ')' - 0x00,0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x20,0x20,0x40, - - 5, // 0x2A '*' - 0x00,0x00,0x90,0x60,0xF0,0x60,0x90,0x00,0x00,0x00,0x00, - - 5, // 0x2B '+' - 0x00,0x00,0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00,0x00, - - 5, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x40,0x80, - - 5, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00, - - 5, // 0x2F '/' - 0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x00, - - 5, // 0x30 '0' - 0x00,0x70,0x90,0x90,0x90,0x90,0x90,0x90,0xE0,0x00,0x00, - - 5, // 0x31 '1' - 0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 5, // 0x32 '2' - 0x00,0x60,0x90,0x90,0x10,0x20,0x40,0x80,0xF0,0x00,0x00, - - 5, // 0x33 '3' - 0x00,0x60,0x90,0x10,0x60,0x10,0x10,0x90,0x60,0x00,0x00, - - 5, // 0x34 '4' - 0x00,0x10,0x30,0x50,0x50,0x90,0xF8,0x10,0x10,0x00,0x00, - - 5, // 0x35 '5' - 0x00,0xF0,0x80,0xE0,0x90,0x10,0x10,0x90,0x60,0x00,0x00, - - 5, // 0x36 '6' - 0x00,0x60,0x90,0x80,0xE0,0x90,0x90,0x90,0x60,0x00,0x00, - - 5, // 0x37 '7' - 0x00,0xF0,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x00,0x00, - - 5, // 0x38 '8' - 0x00,0x60,0x90,0x90,0x60,0x90,0x90,0x90,0x60,0x00,0x00, - - 5, // 0x39 '9' - 0x00,0x60,0x90,0x90,0x90,0x70,0x10,0x90,0x60,0x00,0x00, - - 5, // 0x3A ':' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00, - - 5, // 0x3B ';' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x40,0x80, - - 5, // 0x3C '<' - 0x00,0x08,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x08,0x00, - - 5, // 0x3D '=' - 0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0xF0,0x00,0x00,0x00, - - 5, // 0x3E '>' - 0x00,0x80,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x80,0x00, - - 5, // 0x3F '?' - 0x00,0x60,0x90,0x10,0x10,0x20,0x40,0x00,0x40,0x00,0x00, - - 5, // 0x40 '@' - 0x00,0x60,0x90,0x90,0xB0,0xB0,0x80,0x80,0x70,0x00,0x00, - - 5, // 0x41 'A' - 0x00,0x60,0x90,0x90,0x90,0xF0,0x90,0x90,0x90,0x00,0x00, - - 5, // 0x42 'B' - 0x00,0xE0,0x90,0x90,0xE0,0x90,0x90,0x90,0xE0,0x00,0x00, - - 5, // 0x43 'C' - 0x00,0x60,0x90,0x80,0x80,0x80,0x80,0x90,0x60,0x00,0x00, - - 5, // 0x44 'D' - 0x00,0xE0,0x90,0x90,0x90,0x90,0x90,0x90,0xE0,0x00,0x00, - - 5, // 0x45 'E' - 0x00,0xF0,0x80,0x80,0xE0,0x80,0x80,0x80,0xF0,0x00,0x00, - - 5, // 0x46 'F' - 0x00,0xF0,0x80,0x80,0xE0,0x80,0x80,0x80,0x80,0x00,0x00, - - 5, // 0x47 'G' - 0x00,0x60,0x90,0x80,0x80,0xB0,0x90,0x90,0x60,0x00,0x00, - - 5, // 0x48 'H' - 0x00,0x90,0x90,0x90,0xF0,0x90,0x90,0x90,0x90,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 5, // 0x4A 'J' - 0x00,0x70,0x20,0x20,0x20,0x20,0xA0,0xA0,0x40,0x00,0x00, - - 5, // 0x4B 'K' - 0x00,0x90,0xA0,0xA0,0xC0,0xA0,0xA0,0x90,0x90,0x00,0x00, - - 5, // 0x4C 'L' - 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xF0,0x00,0x00, - - 5, // 0x4D 'M' - 0x00,0x90,0xF0,0xF0,0x90,0x90,0x90,0x90,0x90,0x00,0x00, - - 5, // 0x4E 'N' - 0x00,0x90,0x90,0xD0,0xD0,0xB0,0xB0,0x90,0x90,0x00,0x00, - - 5, // 0x4F 'O' - 0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x00,0x00, - - 5, // 0x50 'P' - 0x00,0xE0,0x90,0x90,0x90,0xE0,0x80,0x80,0x80,0x00,0x00, - - 5, // 0x51 'Q' - 0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x30,0x00, - - 5, // 0x52 'R' - 0x00,0xE0,0x90,0x90,0x90,0xE0,0xA0,0x90,0x90,0x00,0x00, - - 5, // 0x53 'S' - 0x00,0x60,0x90,0x80,0x60,0x10,0x90,0x90,0x60,0x00,0x00, - - 5, // 0x54 'T' - 0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, - - 5, // 0x55 'U' - 0x00,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x00,0x00, - - 5, // 0x56 'V' - 0x00,0x90,0x90,0x90,0x50,0x50,0x50,0x20,0x20,0x00,0x00, - - 5, // 0x57 'W' - 0x00,0x90,0x90,0x90,0x90,0x90,0xF0,0xF0,0x90,0x00,0x00, - - 5, // 0x58 'X' - 0x00,0x90,0x90,0x90,0x60,0x60,0x90,0x90,0x90,0x00,0x00, - - 5, // 0x59 'Y' - 0x00,0x88,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,0x00, - - 5, // 0x5A 'Z' - 0x00,0xF0,0x10,0x20,0x20,0x40,0x40,0x80,0xF0,0x00,0x00, - - 5, // 0x5B '[' - 0x00,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x60, - - 5, // 0x5C '\' - 0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x00, - - 5, // 0x5D ']' - 0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x60, - - 5, // 0x5E '^' - 0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00, - - 5, // 0x60 '`' - 0x00,0x40,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x61 'a' - 0x00,0x00,0x00,0x60,0x10,0x70,0x90,0x90,0x70,0x00,0x00, - - 5, // 0x62 'b' - 0x00,0x80,0x80,0xE0,0x90,0x90,0x90,0x90,0xE0,0x00,0x00, - - 5, // 0x63 'c' - 0x00,0x00,0x00,0x60,0x90,0x80,0x80,0x90,0x60,0x00,0x00, - - 5, // 0x64 'd' - 0x00,0x10,0x10,0x70,0x90,0x90,0x90,0x90,0x70,0x00,0x00, - - 5, // 0x65 'e' - 0x00,0x00,0x00,0x60,0x90,0x90,0xF0,0x80,0x70,0x00,0x00, - - 5, // 0x66 'f' - 0x00,0x30,0x40,0xE0,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 5, // 0x67 'g' - 0x00,0x00,0x00,0x70,0x90,0x90,0x90,0x90,0x70,0x10,0xE0, - - 5, // 0x68 'h' - 0x00,0x80,0x80,0xE0,0x90,0x90,0x90,0x90,0x90,0x00,0x00, - - 5, // 0x69 'i' - 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 5, // 0x6A 'j' - 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0xA0,0x40, - - 5, // 0x6B 'k' - 0x00,0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x90,0x00,0x00, - - 5, // 0x6C 'l' - 0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 5, // 0x6D 'm' - 0x00,0x00,0x00,0x90,0xF0,0x90,0x90,0x90,0x90,0x00,0x00, - - 5, // 0x6E 'n' - 0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0x90,0x90,0x00,0x00, - - 5, // 0x6F 'o' - 0x00,0x00,0x00,0x60,0x90,0x90,0x90,0x90,0x60,0x00,0x00, - - 5, // 0x70 'p' - 0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0x90,0xE0,0x80,0x80, - - 5, // 0x71 'q' - 0x00,0x00,0x00,0x70,0x90,0x90,0x90,0x90,0x70,0x10,0x10, - - 5, // 0x72 'r' - 0x00,0x00,0x00,0xA0,0x50,0x40,0x40,0x40,0xE0,0x00,0x00, - - 5, // 0x73 's' - 0x00,0x00,0x00,0x60,0x90,0x40,0x20,0x90,0x60,0x00,0x00, - - 5, // 0x74 't' - 0x00,0x40,0x40,0xE0,0x40,0x40,0x40,0x40,0x30,0x00,0x00, - - 5, // 0x75 'u' - 0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x90,0x70,0x00,0x00, - - 5, // 0x76 'v' - 0x00,0x00,0x00,0x90,0x90,0x50,0x50,0x20,0x20,0x00,0x00, - - 5, // 0x77 'w' - 0x00,0x00,0x00,0x90,0x90,0x90,0x90,0xF0,0x90,0x00,0x00, - - 5, // 0x78 'x' - 0x00,0x00,0x00,0x90,0x90,0x60,0x60,0x90,0x90,0x00,0x00, - - 5, // 0x79 'y' - 0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x90,0x70,0x10,0xE0, - - 5, // 0x7A 'z' - 0x00,0x00,0x00,0xF0,0x10,0x20,0x40,0x80,0xF0,0x00,0x00, - - 5, // 0x7B '{' - 0x30,0x40,0x40,0x40,0x40,0x80,0x40,0x40,0x40,0x40,0x30, - - 5, // 0x7C '|' - 0x00,0x20,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x20,0x00, - - 5, // 0x7D '}' - 0xC0,0x20,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0xC0, - - 5, // 0x7E '~' - 0x00,0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x7F '' - 0x00,0x20,0x70,0xD8,0x88,0x88,0xF8,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs6x10_mono[] = - { - 10, 3, 32, 128-32, - 0x00,0x00,0x0B,0x00,0x16,0x00,0x21,0x00,0x2C,0x00,0x37,0x00,0x42,0x00,0x4D,0x00,0x58,0x00, - 0x63,0x00,0x6E,0x00,0x79,0x00,0x84,0x00,0x8F,0x00,0x9A,0x00,0xA5,0x00,0xB0,0x00,0xBB,0x00, - 0xC6,0x00,0xD1,0x00,0xDC,0x00,0xE7,0x00,0xF2,0x00,0xFD,0x00,0x08,0x01,0x13,0x01,0x1E,0x01, - 0x29,0x01,0x34,0x01,0x3F,0x01,0x4A,0x01,0x55,0x01,0x60,0x01,0x6B,0x01,0x76,0x01,0x81,0x01, - 0x8C,0x01,0x97,0x01,0xA2,0x01,0xAD,0x01,0xB8,0x01,0xC3,0x01,0xCE,0x01,0xD9,0x01,0xE4,0x01, - 0xEF,0x01,0xFA,0x01,0x05,0x02,0x10,0x02,0x1B,0x02,0x26,0x02,0x31,0x02,0x3C,0x02,0x47,0x02, - 0x52,0x02,0x5D,0x02,0x68,0x02,0x73,0x02,0x7E,0x02,0x89,0x02,0x94,0x02,0x9F,0x02,0xAA,0x02, - 0xB5,0x02,0xC0,0x02,0xCB,0x02,0xD6,0x02,0xE1,0x02,0xEC,0x02,0xF7,0x02,0x02,0x03,0x0D,0x03, - 0x18,0x03,0x23,0x03,0x2E,0x03,0x39,0x03,0x44,0x03,0x4F,0x03,0x5A,0x03,0x65,0x03,0x70,0x03, - 0x7B,0x03,0x86,0x03,0x91,0x03,0x9C,0x03,0xA7,0x03,0xB2,0x03,0xBD,0x03,0xC8,0x03,0xD3,0x03, - 0xDE,0x03,0xE9,0x03,0xF4,0x03,0xFF,0x03,0x0A,0x04,0x15,0x04, - - 6, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00, - - 6, // 0x22 '"' - 0x00,0x28,0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x23 '#' - 0x00,0x28,0x28,0x7C,0x28,0x28,0x7C,0x28,0x28,0x00, - - 6, // 0x24 '$' - 0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x10,0x00, - - 6, // 0x25 '%' - 0x00,0x08,0xC8,0xD0,0x10,0x20,0x2C,0x4C,0x40,0x00, - - 6, // 0x26 '&' - 0x00,0x20,0x50,0x50,0x24,0x54,0x48,0x34,0x00,0x00, - - 6, // 0x27 ''' - 0x00,0x10,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x28 '(' - 0x08,0x10,0x10,0x20,0x20,0x20,0x10,0x10,0x08,0x00, - - 6, // 0x29 ')' - 0x20,0x10,0x10,0x08,0x08,0x08,0x10,0x10,0x20,0x00, - - 6, // 0x2A '*' - 0x00,0x00,0x28,0x7C,0x38,0x7C,0x28,0x00,0x00,0x00, - - 6, // 0x2B '+' - 0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00, - - 6, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40, - - 6, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00, - - 6, // 0x2F '/' - 0x00,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00, - - 6, // 0x30 '0' - 0x00,0x38,0x44,0x4C,0x54,0x64,0x44,0x38,0x00,0x00, - - 6, // 0x31 '1' - 0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 6, // 0x32 '2' - 0x00,0x38,0x44,0x04,0x18,0x20,0x40,0x7C,0x00,0x00, - - 6, // 0x33 '3' - 0x00,0x38,0x44,0x04,0x38,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x34 '4' - 0x00,0x08,0x18,0x28,0x48,0x7C,0x08,0x08,0x00,0x00, - - 6, // 0x35 '5' - 0x00,0x7C,0x40,0x40,0x78,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x36 '6' - 0x00,0x38,0x40,0x40,0x78,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x37 '7' - 0x00,0x7C,0x04,0x08,0x10,0x20,0x20,0x20,0x00,0x00, - - 6, // 0x38 '8' - 0x00,0x38,0x44,0x44,0x38,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x39 '9' - 0x00,0x38,0x44,0x44,0x3C,0x04,0x04,0x38,0x00,0x00, - - 6, // 0x3A ':' - 0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,0x00, - - 6, // 0x3B ';' - 0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x20,0x40, - - 6, // 0x3C '<' - 0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00, - - 6, // 0x3D '=' - 0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00, - - 6, // 0x3E '>' - 0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00, - - 6, // 0x3F '?' - 0x00,0x38,0x44,0x04,0x18,0x10,0x00,0x10,0x00,0x00, - - 6, // 0x40 '@' - 0x00,0x38,0x44,0x5C,0x54,0x5C,0x40,0x38,0x00,0x00, - - 6, // 0x41 'A' - 0x00,0x38,0x44,0x44,0x44,0x7C,0x44,0x44,0x00,0x00, - - 6, // 0x42 'B' - 0x00,0x78,0x44,0x44,0x78,0x44,0x44,0x78,0x00,0x00, - - 6, // 0x43 'C' - 0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00,0x00, - - 6, // 0x44 'D' - 0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x00,0x00, - - 6, // 0x45 'E' - 0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x7C,0x00,0x00, - - 6, // 0x46 'F' - 0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x00,0x00, - - 6, // 0x47 'G' - 0x00,0x38,0x44,0x40,0x4C,0x44,0x44,0x3C,0x00,0x00, - - 6, // 0x48 'H' - 0x00,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x49 'I' - 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 6, // 0x4A 'J' - 0x00,0x1C,0x08,0x08,0x08,0x48,0x48,0x30,0x00,0x00, - - 6, // 0x4B 'K' - 0x00,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00, - - 6, // 0x4C 'L' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,0x00, - - 6, // 0x4D 'M' - 0x00,0x44,0x6C,0x54,0x54,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x4E 'N' - 0x00,0x44,0x44,0x64,0x54,0x4C,0x44,0x44,0x00,0x00, - - 6, // 0x4F 'O' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x50 'P' - 0x00,0x78,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00, - - 6, // 0x51 'Q' - 0x00,0x38,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00, - - 6, // 0x52 'R' - 0x00,0x78,0x44,0x44,0x78,0x48,0x44,0x44,0x00,0x00, - - 6, // 0x53 'S' - 0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x54 'T' - 0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 6, // 0x55 'U' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x56 'V' - 0x00,0x44,0x44,0x44,0x44,0x28,0x28,0x10,0x00,0x00, - - 6, // 0x57 'W' - 0x00,0x44,0x44,0x54,0x54,0x54,0x54,0x28,0x00,0x00, - - 6, // 0x58 'X' - 0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00, - - 6, // 0x59 'Y' - 0x00,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x00,0x00, - - 6, // 0x5A 'Z' - 0x00,0x78,0x08,0x10,0x20,0x40,0x40,0x78,0x00,0x00, - - 6, // 0x5B '[' - 0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, - - 6, // 0x5C '\' - 0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x00, - - 6, // 0x5D ']' - 0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x38,0x00, - - 6, // 0x5E '^' - 0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00, - - 6, // 0x60 '`' - 0x00,0x10,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x61 'a' - 0x00,0x00,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00,0x00, - - 6, // 0x62 'b' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x78,0x00,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x3C,0x00,0x00, - - 6, // 0x64 'd' - 0x00,0x04,0x04,0x3C,0x44,0x44,0x44,0x3C,0x00,0x00, - - 6, // 0x65 'e' - 0x00,0x00,0x00,0x38,0x44,0x78,0x40,0x3C,0x00,0x00, - - 6, // 0x66 'f' - 0x00,0x0C,0x10,0x10,0x38,0x10,0x10,0x10,0x00,0x00, - - 6, // 0x67 'g' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x3C,0x04,0x38, - - 6, // 0x68 'h' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x69 'i' - 0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x38,0x00,0x00, - - 6, // 0x6A 'j' - 0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x48,0x30, - - 6, // 0x6B 'k' - 0x00,0x40,0x40,0x48,0x50,0x60,0x50,0x48,0x00,0x00, - - 6, // 0x6C 'l' - 0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 6, // 0x6D 'm' - 0x00,0x00,0x00,0x68,0x54,0x54,0x44,0x44,0x00,0x00, - - 6, // 0x6E 'n' - 0x00,0x00,0x00,0x58,0x64,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x6F 'o' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x70 'p' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x40, - - 6, // 0x71 'q' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x3C,0x04,0x04, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x58,0x24,0x20,0x20,0x70,0x00,0x00, - - 6, // 0x73 's' - 0x00,0x00,0x00,0x38,0x40,0x38,0x04,0x78,0x00,0x00, - - 6, // 0x74 't' - 0x00,0x10,0x10,0x38,0x10,0x10,0x14,0x08,0x00,0x00, - - 6, // 0x75 'u' - 0x00,0x00,0x00,0x44,0x44,0x44,0x4C,0x34,0x00,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x44,0x44,0x44,0x28,0x10,0x00,0x00, - - 6, // 0x77 'w' - 0x00,0x00,0x00,0x44,0x44,0x54,0x7C,0x28,0x00,0x00, - - 6, // 0x78 'x' - 0x00,0x00,0x00,0x48,0x48,0x30,0x48,0x48,0x00,0x00, - - 6, // 0x79 'y' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x3C,0x04,0x38, - - 6, // 0x7A 'z' - 0x00,0x00,0x00,0x78,0x08,0x30,0x40,0x78,0x00,0x00, - - 6, // 0x7B '{' - 0x18,0x20,0x20,0x20,0xC0,0x20,0x20,0x20,0x18,0x00, - - 6, // 0x7C '|' - 0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x00, - - 6, // 0x7D '}' - 0x60,0x10,0x10,0x10,0x0C,0x10,0x10,0x10,0x60,0x00, - - 6, // 0x7E '~' - 0x00,0x48,0xA8,0x90,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x7F '' - 0x00,0x10,0x38,0x6C,0x44,0x44,0x7C,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs6x11_mono[] = - { - 11, 3, 32, 128-32, - 0x00,0x00,0x0C,0x00,0x18,0x00,0x24,0x00,0x30,0x00,0x3C,0x00,0x48,0x00,0x54,0x00,0x60,0x00, - 0x6C,0x00,0x78,0x00,0x84,0x00,0x90,0x00,0x9C,0x00,0xA8,0x00,0xB4,0x00,0xC0,0x00,0xCC,0x00, - 0xD8,0x00,0xE4,0x00,0xF0,0x00,0xFC,0x00,0x08,0x01,0x14,0x01,0x20,0x01,0x2C,0x01,0x38,0x01, - 0x44,0x01,0x50,0x01,0x5C,0x01,0x68,0x01,0x74,0x01,0x80,0x01,0x8C,0x01,0x98,0x01,0xA4,0x01, - 0xB0,0x01,0xBC,0x01,0xC8,0x01,0xD4,0x01,0xE0,0x01,0xEC,0x01,0xF8,0x01,0x04,0x02,0x10,0x02, - 0x1C,0x02,0x28,0x02,0x34,0x02,0x40,0x02,0x4C,0x02,0x58,0x02,0x64,0x02,0x70,0x02,0x7C,0x02, - 0x88,0x02,0x94,0x02,0xA0,0x02,0xAC,0x02,0xB8,0x02,0xC4,0x02,0xD0,0x02,0xDC,0x02,0xE8,0x02, - 0xF4,0x02,0x00,0x03,0x0C,0x03,0x18,0x03,0x24,0x03,0x30,0x03,0x3C,0x03,0x48,0x03,0x54,0x03, - 0x60,0x03,0x6C,0x03,0x78,0x03,0x84,0x03,0x90,0x03,0x9C,0x03,0xA8,0x03,0xB4,0x03,0xC0,0x03, - 0xCC,0x03,0xD8,0x03,0xE4,0x03,0xF0,0x03,0xFC,0x03,0x08,0x04,0x14,0x04,0x20,0x04,0x2C,0x04, - 0x38,0x04,0x44,0x04,0x50,0x04,0x5C,0x04,0x68,0x04,0x74,0x04, - - 6, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, - - 6, // 0x22 '"' - 0x00,0x28,0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x23 '#' - 0x00,0x28,0x28,0x7C,0x28,0x28,0x7C,0x28,0x28,0x00,0x00, - - 6, // 0x24 '$' - 0x00,0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x10,0x00, - - 6, // 0x25 '%' - 0x00,0x68,0xA8,0xD0,0x10,0x20,0x2C,0x54,0x58,0x00,0x00, - - 6, // 0x26 '&' - 0x00,0x20,0x50,0x50,0x20,0x54,0x54,0x48,0x34,0x00,0x00, - - 6, // 0x27 ''' - 0x00,0x10,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x28 '(' - 0x08,0x10,0x10,0x20,0x20,0x20,0x20,0x10,0x10,0x08,0x00, - - 6, // 0x29 ')' - 0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x00, - - 6, // 0x2A '*' - 0x00,0x00,0x28,0x7C,0x38,0x7C,0x28,0x00,0x00,0x00,0x00, - - 6, // 0x2B '+' - 0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00, - - 6, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40, - - 6, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00, - - 6, // 0x2F '/' - 0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00, - - 6, // 0x30 '0' - 0x00,0x38,0x44,0x44,0x54,0x54,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x31 '1' - 0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 6, // 0x32 '2' - 0x00,0x38,0x44,0x44,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 6, // 0x33 '3' - 0x00,0x38,0x44,0x04,0x38,0x04,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x34 '4' - 0x00,0x08,0x18,0x28,0x28,0x48,0x7C,0x08,0x08,0x00,0x00, - - 6, // 0x35 '5' - 0x00,0x7C,0x40,0x78,0x44,0x04,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x36 '6' - 0x00,0x38,0x44,0x40,0x78,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x37 '7' - 0x00,0x7C,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x00,0x00, - - 6, // 0x38 '8' - 0x00,0x38,0x44,0x44,0x38,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x39 '9' - 0x00,0x38,0x44,0x44,0x3C,0x04,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x3A ':' - 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,0x00, - - 6, // 0x3B ';' - 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x20,0x40, - - 6, // 0x3C '<' - 0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00, - - 6, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00, - - 6, // 0x3E '>' - 0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00, - - 6, // 0x3F '?' - 0x00,0x38,0x44,0x04,0x08,0x10,0x10,0x00,0x10,0x00,0x00, - - 6, // 0x40 '@' - 0x00,0x38,0x44,0x5C,0x54,0x54,0x4C,0x40,0x38,0x00,0x00, - - 6, // 0x41 'A' - 0x00,0x38,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x42 'B' - 0x00,0x78,0x44,0x44,0x78,0x44,0x44,0x44,0x78,0x00,0x00, - - 6, // 0x43 'C' - 0x00,0x38,0x44,0x40,0x40,0x40,0x40,0x44,0x38,0x00,0x00, - - 6, // 0x44 'D' - 0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x48,0x70,0x00,0x00, - - 6, // 0x45 'E' - 0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x7C,0x00,0x00, - - 6, // 0x46 'F' - 0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00,0x00, - - 6, // 0x47 'G' - 0x00,0x38,0x44,0x40,0x40,0x5C,0x44,0x4C,0x34,0x00,0x00, - - 6, // 0x48 'H' - 0x00,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x49 'I' - 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 6, // 0x4A 'J' - 0x00,0x1C,0x08,0x08,0x08,0x08,0x48,0x48,0x30,0x00,0x00, - - 6, // 0x4B 'K' - 0x00,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x44,0x00,0x00, - - 6, // 0x4C 'L' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,0x00, - - 6, // 0x4D 'M' - 0x00,0x44,0x6C,0x54,0x54,0x54,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x4E 'N' - 0x00,0x44,0x64,0x64,0x54,0x54,0x4C,0x4C,0x44,0x00,0x00, - - 6, // 0x4F 'O' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x50 'P' - 0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00, - - 6, // 0x51 'Q' - 0x00,0x38,0x44,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00, - - 6, // 0x52 'R' - 0x00,0x78,0x44,0x44,0x44,0x78,0x48,0x44,0x44,0x00,0x00, - - 6, // 0x53 'S' - 0x00,0x38,0x44,0x40,0x38,0x04,0x04,0x44,0x38,0x00,0x00, - - 6, // 0x54 'T' - 0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 6, // 0x55 'U' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x56 'V' - 0x00,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x00,0x00, - - 6, // 0x57 'W' - 0x00,0x44,0x44,0x54,0x54,0x54,0x54,0x54,0x28,0x00,0x00, - - 6, // 0x58 'X' - 0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x59 'Y' - 0x00,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x00,0x00, - - 6, // 0x5A 'Z' - 0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x40,0x7C,0x00,0x00, - - 6, // 0x5B '[' - 0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, - - 6, // 0x5C '\' - 0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x00, - - 6, // 0x5D ']' - 0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x38,0x00, - - 6, // 0x5E '^' - 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00, - - 6, // 0x60 '`' - 0x00,0x20,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x61 'a' - 0x00,0x00,0x00,0x38,0x04,0x3C,0x44,0x44,0x3C,0x00,0x00, - - 6, // 0x62 'b' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x78,0x00,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x44,0x38,0x00,0x00, - - 6, // 0x64 'd' - 0x00,0x04,0x04,0x3C,0x44,0x44,0x44,0x44,0x3C,0x00,0x00, - - 6, // 0x65 'e' - 0x00,0x00,0x00,0x38,0x44,0x7C,0x40,0x44,0x38,0x00,0x00, - - 6, // 0x66 'f' - 0x00,0x0C,0x10,0x38,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 6, // 0x67 'g' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x3C,0x04,0x78, - - 6, // 0x68 'h' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x69 'i' - 0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 6, // 0x6A 'j' - 0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x50,0x20, - - 6, // 0x6B 'k' - 0x00,0x40,0x40,0x4C,0x50,0x60,0x50,0x48,0x44,0x00,0x00, - - 6, // 0x6C 'l' - 0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 6, // 0x6D 'm' - 0x00,0x00,0x00,0x68,0x54,0x54,0x54,0x44,0x44,0x00,0x00, - - 6, // 0x6E 'n' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 6, // 0x6F 'o' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 6, // 0x70 'p' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40, - - 6, // 0x71 'q' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x3C,0x04,0x04, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x58,0x24,0x20,0x20,0x20,0x70,0x00,0x00, - - 6, // 0x73 's' - 0x00,0x00,0x00,0x38,0x44,0x30,0x08,0x44,0x38,0x00,0x00, - - 6, // 0x74 't' - 0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x20,0x18,0x00,0x00, - - 6, // 0x75 'u' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x4C,0x34,0x00,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00, - - 6, // 0x77 'w' - 0x00,0x00,0x00,0x44,0x44,0x44,0x54,0x7C,0x28,0x00,0x00, - - 6, // 0x78 'x' - 0x00,0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00, - - 6, // 0x79 'y' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x3C,0x08,0x70, - - 6, // 0x7A 'z' - 0x00,0x00,0x00,0x7C,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 6, // 0x7B '{' - 0x18,0x20,0x20,0x20,0xC0,0xC0,0x20,0x20,0x20,0x18,0x00, - - 6, // 0x7C '|' - 0x00,0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x00, - - 6, // 0x7D '}' - 0x60,0x10,0x10,0x10,0x0C,0x0C,0x10,0x10,0x10,0x60,0x00, - - 6, // 0x7E '~' - 0x00,0x24,0x54,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x7F '' - 0x00,0x10,0x38,0x6C,0x44,0x44,0x7C,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs7x12_mono_high[] = - { - 12, 3, 32, 128-32, - 0x00,0x00,0x0D,0x00,0x1A,0x00,0x27,0x00,0x34,0x00,0x41,0x00,0x4E,0x00,0x5B,0x00,0x68,0x00, - 0x75,0x00,0x82,0x00,0x8F,0x00,0x9C,0x00,0xA9,0x00,0xB6,0x00,0xC3,0x00,0xD0,0x00,0xDD,0x00, - 0xEA,0x00,0xF7,0x00,0x04,0x01,0x11,0x01,0x1E,0x01,0x2B,0x01,0x38,0x01,0x45,0x01,0x52,0x01, - 0x5F,0x01,0x6C,0x01,0x79,0x01,0x86,0x01,0x93,0x01,0xA0,0x01,0xAD,0x01,0xBA,0x01,0xC7,0x01, - 0xD4,0x01,0xE1,0x01,0xEE,0x01,0xFB,0x01,0x08,0x02,0x15,0x02,0x22,0x02,0x2F,0x02,0x3C,0x02, - 0x49,0x02,0x56,0x02,0x63,0x02,0x70,0x02,0x7D,0x02,0x8A,0x02,0x97,0x02,0xA4,0x02,0xB1,0x02, - 0xBE,0x02,0xCB,0x02,0xD8,0x02,0xE5,0x02,0xF2,0x02,0xFF,0x02,0x0C,0x03,0x19,0x03,0x26,0x03, - 0x33,0x03,0x40,0x03,0x4D,0x03,0x5A,0x03,0x67,0x03,0x74,0x03,0x81,0x03,0x8E,0x03,0x9B,0x03, - 0xA8,0x03,0xB5,0x03,0xC2,0x03,0xCF,0x03,0xDC,0x03,0xE9,0x03,0xF6,0x03,0x03,0x04,0x10,0x04, - 0x1D,0x04,0x2A,0x04,0x37,0x04,0x44,0x04,0x51,0x04,0x5E,0x04,0x6B,0x04,0x78,0x04,0x85,0x04, - 0x92,0x04,0x9F,0x04,0xAC,0x04,0xB9,0x04,0xC6,0x04,0xD3,0x04, - - 7, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x21 '!' - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00, - - 7, // 0x22 '"' - 0x28,0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x23 '#' - 0x24,0x24,0x24,0x7E,0x24,0x24,0x24,0x7E,0x24,0x24,0x24,0x00, - - 7, // 0x24 '$' - 0x10,0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x10,0x10,0x00, - - 7, // 0x25 '%' - 0x32,0x54,0x64,0x08,0x08,0x10,0x10,0x26,0x2A,0x4C,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x20,0x50,0x50,0x50,0x20,0x54,0x54,0x48,0x34,0x00,0x00, - - 7, // 0x27 ''' - 0x10,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x08,0x10,0x10,0x20,0x20,0x20,0x20,0x20,0x10,0x10,0x08,0x00, - - 7, // 0x29 ')' - 0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x00, - - 7, // 0x2A '*' - 0x00,0x00,0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x00, - - 7, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40, - - 7, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00, - - 7, // 0x2F '/' - 0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,0x00, - - 7, // 0x30 '0' - 0x00,0x38,0x44,0x44,0x54,0x54,0x54,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x31 '1' - 0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x38,0x44,0x04,0x04,0x38,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x34 '4' - 0x00,0x08,0x18,0x28,0x28,0x48,0x48,0x7C,0x08,0x08,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x7C,0x40,0x40,0x78,0x44,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x38,0x44,0x40,0x78,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x37 '7' - 0x00,0x7C,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x20,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x38,0x44,0x44,0x44,0x38,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x38,0x44,0x44,0x44,0x3C,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x3A ':' - 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x30,0x30,0x00,0x00, - - 7, // 0x3B ';' - 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x30,0x30,0x20,0x40, - - 7, // 0x3C '<' - 0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, - - 7, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,0x00, - - 7, // 0x3E '>' - 0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, - - 7, // 0x3F '?' - 0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x10,0x00,0x10,0x00,0x00, - - 7, // 0x40 '@' - 0x00,0x38,0x44,0x44,0x5C,0x54,0x54,0x4C,0x40,0x38,0x00,0x00, - - 7, // 0x41 'A' - 0x00,0x38,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x78,0x44,0x44,0x44,0x78,0x44,0x44,0x44,0x78,0x00,0x00, - - 7, // 0x43 'C' - 0x00,0x38,0x44,0x40,0x40,0x40,0x40,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x44,0x48,0x70,0x00,0x00, - - 7, // 0x45 'E' - 0x00,0x7C,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x7C,0x00,0x00, - - 7, // 0x46 'F' - 0x00,0x7C,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x38,0x44,0x40,0x40,0x5C,0x44,0x44,0x4C,0x34,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0x44,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x49 'I' - 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x4A 'J' - 0x00,0x1C,0x08,0x08,0x08,0x08,0x08,0x48,0x48,0x30,0x00,0x00, - - 7, // 0x4B 'K' - 0x00,0x44,0x48,0x50,0x60,0x60,0x50,0x48,0x44,0x44,0x00,0x00, - - 7, // 0x4C 'L' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,0x00, - - 7, // 0x4D 'M' - 0x00,0x44,0x6C,0x6C,0x54,0x54,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x4E 'N' - 0x00,0x44,0x64,0x64,0x54,0x54,0x4C,0x4C,0x44,0x44,0x00,0x00, - - 7, // 0x4F 'O' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x51 'Q' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00, - - 7, // 0x52 'R' - 0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x48,0x44,0x44,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x38,0x44,0x40,0x40,0x38,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x56 'V' - 0x00,0x44,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x00,0x00, - - 7, // 0x57 'W' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x54,0x54,0x28,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x44,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x44,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x00,0x00, - - 7, // 0x5A 'Z' - 0x00,0x7C,0x04,0x04,0x08,0x10,0x20,0x40,0x40,0x7C,0x00,0x00, - - 7, // 0x5B '[' - 0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, - - 7, // 0x5C '\' - 0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x00, - - 7, // 0x5D ']' - 0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x38,0x00, - - 7, // 0x5E '^' - 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00, - - 7, // 0x60 '`' - 0x00,0x20,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x38,0x04,0x3C,0x44,0x44,0x44,0x3C,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x04,0x04,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x38,0x44,0x44,0x7C,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x66 'f' - 0x00,0x0C,0x10,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x04,0x78, - - 7, // 0x68 'h' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x69 'i' - 0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x6A 'j' - 0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x30, - - 7, // 0x6B 'k' - 0x00,0x40,0x40,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00, - - 7, // 0x6C 'l' - 0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x6D 'm' - 0x00,0x00,0x00,0x68,0x54,0x54,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x6E 'n' - 0x00,0x00,0x00,0x58,0x64,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x6F 'o' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x40,0x40, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x44,0x3C,0x04,0x04, - - 7, // 0x72 'r' - 0x00,0x00,0x00,0x58,0x24,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x74 't' - 0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x20,0x24,0x18,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x4C,0x34,0x00,0x00, - - 7, // 0x76 'v' - 0x00,0x00,0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00, - - 7, // 0x77 'w' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x54,0x54,0x28,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3C,0x08,0x70, - - 7, // 0x7A 'z' - 0x00,0x00,0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 7, // 0x7B '{' - 0x18,0x20,0x20,0x20,0x20,0xC0,0x20,0x20,0x20,0x20,0x18,0x00, - - 7, // 0x7C '|' - 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, - - 7, // 0x7D '}' - 0x60,0x10,0x10,0x10,0x10,0x0C,0x10,0x10,0x10,0x10,0x60,0x00, - - 7, // 0x7E '~' - 0x00,0x60,0x92,0x92,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x7F '' - 0x00,0x10,0x38,0x6C,0x44,0x44,0x7C,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u mcs7x12_mono_low[] = - { - 12, 4, 32, 128-32, - 0x00,0x00,0x0D,0x00,0x1A,0x00,0x27,0x00,0x34,0x00,0x41,0x00,0x4E,0x00,0x5B,0x00,0x68,0x00, - 0x75,0x00,0x82,0x00,0x8F,0x00,0x9C,0x00,0xA9,0x00,0xB6,0x00,0xC3,0x00,0xD0,0x00,0xDD,0x00, - 0xEA,0x00,0xF7,0x00,0x04,0x01,0x11,0x01,0x1E,0x01,0x2B,0x01,0x38,0x01,0x45,0x01,0x52,0x01, - 0x5F,0x01,0x6C,0x01,0x79,0x01,0x86,0x01,0x93,0x01,0xA0,0x01,0xAD,0x01,0xBA,0x01,0xC7,0x01, - 0xD4,0x01,0xE1,0x01,0xEE,0x01,0xFB,0x01,0x08,0x02,0x15,0x02,0x22,0x02,0x2F,0x02,0x3C,0x02, - 0x49,0x02,0x56,0x02,0x63,0x02,0x70,0x02,0x7D,0x02,0x8A,0x02,0x97,0x02,0xA4,0x02,0xB1,0x02, - 0xBE,0x02,0xCB,0x02,0xD8,0x02,0xE5,0x02,0xF2,0x02,0xFF,0x02,0x0C,0x03,0x19,0x03,0x26,0x03, - 0x33,0x03,0x40,0x03,0x4D,0x03,0x5A,0x03,0x67,0x03,0x74,0x03,0x81,0x03,0x8E,0x03,0x9B,0x03, - 0xA8,0x03,0xB5,0x03,0xC2,0x03,0xCF,0x03,0xDC,0x03,0xE9,0x03,0xF6,0x03,0x03,0x04,0x10,0x04, - 0x1D,0x04,0x2A,0x04,0x37,0x04,0x44,0x04,0x51,0x04,0x5E,0x04,0x6B,0x04,0x78,0x04,0x85,0x04, - 0x92,0x04,0x9F,0x04,0xAC,0x04,0xB9,0x04,0xC6,0x04,0xD3,0x04, - - 7, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x21 '!' - 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00, - - 7, // 0x22 '"' - 0x28,0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x23 '#' - 0x00,0x28,0x28,0x7C,0x28,0x28,0x28,0x7C,0x28,0x28,0x00,0x00, - - 7, // 0x24 '$' - 0x00,0x10,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x10,0x00,0x00, - - 7, // 0x25 '%' - 0x34,0x54,0x68,0x08,0x10,0x10,0x20,0x2C,0x54,0x58,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x20,0x50,0x50,0x20,0x54,0x54,0x48,0x34,0x00,0x00,0x00, - - 7, // 0x27 ''' - 0x00,0x10,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x08,0x10,0x10,0x20,0x20,0x20,0x20,0x20,0x10,0x10,0x08,0x00, - - 7, // 0x29 ')' - 0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x00, - - 7, // 0x2A '*' - 0x00,0x00,0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x00, - - 7, // 0x2B '+' - 0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00,0x00, - - 7, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40,0x00, - - 7, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x2F '/' - 0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,0x00, - - 7, // 0x30 '0' - 0x00,0x38,0x44,0x44,0x54,0x54,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x31 '1' - 0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x38,0x44,0x44,0x08,0x10,0x20,0x40,0x7C,0x00,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x38,0x44,0x04,0x38,0x04,0x04,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x34 '4' - 0x00,0x08,0x18,0x28,0x28,0x48,0x7C,0x08,0x08,0x00,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x7C,0x40,0x78,0x44,0x04,0x04,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x38,0x44,0x40,0x78,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x37 '7' - 0x00,0x7C,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x00,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x38,0x44,0x44,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x38,0x44,0x44,0x44,0x3C,0x04,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x3A ':' - 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x3B ';' - 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x20,0x40,0x00, - - 7, // 0x3C '<' - 0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, - - 7, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,0x00, - - 7, // 0x3E '>' - 0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, - - 7, // 0x3F '?' - 0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x10,0x00,0x10,0x00,0x00, - - 7, // 0x40 '@' - 0x00,0x38,0x44,0x44,0x5C,0x54,0x4C,0x40,0x38,0x00,0x00,0x00, - - 7, // 0x41 'A' - 0x00,0x38,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x78,0x44,0x44,0x78,0x44,0x44,0x44,0x78,0x00,0x00,0x00, - - 7, // 0x43 'C' - 0x00,0x38,0x44,0x40,0x40,0x40,0x40,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x48,0x70,0x00,0x00,0x00, - - 7, // 0x45 'E' - 0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x7C,0x00,0x00,0x00, - - 7, // 0x46 'F' - 0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x38,0x44,0x40,0x40,0x4C,0x44,0x4C,0x34,0x00,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x49 'I' - 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, - - 7, // 0x4A 'J' - 0x00,0x1C,0x08,0x08,0x08,0x08,0x48,0x48,0x30,0x00,0x00,0x00, - - 7, // 0x4B 'K' - 0x00,0x44,0x48,0x50,0x60,0x60,0x50,0x48,0x44,0x00,0x00,0x00, - - 7, // 0x4C 'L' - 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,0x00,0x00, - - 7, // 0x4D 'M' - 0x00,0x44,0x6C,0x54,0x54,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x4E 'N' - 0x00,0x44,0x64,0x64,0x54,0x54,0x4C,0x4C,0x44,0x00,0x00,0x00, - - 7, // 0x4F 'O' - 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x51 'Q' - 0x00,0x38,0x44,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00,0x00, - - 7, // 0x52 'R' - 0x00,0x78,0x44,0x44,0x44,0x78,0x48,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x56 'V' - 0x00,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x57 'W' - 0x00,0x44,0x44,0x44,0x44,0x44,0x54,0x54,0x28,0x00,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x5A 'Z' - 0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x40,0x7C,0x00,0x00,0x00, - - 7, // 0x5B '[' - 0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, - - 7, // 0x5C '\' - 0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x00, - - 7, // 0x5D ']' - 0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x38,0x00, - - 7, // 0x5E '^' - 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00, - - 7, // 0x60 '`' - 0x00,0x20,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x38,0x04,0x3C,0x44,0x44,0x3C,0x00,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x78,0x00,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x04,0x04,0x3C,0x44,0x44,0x44,0x44,0x3C,0x00,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x38,0x44,0x7C,0x40,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x66 'f' - 0x00,0x0C,0x10,0x38,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x3C,0x04,0x44,0x38, - - 7, // 0x68 'h' - 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x69 'i' - 0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, - - 7, // 0x6A 'j' - 0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x48,0x48,0x30, - - 7, // 0x6B 'k' - 0x00,0x40,0x40,0x4C,0x50,0x60,0x50,0x48,0x44,0x00,0x00,0x00, - - 7, // 0x6C 'l' - 0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, - - 7, // 0x6D 'm' - 0x00,0x00,0x00,0x68,0x54,0x54,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x6E 'n' - 0x00,0x00,0x00,0x58,0x64,0x44,0x44,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x6F 'o' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40,0x40, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x3C,0x04,0x04,0x04, - - 7, // 0x72 'r' - 0x00,0x00,0x00,0x58,0x24,0x20,0x20,0x20,0x70,0x00,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x38,0x44,0x30,0x08,0x44,0x38,0x00,0x00,0x00, - - 7, // 0x74 't' - 0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x24,0x18,0x00,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x4C,0x34,0x00,0x00,0x00, - - 7, // 0x76 'v' - 0x00,0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x77 'w' - 0x00,0x00,0x00,0x44,0x44,0x44,0x54,0x54,0x28,0x00,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x3C,0x04,0x08,0x70, - - 7, // 0x7A 'z' - 0x00,0x00,0x00,0x7C,0x08,0x10,0x20,0x40,0x7C,0x00,0x00,0x00, - - 7, // 0x7B '{' - 0x18,0x20,0x20,0x20,0x20,0xC0,0x20,0x20,0x20,0x20,0x18,0x00, - - 7, // 0x7C '|' - 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, - - 7, // 0x7D '}' - 0x60,0x10,0x10,0x10,0x10,0x0C,0x10,0x10,0x10,0x10,0x60,0x00, - - 7, // 0x7E '~' - 0x00,0x24,0x54,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x7F '' - 0x00,0x10,0x38,0x6C,0x44,0x44,0x7C,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana12[] = - { - 12, 3, 32, 128-32, - 0x00,0x00,0x0D,0x00,0x1A,0x00,0x27,0x00,0x34,0x00,0x41,0x00,0x5A,0x00,0x67,0x00,0x74,0x00, - 0x81,0x00,0x8E,0x00,0x9B,0x00,0xA8,0x00,0xB5,0x00,0xC2,0x00,0xCF,0x00,0xDC,0x00,0xE9,0x00, - 0xF6,0x00,0x03,0x01,0x10,0x01,0x1D,0x01,0x2A,0x01,0x37,0x01,0x44,0x01,0x51,0x01,0x5E,0x01, - 0x6B,0x01,0x78,0x01,0x85,0x01,0x92,0x01,0x9F,0x01,0xAC,0x01,0xC5,0x01,0xD2,0x01,0xDF,0x01, - 0xEC,0x01,0xF9,0x01,0x06,0x02,0x13,0x02,0x20,0x02,0x2D,0x02,0x3A,0x02,0x47,0x02,0x54,0x02, - 0x61,0x02,0x7A,0x02,0x87,0x02,0xA0,0x02,0xAD,0x02,0xC6,0x02,0xD3,0x02,0xE0,0x02,0xED,0x02, - 0xFA,0x02,0x07,0x03,0x20,0x03,0x2D,0x03,0x3A,0x03,0x47,0x03,0x54,0x03,0x61,0x03,0x6E,0x03, - 0x7B,0x03,0x88,0x03,0x95,0x03,0xA2,0x03,0xAF,0x03,0xBC,0x03,0xC9,0x03,0xD6,0x03,0xE3,0x03, - 0xF0,0x03,0xFD,0x03,0x0A,0x04,0x17,0x04,0x24,0x04,0x31,0x04,0x4A,0x04,0x57,0x04,0x64,0x04, - 0x71,0x04,0x7E,0x04,0x8B,0x04,0x98,0x04,0xA5,0x04,0xB2,0x04,0xBF,0x04,0xCC,0x04,0xD9,0x04, - 0xE6,0x04,0xF3,0x04,0x00,0x05,0x0D,0x05,0x1A,0x05,0x27,0x05, - - 3, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x21 '!' - 0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, - - 5, // 0x22 '"' - 0x00,0x00,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00,0x00, - - 7, // 0x24 '$' - 0x00,0x00,0x10,0x10,0x3C,0x50,0x30,0x18,0x14,0x78,0x10,0x10, - - 11, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x00,0x4A,0x00,0x4A,0x00,0x35,0x80,0x0A,0x40,0x0A,0x40,0x11,0x80,0x00,0x00,0x00,0x00, - - 7, // 0x26 '&' - 0x00,0x00,0x00,0x30,0x48,0x48,0x32,0x4A,0x44,0x3A,0x00,0x00, - - 3, // 0x27 ''' - 0x00,0x00,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x28 '(' - 0x00,0x00,0x10,0x20,0x40,0x40,0x40,0x40,0x40,0x40,0x20,0x10, - - 4, // 0x29 ')' - 0x00,0x00,0x80,0x40,0x20,0x20,0x20,0x20,0x20,0x20,0x40,0x80, - - 7, // 0x2A '*' - 0x00,0x10,0x54,0x38,0x54,0x10,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00, - - 3, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80,0x00, - - 5, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00, - - 3, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x00, - - 4, // 0x2F '/' - 0x00,0x00,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x80,0x00, - - 7, // 0x30 '0' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x31 '1' - 0x00,0x00,0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x38,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x00,0x00,0x38,0x44,0x04,0x08,0x10,0x20,0x7C,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x00,0x00,0x38,0x44,0x04,0x18,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x34 '4' - 0x00,0x00,0x00,0x08,0x18,0x28,0x48,0x7C,0x08,0x08,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x00,0x00,0x7C,0x40,0x78,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x00,0x00,0x18,0x20,0x40,0x78,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x37 '7' - 0x00,0x00,0x00,0x7C,0x04,0x08,0x08,0x10,0x10,0x10,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x00,0x00,0x38,0x44,0x44,0x38,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x00,0x00,0x38,0x44,0x44,0x3C,0x04,0x08,0x30,0x00,0x00, - - 4, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x00, - - 4, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x40,0x40,0x80,0x00, - - 7, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x04,0x18,0x60,0x18,0x04,0x00,0x00,0x00, - - 7, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x7C,0x00,0x00,0x00,0x00, - - 7, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x40,0x30,0x0C,0x30,0x40,0x00,0x00,0x00, - - 6, // 0x3F '?' - 0x00,0x00,0x00,0x70,0x08,0x08,0x10,0x20,0x00,0x20,0x00,0x00, - - 10, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x20,0x80,0x4E,0x80,0x52,0x80,0x52,0x80,0x4D,0x00,0x20,0x00,0x1F,0x00,0x00,0x00, - - 8, // 0x41 'A' - 0x00,0x00,0x00,0x18,0x18,0x24,0x24,0x7E,0x42,0x42,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x00,0x00,0x70,0x48,0x48,0x78,0x44,0x44,0x78,0x00,0x00, - - 8, // 0x43 'C' - 0x00,0x00,0x00,0x1C,0x22,0x40,0x40,0x40,0x22,0x1C,0x00,0x00, - - 8, // 0x44 'D' - 0x00,0x00,0x00,0x78,0x44,0x42,0x42,0x42,0x44,0x78,0x00,0x00, - - 7, // 0x45 'E' - 0x00,0x00,0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x7C,0x00,0x00, - - 6, // 0x46 'F' - 0x00,0x00,0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x00,0x00, - - 8, // 0x47 'G' - 0x00,0x00,0x00,0x1C,0x22,0x40,0x4E,0x42,0x22,0x1C,0x00,0x00, - - 8, // 0x48 'H' - 0x00,0x00,0x00,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 5, // 0x4A 'J' - 0x00,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0xE0,0x00,0x00, - - 7, // 0x4B 'K' - 0x00,0x00,0x00,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00, - - 6, // 0x4C 'L' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,0x00, - - 9, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x55,0x00,0x55,0x00,0x49,0x00,0x49,0x00,0x41,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x4E 'N' - 0x00,0x00,0x00,0x42,0x62,0x52,0x4A,0x46,0x42,0x42,0x00,0x00, - - 9, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x40,0x00,0x00, - - 9, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x04,0x00,0x03,0x00, - - 7, // 0x52 'R' - 0x00,0x00,0x00,0x78,0x44,0x44,0x78,0x50,0x48,0x44,0x00,0x00, - - 7, // 0x53 'S' - 0x00,0x00,0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0x00,0x00,0xFE,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 8, // 0x55 'U' - 0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, - - 8, // 0x56 'V' - 0x00,0x00,0x00,0x42,0x42,0x42,0x24,0x24,0x18,0x18,0x00,0x00, - - 9, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x49,0x00,0x49,0x00,0x55,0x00,0x55,0x00,0x22,0x00,0x22,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x00,0x00, - - 7, // 0x5A 'Z' - 0x00,0x00,0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 4, // 0x5B '[' - 0x00,0x00,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x60, - - 4, // 0x5C '\' - 0x00,0x00,0x80,0x80,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x00, - - 4, // 0x5D ']' - 0x00,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x60, - - 7, // 0x5E '^' - 0x00,0x00,0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, - - 6, // 0x60 '`' - 0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x30,0x08,0x38,0x48,0x38,0x00,0x00, - - 6, // 0x62 'b' - 0x00,0x00,0x40,0x40,0x40,0x70,0x48,0x48,0x48,0x70,0x00,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x38,0x40,0x40,0x40,0x38,0x00,0x00, - - 6, // 0x64 'd' - 0x00,0x00,0x08,0x08,0x08,0x38,0x48,0x48,0x48,0x38,0x00,0x00, - - 6, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x78,0x40,0x38,0x00,0x00, - - 4, // 0x66 'f' - 0x00,0x00,0x30,0x40,0x40,0xE0,0x40,0x40,0x40,0x40,0x00,0x00, - - 6, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x30, - - 6, // 0x68 'h' - 0x00,0x00,0x40,0x40,0x40,0x70,0x48,0x48,0x48,0x48,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 3, // 0x6A 'j' - 0x00,0x00,0x00,0x40,0x00,0xC0,0x40,0x40,0x40,0x40,0x40,0x80, - - 6, // 0x6B 'k' - 0x00,0x00,0x40,0x40,0x40,0x48,0x50,0x60,0x50,0x48,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 9, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x00,0x49,0x00,0x49,0x00,0x49,0x00,0x49,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x70,0x48,0x48,0x48,0x48,0x00,0x00, - - 6, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00, - - 6, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x70,0x48,0x48,0x48,0x70,0x40,0x40, - - 6, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x08, - - 4, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x50,0x60,0x40,0x40,0x40,0x00,0x00, - - 6, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x38,0x40,0x30,0x08,0x70,0x00,0x00, - - 4, // 0x74 't' - 0x00,0x00,0x00,0x00,0x40,0xF0,0x40,0x40,0x40,0x30,0x00,0x00, - - 6, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x48,0x48,0x48,0x48,0x38,0x00,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x48,0x48,0x48,0x30,0x30,0x00,0x00, - - 7, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x44,0x54,0x54,0x28,0x28,0x00,0x00, - - 6, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x48,0x48,0x30,0x48,0x48,0x00,0x00, - - 6, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x48,0x48,0x48,0x30,0x10,0x20,0x20, - - 5, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x70,0x10,0x20,0x40,0x70,0x00,0x00, - - 6, // 0x7B '{' - 0x00,0x00,0x18,0x20,0x20,0x20,0x20,0xC0,0x20,0x20,0x20,0x18, - - 5, // 0x7C '|' - 0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - - 6, // 0x7D '}' - 0x00,0x00,0x60,0x10,0x10,0x10,0x10,0x0C,0x10,0x10,0x10,0x60, - - 7, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x58,0x00,0x00,0x00,0x00, - - 9, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x7F,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana12_bold[] = - { - 12, 3, 32, 128-32, - 0x00,0x00,0x0D,0x00,0x1A,0x00,0x27,0x00,0x34,0x00,0x41,0x00,0x5A,0x00,0x67,0x00,0x74,0x00, - 0x81,0x00,0x8E,0x00,0x9B,0x00,0xA8,0x00,0xB5,0x00,0xC2,0x00,0xCF,0x00,0xDC,0x00,0xE9,0x00, - 0xF6,0x00,0x03,0x01,0x10,0x01,0x1D,0x01,0x2A,0x01,0x37,0x01,0x44,0x01,0x51,0x01,0x5E,0x01, - 0x6B,0x01,0x78,0x01,0x85,0x01,0x92,0x01,0x9F,0x01,0xAC,0x01,0xC5,0x01,0xD2,0x01,0xDF,0x01, - 0xEC,0x01,0xF9,0x01,0x06,0x02,0x13,0x02,0x20,0x02,0x2D,0x02,0x3A,0x02,0x47,0x02,0x54,0x02, - 0x61,0x02,0x6E,0x02,0x7B,0x02,0x88,0x02,0x95,0x02,0xA2,0x02,0xAF,0x02,0xBC,0x02,0xC9,0x02, - 0xD6,0x02,0xE3,0x02,0xFC,0x02,0x09,0x03,0x16,0x03,0x23,0x03,0x30,0x03,0x3D,0x03,0x4A,0x03, - 0x57,0x03,0x64,0x03,0x71,0x03,0x7E,0x03,0x8B,0x03,0x98,0x03,0xA5,0x03,0xB2,0x03,0xBF,0x03, - 0xCC,0x03,0xD9,0x03,0xE6,0x03,0xF3,0x03,0x00,0x04,0x0D,0x04,0x26,0x04,0x33,0x04,0x40,0x04, - 0x4D,0x04,0x5A,0x04,0x67,0x04,0x74,0x04,0x81,0x04,0x8E,0x04,0x9B,0x04,0xB4,0x04,0xC1,0x04, - 0xCE,0x04,0xDB,0x04,0xE8,0x04,0xF5,0x04,0x02,0x05,0x0F,0x05, - - 3, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x21 '!' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x00,0x60,0x00,0x00, - - 5, // 0x22 '"' - 0x00,0x00,0xD8,0xD8,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x23 '#' - 0x00,0x00,0x00,0x14,0x14,0x7E,0x28,0xFC,0x50,0x50,0x00,0x00, - - 6, // 0x24 '$' - 0x00,0x00,0x20,0x20,0x70,0xE8,0xE0,0x38,0xB8,0x70,0x20,0x20, - - 11, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x00,0x94,0x00,0x94,0x00,0x69,0x80,0x0A,0x40,0x0A,0x40,0x11,0x80,0x00,0x00,0x00,0x00, - - 8, // 0x26 '&' - 0x00,0x00,0x00,0x70,0xD8,0xD8,0x76,0xDC,0xCC,0x76,0x00,0x00, - - 3, // 0x27 ''' - 0x00,0x00,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x00,0x00,0x30,0x60,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x60,0x30, - - 5, // 0x29 ')' - 0x00,0x00,0xC0,0x60,0x30,0x30,0x30,0x30,0x30,0x30,0x60,0xC0, - - 6, // 0x2A '*' - 0x00,0x00,0x20,0xA8,0x70,0xA8,0x20,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00, - - 3, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x80,0x00, - - 4, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00, - - 3, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x00,0x00, - - 6, // 0x2F '/' - 0x00,0x00,0x08,0x08,0x10,0x10,0x20,0x40,0x40,0x80,0x80,0x00, - - 6, // 0x30 '0' - 0x00,0x00,0x00,0x70,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00, - - 6, // 0x31 '1' - 0x00,0x00,0x00,0x30,0x70,0x30,0x30,0x30,0x30,0x78,0x00,0x00, - - 6, // 0x32 '2' - 0x00,0x00,0x00,0x70,0x98,0x18,0x30,0x60,0xC0,0xF8,0x00,0x00, - - 6, // 0x33 '3' - 0x00,0x00,0x00,0x70,0x98,0x18,0x70,0x18,0x98,0x70,0x00,0x00, - - 6, // 0x34 '4' - 0x00,0x00,0x00,0x18,0x38,0x58,0x98,0xFC,0x18,0x18,0x00,0x00, - - 6, // 0x35 '5' - 0x00,0x00,0x00,0xF8,0xC0,0xF0,0x18,0x18,0x98,0x70,0x00,0x00, - - 6, // 0x36 '6' - 0x00,0x00,0x00,0x70,0xC0,0xF0,0xD8,0xD8,0xD8,0x70,0x00,0x00, - - 6, // 0x37 '7' - 0x00,0x00,0x00,0xF8,0x18,0x30,0x30,0x60,0x60,0xC0,0x00,0x00, - - 6, // 0x38 '8' - 0x00,0x00,0x00,0x70,0xD8,0xD8,0x70,0xD8,0xD8,0x70,0x00,0x00, - - 6, // 0x39 '9' - 0x00,0x00,0x00,0x70,0xD8,0xD8,0xD8,0x78,0x18,0x70,0x00,0x00, - - 4, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x60,0x60,0x00,0x00, - - 4, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x60,0x60,0x40,0x00, - - 8, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x04,0x18,0x60,0x60,0x18,0x04,0x00,0x00, - - 8, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x7C,0x00,0x00,0x00,0x00, - - 8, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x40,0x30,0x0C,0x0C,0x30,0x40,0x00,0x00, - - 6, // 0x3F '?' - 0x00,0x00,0x00,0xF0,0x18,0x18,0x30,0x60,0x00,0x60,0x00,0x00, - - 9, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x42,0x00,0x9D,0x00,0xA5,0x00,0xA5,0x00,0x9E,0x00,0x40,0x00,0x3C,0x00,0x00,0x00, - - 8, // 0x41 'A' - 0x00,0x00,0x00,0x38,0x38,0x6C,0x6C,0x7C,0xC6,0xC6,0x00,0x00, - - 7, // 0x42 'B' - 0x00,0x00,0x00,0xF8,0xCC,0xCC,0xF8,0xCC,0xCC,0xF8,0x00,0x00, - - 6, // 0x43 'C' - 0x00,0x00,0x00,0x70,0xC8,0xC0,0xC0,0xC0,0xC8,0x70,0x00,0x00, - - 7, // 0x44 'D' - 0x00,0x00,0x00,0xF8,0xCC,0xCC,0xCC,0xCC,0xCC,0xF8,0x00,0x00, - - 6, // 0x45 'E' - 0x00,0x00,0x00,0xF8,0xC0,0xC0,0xF8,0xC0,0xC0,0xF8,0x00,0x00, - - 6, // 0x46 'F' - 0x00,0x00,0x00,0xF8,0xC0,0xC0,0xF8,0xC0,0xC0,0xC0,0x00,0x00, - - 7, // 0x47 'G' - 0x00,0x00,0x00,0x78,0xC4,0xC0,0xC0,0xDC,0xCC,0x7C,0x00,0x00, - - 7, // 0x48 'H' - 0x00,0x00,0x00,0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0xF0,0x00,0x00, - - 5, // 0x4A 'J' - 0x00,0x00,0x00,0x70,0x30,0x30,0x30,0x30,0x30,0xE0,0x00,0x00, - - 7, // 0x4B 'K' - 0x00,0x00,0x00,0xCC,0xD8,0xF0,0xE0,0xF0,0xD8,0xCC,0x00,0x00, - - 6, // 0x4C 'L' - 0x00,0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xF8,0x00,0x00, - - 8, // 0x4D 'M' - 0x00,0x00,0x00,0x82,0xC6,0xEE,0xB6,0xB6,0x86,0x86,0x00,0x00, - - 7, // 0x4E 'N' - 0x00,0x00,0x00,0x84,0xC4,0xE4,0xB4,0x9C,0x8C,0x84,0x00,0x00, - - 8, // 0x4F 'O' - 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x00,0x00,0xF8,0xCC,0xCC,0xCC,0xF8,0xC0,0xC0,0x00,0x00, - - 8, // 0x51 'Q' - 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x18,0x0E, - - 7, // 0x52 'R' - 0x00,0x00,0x00,0xF8,0xCC,0xCC,0xF8,0xD8,0xCC,0xC6,0x00,0x00, - - 6, // 0x53 'S' - 0x00,0x00,0x00,0x70,0xC8,0xC0,0x70,0x18,0x98,0x70,0x00,0x00, - - 6, // 0x54 'T' - 0x00,0x00,0x00,0xFC,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00, - - 7, // 0x55 'U' - 0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00, - - 7, // 0x56 'V' - 0x00,0x00,0x00,0xCC,0xCC,0x78,0x78,0x78,0x30,0x30,0x00,0x00, - - 11, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0xCC,0xC0,0xCC,0xC0,0x6D,0x80,0x6D,0x80,0x73,0x80,0x33,0x00,0x33,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x58 'X' - 0x00,0x00,0x00,0xCC,0xCC,0x78,0x30,0x78,0xCC,0xCC,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x00,0x00,0xCC,0xCC,0x78,0x30,0x30,0x30,0x30,0x00,0x00, - - 6, // 0x5A 'Z' - 0x00,0x00,0x00,0xF8,0x18,0x30,0x60,0xC0,0xC0,0xF8,0x00,0x00, - - 5, // 0x5B '[' - 0x00,0x00,0x70,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x70, - - 6, // 0x5C '\' - 0x00,0x00,0x80,0x80,0x40,0x40,0x20,0x10,0x10,0x08,0x08,0x00, - - 5, // 0x5D ']' - 0x00,0x00,0x70,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x70, - - 8, // 0x5E '^' - 0x00,0x00,0x00,0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, - - 6, // 0x60 '`' - 0x00,0x00,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x70,0x18,0x78,0xD8,0x78,0x00,0x00, - - 6, // 0x62 'b' - 0x00,0x00,0xC0,0xC0,0xC0,0xF0,0xD8,0xD8,0xD8,0xF0,0x00,0x00, - - 5, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x70,0xC0,0xC0,0xC0,0x70,0x00,0x00, - - 6, // 0x64 'd' - 0x00,0x00,0x18,0x18,0x18,0x78,0xD8,0xD8,0xD8,0x78,0x00,0x00, - - 6, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x70,0xD8,0xF8,0xC0,0x78,0x00,0x00, - - 5, // 0x66 'f' - 0x00,0x00,0x38,0x60,0x60,0xF8,0x60,0x60,0x60,0x60,0x00,0x00, - - 6, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x78,0xD8,0xD8,0xD8,0x78,0x18,0x70, - - 6, // 0x68 'h' - 0x00,0x00,0xC0,0xC0,0xC0,0xF0,0xD8,0xD8,0xD8,0xD8,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x00,0x00,0xC0,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00, - - 4, // 0x6A 'j' - 0x00,0x00,0x00,0x60,0x00,0xE0,0x60,0x60,0x60,0x60,0x60,0xC0, - - 6, // 0x6B 'k' - 0x00,0x00,0xC0,0xC0,0xC0,0xD8,0xD8,0xF0,0xD8,0xD8,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00, - - 9, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF6,0x00,0xDB,0x00,0xDB,0x00,0xDB,0x00,0xDB,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0xF0,0xD8,0xD8,0xD8,0xD8,0x00,0x00, - - 6, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x70,0xD8,0xD8,0xD8,0x70,0x00,0x00, - - 6, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0xF0,0xD8,0xD8,0xD8,0xF0,0xC0,0xC0, - - 6, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x78,0xD8,0xD8,0xD8,0x78,0x18,0x18, - - 4, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0xD0,0xE0,0xC0,0xC0,0xC0,0x00,0x00, - - 5, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x70,0xC0,0xF0,0x30,0xE0,0x00,0x00, - - 5, // 0x74 't' - 0x00,0x00,0x00,0x60,0x60,0xF8,0x60,0x60,0x60,0x38,0x00,0x00, - - 6, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0xD8,0xD8,0xD8,0xD8,0x78,0x00,0x00, - - 6, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0xD8,0xD8,0xD8,0x70,0x70,0x00,0x00, - - 9, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDB,0x00,0xDB,0x00,0xDB,0x00,0x66,0x00,0x66,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0xD8,0xD8,0x70,0xD8,0xD8,0x00,0x00, - - 6, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0xD8,0xD8,0xD8,0x70,0x70,0x30,0x60, - - 5, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0xF0,0x30,0x60,0xC0,0xF0,0x00,0x00, - - 6, // 0x7B '{' - 0x00,0x00,0x18,0x30,0x30,0x30,0xE0,0x30,0x30,0x30,0x30,0x18, - - 5, // 0x7C '|' - 0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - - 6, // 0x7D '}' - 0x00,0x00,0xC0,0x60,0x60,0x60,0x38,0x60,0x60,0x60,0x60,0xC0, - - 8, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x92,0x8C,0x00,0x00,0x00, - - 9, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x7F,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana13[] = - { - 13, 3, 32, 128-32, - 0x00,0x00,0x0E,0x00,0x1C,0x00,0x2A,0x00,0x45,0x00,0x53,0x00,0x6E,0x00,0x7C,0x00,0x8A,0x00, - 0x98,0x00,0xA6,0x00,0xB4,0x00,0xCF,0x00,0xDD,0x00,0xEB,0x00,0xF9,0x00,0x07,0x01,0x15,0x01, - 0x23,0x01,0x31,0x01,0x3F,0x01,0x4D,0x01,0x5B,0x01,0x69,0x01,0x77,0x01,0x85,0x01,0x93,0x01, - 0xA1,0x01,0xAF,0x01,0xCA,0x01,0xE5,0x01,0x00,0x02,0x0E,0x02,0x29,0x02,0x37,0x02,0x45,0x02, - 0x60,0x02,0x7B,0x02,0x89,0x02,0x97,0x02,0xB2,0x02,0xC0,0x02,0xCE,0x02,0xDC,0x02,0xEA,0x02, - 0xF8,0x02,0x13,0x03,0x21,0x03,0x3C,0x03,0x4A,0x03,0x65,0x03,0x73,0x03,0x81,0x03,0x8F,0x03, - 0x9D,0x03,0xAB,0x03,0xC6,0x03,0xD4,0x03,0xE2,0x03,0xF0,0x03,0xFE,0x03,0x0C,0x04,0x1A,0x04, - 0x35,0x04,0x43,0x04,0x51,0x04,0x5F,0x04,0x6D,0x04,0x7B,0x04,0x89,0x04,0x97,0x04,0xA5,0x04, - 0xB3,0x04,0xC1,0x04,0xCF,0x04,0xDD,0x04,0xEB,0x04,0xF9,0x04,0x14,0x05,0x22,0x05,0x30,0x05, - 0x3E,0x05,0x4C,0x05,0x5A,0x05,0x68,0x05,0x76,0x05,0x84,0x05,0x92,0x05,0xAD,0x05,0xBB,0x05, - 0xC9,0x05,0xD7,0x05,0xE5,0x05,0xF3,0x05,0x01,0x06,0x1C,0x06, - - 4, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x21 '!' - 0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, - - 5, // 0x22 '"' - 0x00,0x00,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x0A,0x00,0x3F,0x00,0x14,0x00,0x14,0x00,0x7E,0x00,0x28,0x00,0x28,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x24 '$' - 0x00,0x00,0x10,0x10,0x3C,0x50,0x50,0x38,0x14,0x14,0x78,0x10,0x10, - - 12, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x00,0x49,0x00,0x4A,0x00,0x32,0x00,0x04,0xC0,0x05,0x20,0x09,0x20,0x08,0xC0,0x00,0x00,0x00,0x00, - - 8, // 0x26 '&' - 0x00,0x00,0x00,0x30,0x48,0x48,0x32,0x4A,0x44,0x46,0x39,0x00,0x00, - - 3, // 0x27 ''' - 0x00,0x00,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x00,0x00,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10, - - 5, // 0x29 ')' - 0x00,0x00,0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40, - - 7, // 0x2A '*' - 0x00,0x00,0x10,0x54,0x38,0x54,0x10,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x7F,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x40, - - 5, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00, - - 5, // 0x2F '/' - 0x00,0x00,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x00, - - 7, // 0x30 '0' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x31 '1' - 0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00, - - 7, // 0x32 '2' - 0x00,0x00,0x00,0x38,0x44,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 7, // 0x33 '3' - 0x00,0x00,0x00,0x38,0x44,0x04,0x18,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x34 '4' - 0x00,0x00,0x00,0x08,0x18,0x28,0x48,0x88,0xFC,0x08,0x08,0x00,0x00, - - 7, // 0x35 '5' - 0x00,0x00,0x00,0x7C,0x40,0x40,0x78,0x04,0x04,0x44,0x38,0x00,0x00, - - 7, // 0x36 '6' - 0x00,0x00,0x00,0x18,0x20,0x40,0x78,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x37 '7' - 0x00,0x00,0x00,0x7C,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x00,0x00, - - 7, // 0x38 '8' - 0x00,0x00,0x00,0x38,0x44,0x44,0x38,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x39 '9' - 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x3C,0x04,0x08,0x30,0x00,0x00, - - 5, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x20,0x00,0x00, - - 5, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x20,0x20,0x40, - - 9, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x18,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x0C,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x3F '?' - 0x00,0x00,0x00,0x70,0x08,0x08,0x10,0x20,0x20,0x00,0x20,0x00,0x00, - - 10, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x20,0x80,0x4E,0x80,0x52,0x80,0x52,0x80,0x52,0x80,0x4D,0x00,0x20,0x00,0x1E,0x00,0x00,0x00, - - 8, // 0x41 'A' - 0x00,0x00,0x00,0x18,0x18,0x24,0x24,0x24,0x7E,0x42,0x42,0x00,0x00, - - 8, // 0x42 'B' - 0x00,0x00,0x00,0x78,0x44,0x44,0x7C,0x42,0x42,0x42,0x7C,0x00,0x00, - - 9, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x42,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x42,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x45 'E' - 0x00,0x00,0x00,0x7C,0x40,0x40,0x7C,0x40,0x40,0x40,0x7C,0x00,0x00, - - 6, // 0x46 'F' - 0x00,0x00,0x00,0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00,0x00, - - 9, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x00,0x40,0x00,0x47,0x00,0x41,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x48 'H' - 0x00,0x00,0x00,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 5, // 0x4A 'J' - 0x00,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0xE0,0x00,0x00, - - 8, // 0x4B 'K' - 0x00,0x00,0x00,0x42,0x44,0x48,0x50,0x70,0x48,0x44,0x42,0x00,0x00, - - 6, // 0x4C 'L' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,0x00, - - 9, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x55,0x00,0x55,0x00,0x49,0x00,0x49,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x4E 'N' - 0x00,0x00,0x00,0x62,0x62,0x52,0x52,0x4A,0x4A,0x46,0x46,0x00,0x00, - - 9, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x50 'P' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00, - - 9, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x04,0x00,0x03,0x00, - - 8, // 0x52 'R' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x78,0x48,0x44,0x42,0x00,0x00, - - 8, // 0x53 'S' - 0x00,0x00,0x00,0x3C,0x42,0x40,0x30,0x0C,0x02,0x42,0x3C,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0x00,0x00,0xFE,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 8, // 0x55 'U' - 0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, - - 8, // 0x56 'V' - 0x00,0x00,0x00,0x42,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x00,0x00, - - 11, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x40,0x44,0x40,0x2A,0x80,0x2A,0x80,0x2A,0x80,0x2A,0x80,0x11,0x00,0x11,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x58 'X' - 0x00,0x00,0x00,0x42,0x42,0x24,0x18,0x18,0x24,0x42,0x42,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x00,0x00,0x82,0x44,0x28,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 8, // 0x5A 'Z' - 0x00,0x00,0x00,0x7E,0x02,0x04,0x08,0x10,0x20,0x40,0x7E,0x00,0x00, - - 5, // 0x5B '[' - 0x00,0x00,0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70, - - 5, // 0x5C '\' - 0x00,0x00,0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x00, - - 5, // 0x5D ']' - 0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70, - - 9, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x14,0x00,0x22,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE, - - 7, // 0x60 '`' - 0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x38,0x04,0x3C,0x44,0x44,0x3C,0x00,0x00, - - 7, // 0x62 'b' - 0x00,0x00,0x40,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x78,0x00,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x44,0x38,0x00,0x00, - - 7, // 0x64 'd' - 0x00,0x00,0x04,0x04,0x04,0x3C,0x44,0x44,0x44,0x44,0x3C,0x00,0x00, - - 7, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x7C,0x40,0x44,0x38,0x00,0x00, - - 4, // 0x66 'f' - 0x00,0x00,0x30,0x40,0x40,0xF0,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x3C,0x04,0x38, - - 7, // 0x68 'h' - 0x00,0x00,0x40,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x00,0x40,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 4, // 0x6A 'j' - 0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0xC0, - - 7, // 0x6B 'k' - 0x00,0x00,0x40,0x40,0x40,0x44,0x48,0x50,0x70,0x48,0x44,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 11, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7B,0x80,0x44,0x40,0x44,0x40,0x44,0x40,0x44,0x40,0x44,0x40,0x00,0x00,0x00,0x00, - - 7, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x00,0x00, - - 7, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00, - - 7, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40, - - 7, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x44,0x44,0x44,0x44,0x3C,0x04,0x04, - - 5, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x58,0x60,0x40,0x40,0x40,0x40,0x00,0x00, - - 6, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x38,0x40,0x60,0x18,0x08,0x70,0x00,0x00, - - 4, // 0x74 't' - 0x00,0x00,0x00,0x40,0x40,0xF0,0x40,0x40,0x40,0x40,0x30,0x00,0x00, - - 7, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x3C,0x00,0x00, - - 7, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00, - - 9, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,0x00,0x49,0x00,0x55,0x00,0x55,0x00,0x22,0x00,0x22,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x44,0x28,0x10,0x10,0x28,0x44,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x44,0x28,0x28,0x28,0x10,0x10,0x10,0x20, - - 6, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x78,0x08,0x10,0x20,0x40,0x78,0x00,0x00, - - 7, // 0x7B '{' - 0x00,0x00,0x0C,0x10,0x10,0x10,0x10,0x60,0x10,0x10,0x10,0x10,0x0C, - - 5, // 0x7C '|' - 0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - - 7, // 0x7D '}' - 0x00,0x00,0x60,0x10,0x10,0x10,0x10,0x0C,0x10,0x10,0x10,0x10,0x60, - - 9, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x00,0x49,0x00,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x7F,0x80,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana13_bold[] = - { - 13, 3, 32, 128-32, - 0x00,0x00,0x0E,0x00,0x1C,0x00,0x2A,0x00,0x45,0x00,0x53,0x00,0x6E,0x00,0x89,0x00,0x97,0x00, - 0xA5,0x00,0xB3,0x00,0xC1,0x00,0xDC,0x00,0xEA,0x00,0xF8,0x00,0x06,0x01,0x14,0x01,0x22,0x01, - 0x30,0x01,0x3E,0x01,0x4C,0x01,0x5A,0x01,0x68,0x01,0x76,0x01,0x84,0x01,0x92,0x01,0xA0,0x01, - 0xAE,0x01,0xBC,0x01,0xD7,0x01,0xF2,0x01,0x0D,0x02,0x1B,0x02,0x36,0x02,0x51,0x02,0x5F,0x02, - 0x6D,0x02,0x88,0x02,0x96,0x02,0xA4,0x02,0xBF,0x02,0xDA,0x02,0xE8,0x02,0xF6,0x02,0x04,0x03, - 0x12,0x03,0x2D,0x03,0x48,0x03,0x63,0x03,0x71,0x03,0x8C,0x03,0x9A,0x03,0xA8,0x03,0xB6,0x03, - 0xD1,0x03,0xDF,0x03,0xFA,0x03,0x08,0x04,0x16,0x04,0x24,0x04,0x32,0x04,0x40,0x04,0x4E,0x04, - 0x69,0x04,0x77,0x04,0x85,0x04,0x93,0x04,0xA1,0x04,0xAF,0x04,0xBD,0x04,0xCB,0x04,0xD9,0x04, - 0xE7,0x04,0xF5,0x04,0x03,0x05,0x11,0x05,0x1F,0x05,0x2D,0x05,0x48,0x05,0x56,0x05,0x64,0x05, - 0x72,0x05,0x80,0x05,0x8E,0x05,0x9C,0x05,0xAA,0x05,0xB8,0x05,0xC6,0x05,0xE1,0x05,0xEF,0x05, - 0xFD,0x05,0x0B,0x06,0x19,0x06,0x27,0x06,0x35,0x06,0x50,0x06, - - 4, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x21 '!' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x60,0x00,0x00, - - 7, // 0x22 '"' - 0x00,0x00,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x0A,0x00,0x3F,0x00,0x14,0x00,0x14,0x00,0x7E,0x00,0x28,0x00,0x28,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x24 '$' - 0x00,0x00,0x08,0x08,0x3C,0x6A,0x68,0x3C,0x16,0x56,0x3C,0x10,0x10, - - 14, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x80,0x6C,0x80,0x6D,0x00,0x6D,0x70,0x3A,0xD8,0x02,0xD8,0x04,0xD8,0x04,0x70,0x00,0x00,0x00,0x00, - - 10, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x6C,0x00,0x6C,0x00,0x39,0x80,0x6D,0x00,0x66,0x00,0x63,0x00,0x3D,0x80,0x00,0x00,0x00,0x00, - - 4, // 0x27 ''' - 0x00,0x00,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x28 '(' - 0x00,0x00,0x18,0x30,0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x30,0x18, - - 6, // 0x29 ')' - 0x00,0x00,0x60,0x30,0x30,0x18,0x18,0x18,0x18,0x18,0x30,0x30,0x60, - - 8, // 0x2A '*' - 0x00,0x00,0x10,0x54,0x38,0x54,0x10,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x7F,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x60,0x40, - - 6, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00, - - 8, // 0x2F '/' - 0x00,0x00,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x30,0x30,0x60,0x60, - - 8, // 0x30 '0' - 0x00,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00, - - 8, // 0x31 '1' - 0x00,0x00,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00, - - 8, // 0x32 '2' - 0x00,0x00,0x00,0x3C,0x66,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00,0x00, - - 8, // 0x33 '3' - 0x00,0x00,0x00,0x3C,0x66,0x06,0x1C,0x06,0x06,0x66,0x3C,0x00,0x00, - - 8, // 0x34 '4' - 0x00,0x00,0x00,0x04,0x0C,0x1C,0x2C,0x4C,0x7E,0x0C,0x0C,0x00,0x00, - - 8, // 0x35 '5' - 0x00,0x00,0x00,0x3E,0x30,0x30,0x3C,0x06,0x06,0x66,0x3C,0x00,0x00, - - 8, // 0x36 '6' - 0x00,0x00,0x00,0x1C,0x30,0x60,0x7C,0x66,0x66,0x66,0x3C,0x00,0x00, - - 8, // 0x37 '7' - 0x00,0x00,0x00,0x7E,0x06,0x0C,0x0C,0x18,0x18,0x30,0x30,0x00,0x00, - - 8, // 0x38 '8' - 0x00,0x00,0x00,0x3C,0x66,0x66,0x3C,0x66,0x66,0x66,0x3C,0x00,0x00, - - 8, // 0x39 '9' - 0x00,0x00,0x00,0x3C,0x66,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00,0x00, - - 4, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00, - - 4, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x60,0x40, - - 9, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x0C,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x00,0x06,0x00,0x18,0x00,0x60,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x3F '?' - 0x00,0x00,0x00,0x38,0x4C,0x0C,0x18,0x30,0x30,0x00,0x30,0x00,0x00, - - 11, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x20,0x40,0x4F,0x40,0x5B,0x40,0x5B,0x40,0x5B,0x40,0x4F,0x80,0x20,0x00,0x1F,0x00,0x00,0x00, - - 9, // 0x41 'A' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x1C,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x7F,0x00,0x63,0x00,0x63,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x42 'B' - 0x00,0x00,0x00,0x7C,0x66,0x66,0x7C,0x66,0x66,0x66,0x7C,0x00,0x00, - - 8, // 0x43 'C' - 0x00,0x00,0x00,0x3C,0x62,0x60,0x60,0x60,0x60,0x62,0x3C,0x00,0x00, - - 9, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x66,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x66,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x45 'E' - 0x00,0x00,0x00,0x7E,0x60,0x60,0x7E,0x60,0x60,0x60,0x7E,0x00,0x00, - - 8, // 0x46 'F' - 0x00,0x00,0x00,0x7E,0x60,0x60,0x7E,0x60,0x60,0x60,0x60,0x00,0x00, - - 9, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x61,0x00,0x60,0x00,0x60,0x00,0x67,0x00,0x63,0x00,0x63,0x00,0x3F,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7F,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x49 'I' - 0x00,0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00, - - 6, // 0x4A 'J' - 0x00,0x00,0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0xF0,0x00,0x00, - - 8, // 0x4B 'K' - 0x00,0x00,0x00,0x66,0x6C,0x78,0x70,0x70,0x78,0x6C,0x66,0x00,0x00, - - 7, // 0x4C 'L' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0x00, - - 10, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x80,0x71,0x80,0x7B,0x80,0x5D,0x80,0x49,0x80,0x41,0x80,0x41,0x80,0x41,0x80,0x00,0x00,0x00,0x00, - - 9, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x61,0x00,0x71,0x00,0x59,0x00,0x4D,0x00,0x47,0x00,0x43,0x00,0x41,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x50 'P' - 0x00,0x00,0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x00,0x00, - - 9, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x0C,0x00,0x07,0x00, - - 8, // 0x52 'R' - 0x00,0x00,0x00,0x7C,0x66,0x66,0x66,0x7C,0x6C,0x66,0x63,0x00,0x00, - - 8, // 0x53 'S' - 0x00,0x00,0x00,0x3C,0x62,0x60,0x7C,0x3E,0x06,0x46,0x3C,0x00,0x00, - - 8, // 0x54 'T' - 0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00, - - 9, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x56 'V' - 0x00,0x00,0x00,0x66,0x66,0x66,0x3C,0x3C,0x3C,0x18,0x18,0x00,0x00, - - 12, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x60,0x66,0x60,0x66,0x60,0x36,0xC0,0x3F,0xC0,0x39,0xC0,0x19,0x80,0x19,0x80,0x00,0x00,0x00,0x00, - - 8, // 0x58 'X' - 0x00,0x00,0x00,0x66,0x66,0x3C,0x18,0x18,0x3C,0x66,0x66,0x00,0x00, - - 8, // 0x59 'Y' - 0x00,0x00,0x00,0x66,0x66,0x3C,0x3C,0x18,0x18,0x18,0x18,0x00,0x00, - - 8, // 0x5A 'Z' - 0x00,0x00,0x00,0x7E,0x06,0x0E,0x1C,0x38,0x70,0x60,0x7E,0x00,0x00, - - 6, // 0x5B '[' - 0x00,0x00,0x78,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x78, - - 8, // 0x5C '\' - 0x00,0x00,0x60,0x60,0x30,0x30,0x18,0x18,0x18,0x0C,0x0C,0x06,0x06, - - 6, // 0x5D ']' - 0x00,0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x78, - - 10, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x1E,0x00,0x33,0x00,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, - - 8, // 0x60 '`' - 0x00,0x00,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3E,0x00,0x00, - - 8, // 0x62 'b' - 0x00,0x00,0x60,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x60,0x60,0x60,0x60,0x3C,0x00,0x00, - - 8, // 0x64 'd' - 0x00,0x00,0x06,0x06,0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00, - - 8, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x7E,0x60,0x62,0x3C,0x00,0x00, - - 5, // 0x66 'f' - 0x00,0x00,0x38,0x60,0x60,0xF8,0x60,0x60,0x60,0x60,0x60,0x00,0x00, - - 8, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C, - - 8, // 0x68 'h' - 0x00,0x00,0x60,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x66,0x00,0x00, - - 4, // 0x69 'i' - 0x00,0x00,0x00,0x60,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00, - - 5, // 0x6A 'j' - 0x00,0x00,0x00,0x30,0x00,0x70,0x30,0x30,0x30,0x30,0x30,0x30,0xE0, - - 8, // 0x6B 'k' - 0x00,0x00,0x60,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0x00,0x00, - - 4, // 0x6C 'l' - 0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00, - - 12, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7D,0xC0,0x66,0x60,0x66,0x60,0x66,0x60,0x66,0x60,0x66,0x60,0x00,0x00,0x00,0x00, - - 8, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x66,0x00,0x00, - - 8, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,0x00, - - 8, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x7C,0x60,0x60, - - 8, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x3E,0x06,0x06, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x6C,0x7C,0x60,0x60,0x60,0x60,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x60,0x78,0x3C,0x0C,0x78,0x00,0x00, - - 5, // 0x74 't' - 0x00,0x00,0x00,0x60,0x60,0xF8,0x60,0x60,0x60,0x60,0x38,0x00,0x00, - - 8, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3E,0x00,0x00, - - 8, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x3C,0x3C,0x18,0x00,0x00, - - 10, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x80,0x6D,0x80,0x6D,0x80,0x6D,0x80,0x33,0x00,0x33,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x3C,0x3C,0x66,0x66,0x00,0x00, - - 8, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x3C,0x3C,0x18,0x18,0x30,0x30, - - 7, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x0C,0x18,0x30,0x60,0x7C,0x00,0x00, - - 8, // 0x7B '{' - 0x00,0x00,0x0E,0x18,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E, - - 6, // 0x7C '|' - 0x00,0x00,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, - - 8, // 0x7D '}' - 0x00,0x00,0x70,0x18,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70, - - 9, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x00,0x49,0x00,0x49,0x00,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x7F,0x80,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana14[] = - { - 14, 3, 32, 128-32, - 0x00,0x00,0x0F,0x00,0x1E,0x00,0x2D,0x00,0x4A,0x00,0x59,0x00,0x76,0x00,0x93,0x00,0xA2,0x00, - 0xB1,0x00,0xC0,0x00,0xCF,0x00,0xEC,0x00,0xFB,0x00,0x0A,0x01,0x19,0x01,0x28,0x01,0x37,0x01, - 0x46,0x01,0x55,0x01,0x64,0x01,0x73,0x01,0x82,0x01,0x91,0x01,0xA0,0x01,0xAF,0x01,0xBE,0x01, - 0xCD,0x01,0xDC,0x01,0xF9,0x01,0x16,0x02,0x33,0x02,0x42,0x02,0x5F,0x02,0x6E,0x02,0x7D,0x02, - 0x9A,0x02,0xB7,0x02,0xC6,0x02,0xD5,0x02,0xF2,0x02,0x0F,0x03,0x1E,0x03,0x2D,0x03,0x3C,0x03, - 0x4B,0x03,0x68,0x03,0x85,0x03,0xA2,0x03,0xB1,0x03,0xCE,0x03,0xDD,0x03,0xEC,0x03,0xFB,0x03, - 0x18,0x04,0x27,0x04,0x44,0x04,0x53,0x04,0x62,0x04,0x71,0x04,0x80,0x04,0x8F,0x04,0x9E,0x04, - 0xBB,0x04,0xCA,0x04,0xD9,0x04,0xE8,0x04,0xF7,0x04,0x06,0x05,0x15,0x05,0x24,0x05,0x33,0x05, - 0x42,0x05,0x51,0x05,0x60,0x05,0x6F,0x05,0x7E,0x05,0x8D,0x05,0xAA,0x05,0xB9,0x05,0xC8,0x05, - 0xD7,0x05,0xE6,0x05,0xF5,0x05,0x04,0x06,0x13,0x06,0x22,0x06,0x31,0x06,0x4E,0x06,0x5D,0x06, - 0x6C,0x06,0x7B,0x06,0x8A,0x06,0x99,0x06,0xA8,0x06,0xC5,0x06, - - 4, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x21 '!' - 0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, - - 6, // 0x22 '"' - 0x00,0x00,0x48,0x48,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x09,0x00,0x12,0x00,0x3F,0x80,0x12,0x00,0x12,0x00,0x7F,0x00,0x24,0x00,0x24,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x24 '$' - 0x00,0x00,0x10,0x10,0x3E,0x50,0x50,0x30,0x1C,0x12,0x12,0x7C,0x10,0x10, - - 13, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x80,0x49,0x00,0x49,0x00,0x4A,0x00,0x32,0x60,0x02,0x90,0x04,0x90,0x04,0x90,0x08,0x60,0x00,0x00,0x00,0x00, - - 10, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x44,0x00,0x44,0x00,0x39,0x00,0x45,0x00,0x42,0x00,0x43,0x00,0x3C,0x80,0x00,0x00,0x00,0x00, - - 3, // 0x27 ''' - 0x00,0x00,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x28 '(' - 0x00,0x00,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10, - - 5, // 0x29 ')' - 0x00,0x00,0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40, - - 8, // 0x2A '*' - 0x00,0x00,0x10,0x54,0x38,0x54,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x7F,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x40, - - 5, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00, - - 5, // 0x2F '/' - 0x00,0x00,0x08,0x08,0x10,0x10,0x10,0x20,0x20,0x20,0x40,0x40,0x40,0x80, - - 8, // 0x30 '0' - 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, - - 8, // 0x31 '1' - 0x00,0x00,0x00,0x08,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00, - - 8, // 0x32 '2' - 0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x18,0x20,0x40,0x7E,0x00,0x00, - - 8, // 0x33 '3' - 0x00,0x00,0x00,0x3C,0x42,0x02,0x02,0x1C,0x02,0x02,0x42,0x3C,0x00,0x00, - - 8, // 0x34 '4' - 0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x44,0x7F,0x04,0x04,0x04,0x00,0x00, - - 8, // 0x35 '5' - 0x00,0x00,0x00,0x7E,0x40,0x40,0x7C,0x02,0x02,0x02,0x42,0x3C,0x00,0x00, - - 8, // 0x36 '6' - 0x00,0x00,0x00,0x1C,0x20,0x40,0x7C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, - - 8, // 0x37 '7' - 0x00,0x00,0x00,0x7E,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x00,0x00, - - 8, // 0x38 '8' - 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x3C,0x42,0x42,0x42,0x3C,0x00,0x00, - - 8, // 0x39 '9' - 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x3E,0x02,0x04,0x38,0x00,0x00, - - 5, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00,0x20,0x20,0x00,0x00, - - 5, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00,0x20,0x20,0x20,0x40, - - 9, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x0C,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x00,0x06,0x00,0x18,0x00,0x60,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x3F '?' - 0x00,0x00,0x00,0x38,0x44,0x04,0x04,0x08,0x10,0x10,0x00,0x10,0x00,0x00, - - 12, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0xC0,0x27,0x40,0x49,0x20,0x49,0x20,0x49,0x20,0x49,0x20,0x27,0xC0,0x30,0x00,0x0F,0x00,0x00,0x00, - - 8, // 0x41 'A' - 0x00,0x00,0x00,0x18,0x18,0x24,0x24,0x42,0x42,0x7E,0x81,0x81,0x00,0x00, - - 8, // 0x42 'B' - 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x7C,0x42,0x42,0x42,0x7C,0x00,0x00, - - 9, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x42,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x42,0x00,0x7C,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x45 'E' - 0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x7E,0x40,0x40,0x40,0x7E,0x00,0x00, - - 7, // 0x46 'F' - 0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x40,0x40,0x40,0x40,0x00,0x00, - - 9, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x00,0x40,0x00,0x47,0x00,0x41,0x00,0x41,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x7F,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, - - 5, // 0x4A 'J' - 0x00,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xE0,0x00,0x00, - - 8, // 0x4B 'K' - 0x00,0x00,0x00,0x42,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x42,0x00,0x00, - - 7, // 0x4C 'L' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7E,0x00,0x00, - - 10, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x52,0x80,0x52,0x80,0x52,0x80,0x4C,0x80,0x4C,0x80,0x40,0x80,0x40,0x80,0x00,0x00,0x00,0x00, - - 9, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x00,0x61,0x00,0x51,0x00,0x51,0x00,0x49,0x00,0x45,0x00,0x45,0x00,0x43,0x00,0x43,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x50 'P' - 0x00,0x00,0x00,0x7C,0x42,0x42,0x42,0x42,0x7C,0x40,0x40,0x40,0x00,0x00, - - 10, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x02,0x00,0x01,0x80, - - 8, // 0x52 'R' - 0x00,0x00,0x00,0x7C,0x42,0x42,0x42,0x7C,0x48,0x44,0x42,0x41,0x00,0x00, - - 8, // 0x53 'S' - 0x00,0x00,0x00,0x3C,0x42,0x40,0x40,0x3C,0x02,0x02,0x42,0x3C,0x00,0x00, - - 7, // 0x54 'T' - 0x00,0x00,0x00,0xFE,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 9, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x56 'V' - 0x00,0x00,0x00,0x81,0x81,0x42,0x42,0x42,0x24,0x24,0x18,0x18,0x00,0x00, - - 13, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x10,0x42,0x10,0x45,0x10,0x45,0x10,0x25,0x20,0x28,0xA0,0x28,0xA0,0x10,0x40,0x10,0x40,0x00,0x00,0x00,0x00, - - 8, // 0x58 'X' - 0x00,0x00,0x00,0x42,0x42,0x24,0x18,0x18,0x18,0x24,0x42,0x42,0x00,0x00, - - 7, // 0x59 'Y' - 0x00,0x00,0x00,0x82,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x10,0x00,0x00, - - 8, // 0x5A 'Z' - 0x00,0x00,0x00,0x7E,0x02,0x04,0x08,0x10,0x10,0x20,0x40,0x7E,0x00,0x00, - - 5, // 0x5B '[' - 0x00,0x00,0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70, - - 5, // 0x5C '\' - 0x00,0x00,0x80,0x80,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x08, - - 5, // 0x5D ']' - 0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70, - - 10, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x12,0x00,0x21,0x00,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, - - 8, // 0x60 '`' - 0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x02,0x02,0x3E,0x42,0x42,0x3E,0x00,0x00, - - 8, // 0x62 'b' - 0x00,0x00,0x40,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0x7C,0x00,0x00, - - 6, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00,0x00, - - 8, // 0x64 'd' - 0x00,0x00,0x02,0x02,0x02,0x3E,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00, - - 8, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x42,0x3C,0x00,0x00, - - 4, // 0x66 'f' - 0x00,0x00,0x30,0x40,0x40,0xF0,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 8, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x3E,0x42,0x42,0x42,0x42,0x46,0x3A,0x02,0x3C, - - 8, // 0x68 'h' - 0x00,0x00,0x40,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x00,0x40,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 4, // 0x6A 'j' - 0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xC0, - - 7, // 0x6B 'k' - 0x00,0x00,0x40,0x40,0x40,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 11, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7B,0x80,0x44,0x40,0x44,0x40,0x44,0x40,0x44,0x40,0x44,0x40,0x44,0x40,0x00,0x00,0x00,0x00, - - 8, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00, - - 8, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, - - 8, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x42,0x7C,0x40,0x40, - - 8, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x3E,0x42,0x42,0x42,0x42,0x46,0x3A,0x02,0x02, - - 5, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x58,0x60,0x40,0x40,0x40,0x40,0x40,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x40,0x40,0x38,0x04,0x04,0x78,0x00,0x00, - - 5, // 0x74 't' - 0x00,0x00,0x00,0x40,0x40,0xF8,0x40,0x40,0x40,0x40,0x40,0x38,0x00,0x00, - - 8, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00, - - 7, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x00,0x00, - - 11, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x40,0x44,0x40,0x2A,0x80,0x2A,0x80,0x2A,0x80,0x11,0x00,0x11,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00, - - 7, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x10,0x20, - - 7, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00, - - 8, // 0x7B '{' - 0x00,0x00,0x0C,0x10,0x10,0x10,0x10,0x60,0x10,0x10,0x10,0x10,0x10,0x0C, - - 5, // 0x7C '|' - 0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - - 8, // 0x7D '}' - 0x00,0x00,0x30,0x08,0x08,0x08,0x08,0x06,0x08,0x08,0x08,0x08,0x08,0x30, - - 10, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x80,0x4C,0x80,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3F,0xE0,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana14_bold[] = - { - 14, 3, 32, 128-32, - 0x00,0x00,0x0F,0x00,0x1E,0x00,0x2D,0x00,0x4A,0x00,0x67,0x00,0x84,0x00,0xA1,0x00,0xB0,0x00, - 0xBF,0x00,0xCE,0x00,0xEB,0x00,0x08,0x01,0x17,0x01,0x26,0x01,0x35,0x01,0x44,0x01,0x61,0x01, - 0x7E,0x01,0x9B,0x01,0xB8,0x01,0xD5,0x01,0xF2,0x01,0x0F,0x02,0x2C,0x02,0x49,0x02,0x66,0x02, - 0x75,0x02,0x84,0x02,0xA1,0x02,0xBE,0x02,0xDB,0x02,0xEA,0x02,0x07,0x03,0x24,0x03,0x41,0x03, - 0x5E,0x03,0x7B,0x03,0x8A,0x03,0x99,0x03,0xB6,0x03,0xD3,0x03,0xE2,0x03,0xF1,0x03,0x0E,0x04, - 0x1D,0x04,0x3A,0x04,0x57,0x04,0x74,0x04,0x91,0x04,0xAE,0x04,0xCB,0x04,0xE8,0x04,0xF7,0x04, - 0x14,0x05,0x31,0x05,0x4E,0x05,0x6B,0x05,0x88,0x05,0x97,0x05,0xA6,0x05,0xB5,0x05,0xC4,0x05, - 0xE1,0x05,0xFE,0x05,0x1B,0x06,0x2A,0x06,0x39,0x06,0x48,0x06,0x57,0x06,0x66,0x06,0x75,0x06, - 0x84,0x06,0x93,0x06,0xA2,0x06,0xB1,0x06,0xC0,0x06,0xCF,0x06,0xEC,0x06,0xFB,0x06,0x0A,0x07, - 0x19,0x07,0x28,0x07,0x37,0x07,0x46,0x07,0x55,0x07,0x64,0x07,0x73,0x07,0x90,0x07,0x9F,0x07, - 0xAE,0x07,0xBD,0x07,0xDA,0x07,0xE9,0x07,0x06,0x08,0x23,0x08, - - 4, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x21 '!' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x60,0x60,0x00,0x00, - - 7, // 0x22 '"' - 0x00,0x00,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x09,0x00,0x3F,0x80,0x3F,0x80,0x12,0x00,0x7F,0x00,0x7F,0x00,0x24,0x00,0x24,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x24 '$' - 0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x3E,0x00,0x69,0x00,0x68,0x00,0x7E,0x00,0x3F,0x00,0x0B,0x00,0x4B,0x00,0x3E,0x00,0x08,0x00,0x08,0x00, - - 15, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x40,0x6C,0x40,0x6C,0x80,0x6C,0xB8,0x6D,0x6C,0x3A,0x6C,0x02,0x6C,0x04,0x6C,0x04,0x38,0x00,0x00,0x00,0x00, - - 10, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x6C,0x00,0x6C,0x00,0x6C,0x00,0x39,0x80,0x6D,0x00,0x66,0x00,0x63,0x00,0x3D,0x80,0x00,0x00,0x00,0x00, - - 4, // 0x27 ''' - 0x00,0x00,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x00,0x00,0x18,0x30,0x30,0x60,0x60,0x60,0x60,0x60,0x60,0x30,0x30,0x18, - - 7, // 0x29 ')' - 0x00,0x00,0x30,0x18,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x18,0x30, - - 9, // 0x2A '*' - 0x00,0x00,0x00,0x00,0x08,0x00,0x2A,0x00,0x1C,0x00,0x1C,0x00,0x2A,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x7F,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x60,0x40, - - 6, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00, - - 8, // 0x2F '/' - 0x00,0x00,0x06,0x06,0x0C,0x0C,0x0C,0x18,0x18,0x30,0x30,0x30,0x60,0x60, - - 9, // 0x30 '0' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x31 '1' - 0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x3C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x3F,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x32 '2' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x03,0x00,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x7F,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x33 '3' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x03,0x00,0x03,0x00,0x1E,0x00,0x03,0x00,0x03,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x34 '4' - 0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0E,0x00,0x16,0x00,0x16,0x00,0x26,0x00,0x46,0x00,0x7F,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x35 '5' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x30,0x00,0x30,0x00,0x3E,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x36 '6' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x30,0x00,0x60,0x00,0x7E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x37 '7' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x38 '8' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x39 '9' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3F,0x00,0x03,0x00,0x06,0x00,0x3C,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0x00,0x00, - - 5, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x60,0x60,0x60,0x40, - - 10, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x06,0x00,0x18,0x00,0x60,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x03,0x00,0x0C,0x00,0x30,0x00,0x40,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x3F '?' - 0x00,0x00,0x00,0x38,0x4C,0x0C,0x18,0x30,0x30,0x00,0x30,0x30,0x00,0x00, - - 12, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0xC0,0x2F,0x40,0x5B,0x20,0x5B,0x20,0x5B,0x20,0x5B,0x20,0x2F,0xC0,0x30,0x00,0x0F,0x00,0x00,0x00, - - 9, // 0x41 'A' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x1C,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x7F,0x00,0x63,0x00,0x63,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x42 'B' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x66,0x00,0x66,0x00,0x66,0x00,0x7E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7E,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x31,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x31,0x00,0x1E,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x63,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x00,0x7E,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x45 'E' - 0x00,0x00,0x00,0x7E,0x60,0x60,0x60,0x7E,0x60,0x60,0x60,0x7E,0x00,0x00, - - 8, // 0x46 'F' - 0x00,0x00,0x00,0x7E,0x60,0x60,0x60,0x7E,0x60,0x60,0x60,0x60,0x00,0x00, - - 10, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x30,0x80,0x60,0x00,0x60,0x00,0x60,0x00,0x67,0x80,0x61,0x80,0x31,0x80,0x1F,0x80,0x00,0x00,0x00,0x00, - - 10, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x7F,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x00,0x00,0x00,0x00, - - 6, // 0x49 'I' - 0x00,0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00, - - 7, // 0x4A 'J' - 0x00,0x00,0x00,0x7C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xF8,0x00,0x00, - - 9, // 0x4B 'K' - 0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x66,0x00,0x6C,0x00,0x78,0x00,0x70,0x00,0x78,0x00,0x6C,0x00,0x66,0x00,0x63,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x4C 'L' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7F,0x00,0x00, - - 11, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x71,0xC0,0x71,0xC0,0x5A,0xC0,0x5A,0xC0,0x4C,0xC0,0x4C,0xC0,0x40,0xC0,0x40,0xC0,0x00,0x00,0x00,0x00, - - 10, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x80,0x70,0x80,0x58,0x80,0x58,0x80,0x4C,0x80,0x46,0x80,0x46,0x80,0x43,0x80,0x41,0x80,0x00,0x00,0x00,0x00, - - 11, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x50 'P' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7E,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x06,0x00,0x03,0xC0, - - 9, // 0x52 'R' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7E,0x00,0x6C,0x00,0x66,0x00,0x63,0x00,0x61,0x80,0x00,0x00,0x00,0x00, - - 9, // 0x53 'S' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x61,0x00,0x60,0x00,0x70,0x00,0x3E,0x00,0x07,0x00,0x03,0x00,0x43,0x00,0x3E,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x54 'T' - 0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00, - - 10, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x3F,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x56 'V' - 0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x18,0x63,0x18,0x63,0x18,0x33,0x30,0x37,0xB0,0x34,0xB0,0x1C,0xE0,0x18,0x60,0x18,0x60,0x00,0x00,0x00,0x00, - - 9, // 0x58 'X' - 0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x36,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x36,0x00,0x63,0x00,0x63,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x59 'Y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x33,0x00,0x1E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x5A 'Z' - 0x00,0x00,0x00,0x7E,0x0C,0x0C,0x18,0x18,0x30,0x30,0x60,0x7E,0x00,0x00, - - 6, // 0x5B '[' - 0x00,0x00,0x78,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x78, - - 8, // 0x5C '\' - 0x00,0x00,0x60,0x60,0x30,0x30,0x30,0x18,0x18,0x0C,0x0C,0x0C,0x06,0x06, - - 6, // 0x5D ']' - 0x00,0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x78, - - 10, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x1E,0x00,0x33,0x00,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80, - - 9, // 0x60 '`' - 0x00,0x00,0x00,0x00,0x30,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x66,0x3E,0x00,0x00, - - 8, // 0x62 'b' - 0x00,0x00,0x60,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x66,0x7C,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x62,0x60,0x60,0x60,0x62,0x3C,0x00,0x00, - - 8, // 0x64 'd' - 0x00,0x00,0x06,0x06,0x06,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x00,0x00, - - 8, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x62,0x3C,0x00,0x00, - - 5, // 0x66 'f' - 0x00,0x00,0x38,0x60,0x60,0xF8,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00, - - 8, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C, - - 8, // 0x68 'h' - 0x00,0x00,0x60,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00, - - 4, // 0x69 'i' - 0x00,0x00,0x60,0x60,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00, - - 5, // 0x6A 'j' - 0x00,0x00,0x30,0x30,0x00,0x70,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xE0, - - 8, // 0x6B 'k' - 0x00,0x00,0x60,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0x63,0x00,0x00, - - 4, // 0x6C 'l' - 0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00, - - 12, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0xC0,0x77,0x60,0x66,0x60,0x66,0x60,0x66,0x60,0x66,0x60,0x66,0x60,0x00,0x00,0x00,0x00, - - 8, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00, - - 8, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00, - - 8, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60, - - 8, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x06, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x6C,0x7C,0x60,0x60,0x60,0x60,0x60,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x3C,0x60,0x60,0x38,0x0C,0x0C,0x78,0x00,0x00, - - 5, // 0x74 't' - 0x00,0x00,0x00,0x60,0x60,0xF8,0x60,0x60,0x60,0x60,0x60,0x38,0x00,0x00, - - 8, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3E,0x00,0x00, - - 8, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x3C,0x3C,0x3C,0x18,0x00,0x00, - - 12, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x60,0x66,0x60,0x66,0x60,0x69,0x60,0x39,0xC0,0x30,0xC0,0x30,0xC0,0x00,0x00,0x00,0x00, - - 8, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00, - - 8, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x3C,0x3C,0x3C,0x18,0x18,0x30, - - 7, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x7C,0x0C,0x18,0x38,0x30,0x60,0x7C,0x00,0x00, - - 9, // 0x7B '{' - 0x00,0x00,0x00,0x00,0x0E,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x70,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x0E,0x00, - - 6, // 0x7C '|' - 0x00,0x00,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, - - 9, // 0x7D '}' - 0x00,0x00,0x00,0x00,0x38,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x07,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x38,0x00, - - 10, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x80,0x48,0x80,0x44,0x80,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3F,0xE0,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana16[] = - { - 16, 4, 32, 128-32, - 0x00,0x00,0x11,0x00,0x22,0x00,0x33,0x00,0x54,0x00,0x65,0x00,0x86,0x00,0xA7,0x00,0xB8,0x00, - 0xC9,0x00,0xDA,0x00,0xFB,0x00,0x1C,0x01,0x2D,0x01,0x3E,0x01,0x4F,0x01,0x60,0x01,0x71,0x01, - 0x82,0x01,0x93,0x01,0xA4,0x01,0xB5,0x01,0xC6,0x01,0xD7,0x01,0xE8,0x01,0xF9,0x01,0x0A,0x02, - 0x1B,0x02,0x2C,0x02,0x4D,0x02,0x6E,0x02,0x8F,0x02,0xA0,0x02,0xC1,0x02,0xE2,0x02,0xF3,0x02, - 0x14,0x03,0x35,0x03,0x46,0x03,0x57,0x03,0x78,0x03,0x99,0x03,0xAA,0x03,0xBB,0x03,0xCC,0x03, - 0xDD,0x03,0xFE,0x03,0x1F,0x04,0x40,0x04,0x51,0x04,0x72,0x04,0x93,0x04,0xB4,0x04,0xD5,0x04, - 0xF6,0x04,0x17,0x05,0x38,0x05,0x59,0x05,0x7A,0x05,0x9B,0x05,0xAC,0x05,0xBD,0x05,0xCE,0x05, - 0xEF,0x05,0x00,0x06,0x11,0x06,0x22,0x06,0x33,0x06,0x44,0x06,0x55,0x06,0x66,0x06,0x77,0x06, - 0x88,0x06,0x99,0x06,0xAA,0x06,0xBB,0x06,0xCC,0x06,0xDD,0x06,0xFE,0x06,0x0F,0x07,0x20,0x07, - 0x31,0x07,0x42,0x07,0x53,0x07,0x64,0x07,0x75,0x07,0x86,0x07,0x97,0x07,0xB8,0x07,0xC9,0x07, - 0xDA,0x07,0xEB,0x07,0xFC,0x07,0x0D,0x08,0x1E,0x08,0x3F,0x08, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x21 '!' - 0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x20,0x00,0x00,0x00, - - 5, // 0x22 '"' - 0x00,0x00,0x00,0x50,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x09,0x00,0x3F,0x80,0x12,0x00,0x12,0x00,0x7F,0x00,0x24,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x24 '$' - 0x00,0x00,0x00,0x10,0x10,0x3E,0x50,0x50,0x30,0x1C,0x12,0x12,0x7C,0x10,0x10,0x00, - - 13, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x40,0x44,0x80,0x45,0x00,0x45,0x00,0x3A,0xE0,0x05,0x10,0x05,0x10,0x09,0x10,0x10,0xE0,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x44,0x00,0x44,0x00,0x38,0x80,0x45,0x00,0x42,0x00,0x46,0x00,0x39,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 3, // 0x27 ''' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x28 '(' - 0x00,0x00,0x00,0x08,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10,0x08, - - 6, // 0x29 ')' - 0x00,0x00,0x00,0x40,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x40, - - 9, // 0x2A '*' - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x2A,0x00,0x1C,0x00,0x2A,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x7F,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x40,0x00, - - 7, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00, - - 6, // 0x2F '/' - 0x00,0x00,0x00,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x00, - - 8, // 0x30 '0' - 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,0x00, - - 8, // 0x31 '1' - 0x00,0x00,0x00,0x00,0x08,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00,0x00, - - 8, // 0x32 '2' - 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x18,0x20,0x40,0x7E,0x00,0x00,0x00, - - 8, // 0x33 '3' - 0x00,0x00,0x00,0x00,0x3C,0x42,0x02,0x02,0x1C,0x02,0x02,0x42,0x3C,0x00,0x00,0x00, - - 8, // 0x34 '4' - 0x00,0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x44,0x7F,0x04,0x04,0x04,0x00,0x00,0x00, - - 8, // 0x35 '5' - 0x00,0x00,0x00,0x00,0x3E,0x20,0x20,0x20,0x3C,0x02,0x02,0x42,0x3C,0x00,0x00,0x00, - - 8, // 0x36 '6' - 0x00,0x00,0x00,0x00,0x1C,0x20,0x40,0x7C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,0x00, - - 8, // 0x37 '7' - 0x00,0x00,0x00,0x00,0x7E,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x10,0x00,0x00,0x00, - - 8, // 0x38 '8' - 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x3C,0x42,0x42,0x42,0x3C,0x00,0x00,0x00, - - 8, // 0x39 '9' - 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x3E,0x02,0x04,0x38,0x00,0x00,0x00, - - 6, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00, - - 6, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00,0x20,0x20,0x20,0x40,0x00, - - 9, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x0C,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x00,0x06,0x00,0x18,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x3F '?' - 0x00,0x00,0x00,0x00,0x38,0x44,0x04,0x08,0x10,0x10,0x00,0x10,0x10,0x00,0x00,0x00, - - 13, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x10,0x40,0x27,0xA0,0x48,0x90,0x48,0x90,0x48,0x90,0x48,0x90,0x48,0x90,0x27,0xE0,0x10,0x00,0x0F,0x80,0x00,0x00, - - 9, // 0x41 'A' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x14,0x00,0x14,0x00,0x22,0x00,0x22,0x00,0x3E,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x42 'B' - 0x00,0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x7C,0x42,0x42,0x42,0x7C,0x00,0x00,0x00, - - 9, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x42,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x42,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x45 'E' - 0x00,0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x7E,0x40,0x40,0x40,0x7E,0x00,0x00,0x00, - - 8, // 0x46 'F' - 0x00,0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 9, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x47,0x00,0x41,0x00,0x21,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x7F,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x00,0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,0x00, - - 6, // 0x4A 'J' - 0x00,0x00,0x00,0x00,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x00, - - 8, // 0x4B 'K' - 0x00,0x00,0x00,0x00,0x42,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x42,0x00,0x00,0x00, - - 7, // 0x4C 'L' - 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7E,0x00,0x00,0x00, - - 11, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x60,0xC0,0x51,0x40,0x51,0x40,0x4A,0x40,0x4A,0x40,0x44,0x40,0x44,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x00,0x61,0x00,0x51,0x00,0x51,0x00,0x49,0x00,0x45,0x00,0x45,0x00,0x43,0x00,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x50 'P' - 0x00,0x00,0x00,0x00,0x7C,0x42,0x42,0x42,0x42,0x7C,0x40,0x40,0x40,0x00,0x00,0x00, - - 10, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x02,0x00,0x01,0x80,0x00,0x00, - - 9, // 0x52 'R' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x42,0x00,0x42,0x00,0x42,0x00,0x44,0x00,0x78,0x00,0x44,0x00,0x42,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x53 'S' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x41,0x00,0x40,0x00,0x40,0x00,0x3E,0x00,0x01,0x00,0x01,0x00,0x41,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x54 'T' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x56 'V' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x22,0x00,0x14,0x00,0x14,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x10,0x42,0x10,0x45,0x10,0x45,0x10,0x25,0x20,0x28,0xA0,0x28,0xA0,0x10,0x40,0x10,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x58 'X' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00,0x14,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x59 'Y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x22,0x00,0x22,0x00,0x14,0x00,0x14,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x5A 'Z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5B '[' - 0x00,0x00,0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, - - 6, // 0x5C '\' - 0x00,0x00,0x00,0x80,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x00, - - 6, // 0x5D ']' - 0x00,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, - - 11, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00, - - 8, // 0x60 '`' - 0x00,0x00,0x00,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x02,0x02,0x3E,0x42,0x42,0x3E,0x00,0x00,0x00, - - 8, // 0x62 'b' - 0x00,0x00,0x00,0x40,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0x7C,0x00,0x00,0x00, - - 8, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x40,0x40,0x40,0x42,0x3C,0x00,0x00,0x00, - - 8, // 0x64 'd' - 0x00,0x00,0x00,0x02,0x02,0x02,0x3E,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00,0x00, - - 8, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x42,0x3C,0x00,0x00,0x00, - - 6, // 0x66 'f' - 0x00,0x00,0x00,0x1C,0x20,0x20,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00, - - 8, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x42,0x42,0x42,0x42,0x46,0x3A,0x02,0x02,0x3C, - - 8, // 0x68 'h' - 0x00,0x00,0x00,0x40,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x00,0x00,0x40,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 4, // 0x6A 'j' - 0x00,0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xC0, - - 7, // 0x6B 'k' - 0x00,0x00,0x00,0x40,0x40,0x40,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 11, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x80,0x66,0x40,0x44,0x40,0x44,0x40,0x44,0x40,0x44,0x40,0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00, - - 8, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,0x00, - - 8, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x42,0x7C,0x40,0x40,0x40, - - 8, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x42,0x42,0x42,0x42,0x46,0x3A,0x02,0x02,0x02, - - 5, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x60,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 7, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x40,0x40,0x38,0x04,0x04,0x78,0x00,0x00,0x00, - - 6, // 0x74 't' - 0x00,0x00,0x00,0x00,0x20,0x20,0x78,0x20,0x20,0x20,0x20,0x20,0x18,0x00,0x00,0x00, - - 8, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00,0x00, - - 8, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x00,0x00,0x00, - - 11, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x40,0x44,0x40,0x2A,0x80,0x2A,0x80,0x2A,0x80,0x11,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00,0x00, - - 8, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x10,0x10,0x20, - - 7, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x04,0x08,0x10,0x20,0x40,0x7C,0x00,0x00,0x00, - - 8, // 0x7B '{' - 0x00,0x00,0x00,0x0C,0x10,0x10,0x10,0x10,0x60,0x10,0x10,0x10,0x10,0x10,0x0C,0x00, - - 7, // 0x7C '|' - 0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, - - 8, // 0x7D '}' - 0x00,0x00,0x00,0x30,0x08,0x08,0x08,0x08,0x06,0x08,0x08,0x08,0x08,0x08,0x30,0x00, - - 11, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x80,0x4C,0x80,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xF0,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x3F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana16_bold[] = - { - 16, 4, 32, 128-32, - 0x00,0x00,0x11,0x00,0x22,0x00,0x33,0x00,0x54,0x00,0x75,0x00,0xA6,0x00,0xC7,0x00,0xD8,0x00, - 0xE9,0x00,0xFA,0x00,0x1B,0x01,0x3C,0x01,0x4D,0x01,0x5E,0x01,0x6F,0x01,0x90,0x01,0xB1,0x01, - 0xD2,0x01,0xF3,0x01,0x14,0x02,0x35,0x02,0x56,0x02,0x77,0x02,0x98,0x02,0xB9,0x02,0xDA,0x02, - 0xEB,0x02,0xFC,0x02,0x1D,0x03,0x3E,0x03,0x5F,0x03,0x70,0x03,0x91,0x03,0xB2,0x03,0xD3,0x03, - 0xF4,0x03,0x15,0x04,0x36,0x04,0x57,0x04,0x78,0x04,0x99,0x04,0xAA,0x04,0xBB,0x04,0xDC,0x04, - 0xED,0x04,0x0E,0x05,0x2F,0x05,0x50,0x05,0x71,0x05,0x92,0x05,0xB3,0x05,0xD4,0x05,0xE5,0x05, - 0x06,0x06,0x27,0x06,0x48,0x06,0x69,0x06,0x8A,0x06,0xAB,0x06,0xBC,0x06,0xDD,0x06,0xEE,0x06, - 0x0F,0x07,0x30,0x07,0x51,0x07,0x72,0x07,0x93,0x07,0xA4,0x07,0xC5,0x07,0xE6,0x07,0xF7,0x07, - 0x18,0x08,0x39,0x08,0x4A,0x08,0x5B,0x08,0x6C,0x08,0x7D,0x08,0x9E,0x08,0xBF,0x08,0xE0,0x08, - 0x01,0x09,0x22,0x09,0x33,0x09,0x44,0x09,0x55,0x09,0x76,0x09,0x97,0x09,0xB8,0x09,0xD9,0x09, - 0xFA,0x09,0x0B,0x0A,0x2C,0x0A,0x3D,0x0A,0x5E,0x0A,0x7F,0x0A, - - 4, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00, - - 7, // 0x22 '"' - 0x00,0x00,0x00,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x09,0x00,0x3F,0x80,0x3F,0x80,0x12,0x00,0x7F,0x00,0x7F,0x00,0x24,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x24 '$' - 0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x3E,0x00,0x69,0x00,0x68,0x00,0x78,0x00,0x3E,0x00,0x0F,0x00,0x0B,0x00,0x4B,0x00,0x3E,0x00,0x08,0x00,0x08,0x00,0x00,0x00, - - 17, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x20,0x00,0x66,0x20,0x00,0x66,0x40,0x00,0x66,0x5E,0x00,0x66,0xB3,0x00,0x3D,0x33,0x00,0x01,0x33,0x00,0x02,0x33,0x00,0x02,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x66,0x00,0x66,0x00,0x66,0xC0,0x3C,0xC0,0x66,0x80,0x63,0x00,0x63,0x80,0x3C,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x27 ''' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x00,0x00,0x00,0x0C,0x18,0x30,0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x30,0x18,0x0C, - - 7, // 0x29 ')' - 0x00,0x00,0x00,0x60,0x30,0x18,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x18,0x30,0x60, - - 9, // 0x2A '*' - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x49,0x00,0x2A,0x00,0x1C,0x00,0x2A,0x00,0x49,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x3F,0x80,0x04,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x60,0x60,0xC0,0xC0, - - 7, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, - - 9, // 0x2F '/' - 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x60,0x00,0x00,0x00, - - 9, // 0x30 '0' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x31 '1' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x3C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x32 '2' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x33 '3' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x03,0x00,0x0E,0x00,0x03,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x34 '4' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0E,0x00,0x16,0x00,0x26,0x00,0x46,0x00,0x7F,0x80,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x35 '5' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x30,0x00,0x30,0x00,0x3E,0x00,0x03,0x00,0x03,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x36 '6' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x30,0x00,0x60,0x00,0x7E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x37 '7' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x38 '8' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x39 '9' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3F,0x00,0x03,0x00,0x06,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, - - 5, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x38,0x30,0x30,0x60,0x60, - - 11, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x0C,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x80,0x00,0x00,0x00,0x00,0x3F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x18,0x00,0x06,0x00,0x01,0x80,0x00,0x40,0x01,0x80,0x06,0x00,0x18,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x3F '?' - 0x00,0x00,0x00,0x00,0x3C,0x66,0x06,0x0C,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00, - - 13, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x30,0x60,0x27,0xA0,0x4D,0x90,0x4D,0x90,0x4D,0x90,0x4D,0x90,0x27,0xE0,0x30,0x00,0x0F,0x80,0x00,0x00,0x00,0x00, - - 10, // 0x41 'A' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x0C,0x00,0x1E,0x00,0x1E,0x00,0x33,0x00,0x33,0x00,0x7F,0x80,0x61,0x80,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x42 'B' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7F,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x61,0x80,0x60,0x00,0x60,0x00,0x60,0x00,0x61,0x80,0x31,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x63,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x45 'E' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x46 'F' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x61,0x80,0x60,0x00,0x60,0x00,0x63,0x80,0x61,0x80,0x31,0x80,0x1F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x7F,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x49 'I' - 0x00,0x00,0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00, - - 7, // 0x4A 'J' - 0x00,0x00,0x00,0x00,0x7C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xF8,0x00,0x00,0x00, - - 9, // 0x4B 'K' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x66,0x00,0x6C,0x00,0x78,0x00,0x78,0x00,0x6C,0x00,0x66,0x00,0x63,0x00,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x4C 'L' - 0x00,0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7F,0x00,0x00,0x00, - - 12, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xE0,0x70,0xE0,0x59,0x60,0x59,0x60,0x4E,0x60,0x4E,0x60,0x44,0x60,0x44,0x60,0x40,0x60,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x80,0x70,0x80,0x58,0x80,0x58,0x80,0x4C,0x80,0x46,0x80,0x46,0x80,0x43,0x80,0x43,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x50 'P' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7E,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x03,0x00,0x01,0xC0,0x00,0x00, - - 9, // 0x52 'R' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7E,0x00,0x6C,0x00,0x66,0x00,0x63,0x00,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x53 'S' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x70,0x00,0x3E,0x00,0x07,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x54 'T' - 0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00, - - 10, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x56 'V' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x00,0x33,0x00,0x1E,0x00,0x1E,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x18,0x63,0x18,0x63,0x18,0x33,0x30,0x37,0xB0,0x34,0xB0,0x1C,0xE0,0x18,0x60,0x18,0x60,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x58 'X' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x33,0x00,0x33,0x00,0x1E,0x00,0x0C,0x00,0x1E,0x00,0x33,0x00,0x33,0x00,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x59 'Y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x33,0x00,0x1E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x5A 'Z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5B '[' - 0x00,0x00,0x00,0x78,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x78,0x00, - - 9, // 0x5C '\' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x06,0x00,0x06,0x00,0x03,0x00,0x03,0x00,0x00,0x00, - - 6, // 0x5D ']' - 0x00,0x00,0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x00, - - 10, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x1E,0x00,0x33,0x00,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,0x00,0x00, - - 9, // 0x60 '`' - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x3F,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x62 'b' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x6E,0x00,0x73,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00, - - 9, // 0x64 'd' - 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x3F,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x67,0x00,0x3B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x7F,0x00,0x60,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x66 'f' - 0x00,0x00,0x00,0x38,0x60,0x60,0xF8,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 9, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x67,0x00,0x3B,0x00,0x03,0x00,0x03,0x00,0x3E,0x00, - - 9, // 0x68 'h' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x6E,0x00,0x73,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x69 'i' - 0x00,0x00,0x00,0x60,0x60,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 5, // 0x6A 'j' - 0x00,0x00,0x00,0x30,0x30,0x00,0x70,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xE0, - - 8, // 0x6B 'k' - 0x00,0x00,0x00,0x60,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0x63,0x00,0x00,0x00, - - 4, // 0x6C 'l' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 14, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x70,0x73,0x98,0x63,0x18,0x63,0x18,0x63,0x18,0x63,0x18,0x63,0x18,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x00,0x73,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x00,0x73,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x7E,0x00,0x60,0x00,0x60,0x00,0x60,0x00, - - 9, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x67,0x00,0x3B,0x00,0x03,0x00,0x03,0x00,0x03,0x00, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x7C,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 8, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x60,0x70,0x3C,0x0E,0x06,0x7C,0x00,0x00,0x00, - - 6, // 0x74 't' - 0x00,0x00,0x00,0x00,0x60,0x60,0xF8,0x60,0x60,0x60,0x60,0x60,0x38,0x00,0x00,0x00, - - 9, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x67,0x00,0x3B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x36,0x00,0x36,0x00,0x1C,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x60,0x66,0x60,0x66,0x60,0x69,0x60,0x39,0xC0,0x30,0xC0,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x36,0x00,0x1C,0x00,0x36,0x00,0x63,0x00,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x36,0x00,0x36,0x00,0x1C,0x00,0x1C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00, - - 8, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00,0x00,0x00, - - 9, // 0x7B '{' - 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x70,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x07,0x00,0x00,0x00, - - 8, // 0x7C '|' - 0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00, - - 9, // 0x7D '}' - 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x07,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x70,0x00,0x00,0x00, - - 11, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x40,0x44,0x40,0x44,0x40,0x43,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xF0,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x3F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana17[] = - { - 17, 4, 32, 128-32, - 0x00,0x00,0x12,0x00,0x24,0x00,0x36,0x00,0x59,0x00,0x7C,0x00,0x9F,0x00,0xC2,0x00,0xD4,0x00, - 0xE6,0x00,0xF8,0x00,0x1B,0x01,0x3E,0x01,0x50,0x01,0x62,0x01,0x74,0x01,0x86,0x01,0xA9,0x01, - 0xCC,0x01,0xEF,0x01,0x12,0x02,0x35,0x02,0x58,0x02,0x7B,0x02,0x9E,0x02,0xC1,0x02,0xE4,0x02, - 0xF6,0x02,0x08,0x03,0x2B,0x03,0x4E,0x03,0x71,0x03,0x83,0x03,0xA6,0x03,0xC9,0x03,0xEC,0x03, - 0x0F,0x04,0x32,0x04,0x55,0x04,0x67,0x04,0x8A,0x04,0xAD,0x04,0xBF,0x04,0xD1,0x04,0xF4,0x04, - 0x06,0x05,0x29,0x05,0x4C,0x05,0x6F,0x05,0x81,0x05,0xA4,0x05,0xC7,0x05,0xEA,0x05,0x0D,0x06, - 0x30,0x06,0x53,0x06,0x76,0x06,0x99,0x06,0xBC,0x06,0xDF,0x06,0xF1,0x06,0x03,0x07,0x15,0x07, - 0x38,0x07,0x5B,0x07,0x7E,0x07,0x90,0x07,0xB3,0x07,0xC5,0x07,0xE8,0x07,0xFA,0x07,0x0C,0x08, - 0x2F,0x08,0x52,0x08,0x64,0x08,0x76,0x08,0x88,0x08,0x9A,0x08,0xBD,0x08,0xE0,0x08,0x03,0x09, - 0x26,0x09,0x49,0x09,0x5B,0x09,0x6D,0x09,0x7F,0x09,0xA2,0x09,0xB4,0x09,0xD7,0x09,0xFA,0x09, - 0x0C,0x0A,0x1E,0x0A,0x41,0x0A,0x53,0x0A,0x76,0x0A,0x99,0x0A, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x20,0x00,0x00,0x00, - - 6, // 0x22 '"' - 0x00,0x00,0x00,0x48,0x48,0x48,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x80,0x04,0x80,0x09,0x00,0x3F,0xC0,0x09,0x00,0x12,0x00,0x7F,0x80,0x12,0x00,0x24,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x24 '$' - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x3E,0x00,0x49,0x00,0x48,0x00,0x48,0x00,0x3E,0x00,0x09,0x00,0x09,0x00,0x49,0x00,0x3E,0x00,0x08,0x00,0x08,0x00,0x00,0x00, - - 15, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x20,0x44,0x40,0x44,0x80,0x44,0x80,0x45,0x38,0x39,0x44,0x02,0x44,0x04,0x44,0x04,0x44,0x08,0x38,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x42,0x00,0x42,0x00,0x44,0x00,0x38,0x80,0x44,0x80,0x42,0x80,0x41,0x00,0x22,0x80,0x1C,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x27 ''' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x28 '(' - 0x00,0x00,0x00,0x08,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10,0x08, - - 6, // 0x29 ')' - 0x00,0x00,0x00,0x40,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x40, - - 9, // 0x2A '*' - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x49,0x00,0x2A,0x00,0x1C,0x00,0x2A,0x00,0x49,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x7F,0xC0,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x40,0x00, - - 7, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00, - - 6, // 0x2F '/' - 0x00,0x00,0x00,0x04,0x08,0x08,0x08,0x10,0x10,0x20,0x20,0x20,0x40,0x40,0x80,0x80,0x00, - - 9, // 0x30 '0' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x31 '1' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x38,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x32 '2' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x41,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x0C,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x33 '3' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x41,0x00,0x01,0x00,0x02,0x00,0x1C,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0x42,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x34 '4' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x06,0x00,0x0A,0x00,0x12,0x00,0x22,0x00,0x42,0x00,0x7F,0x80,0x02,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x35 '5' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x7C,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0x42,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x36 '6' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x30,0x00,0x20,0x00,0x40,0x00,0x7C,0x00,0x42,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x37 '7' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x04,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x10,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x38 '8' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x3E,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x39 '9' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x21,0x00,0x1F,0x00,0x01,0x00,0x02,0x00,0x06,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00, - - 6, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x40,0x00, - - 11, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x06,0x00,0x18,0x00,0x60,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xC0,0x00,0x00,0x00,0x00,0x3F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0xC0,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x3F '?' - 0x00,0x00,0x00,0x00,0x3C,0x42,0x02,0x02,0x0C,0x10,0x10,0x00,0x10,0x10,0x00,0x00,0x00, - - 14, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x18,0x20,0x20,0x10,0x27,0xC8,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x27,0xF0,0x20,0x00,0x18,0x00,0x07,0xC0,0x00,0x00, - - 10, // 0x41 'A' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x12,0x00,0x12,0x00,0x21,0x00,0x21,0x00,0x21,0x00,0x7F,0x80,0x40,0x80,0x80,0x40,0x80,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x42 'B' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x7E,0x00,0x41,0x00,0x40,0x80,0x40,0x80,0x41,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0x80,0x20,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x30,0x80,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x41,0x80,0x40,0x80,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x41,0x80,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x45 'E' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x7F,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x46 'F' - 0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x7E,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 11, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0xC0,0x20,0x40,0x40,0x00,0x40,0x00,0x43,0xC0,0x40,0x40,0x20,0x40,0x30,0x40,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x7F,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x00,0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,0x00, - - 6, // 0x4A 'J' - 0x00,0x00,0x00,0x00,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x00, - - 10, // 0x4B 'K' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x42,0x00,0x44,0x00,0x48,0x00,0x50,0x00,0x68,0x00,0x44,0x00,0x42,0x00,0x41,0x00,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x4C 'L' - 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7F,0x00,0x00,0x00, - - 11, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x60,0xC0,0x51,0x40,0x51,0x40,0x4A,0x40,0x4A,0x40,0x44,0x40,0x44,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x80,0x60,0x80,0x50,0x80,0x48,0x80,0x48,0x80,0x44,0x80,0x44,0x80,0x42,0x80,0x41,0x80,0x41,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x31,0x80,0x20,0x80,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x20,0x80,0x31,0x80,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x50 'P' - 0x00,0x00,0x00,0x00,0x7C,0x42,0x41,0x41,0x42,0x7C,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 11, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x31,0x80,0x20,0x80,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x20,0x80,0x31,0x80,0x0E,0x00,0x02,0x00,0x02,0x00,0x01,0xC0, - - 10, // 0x52 'R' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x42,0x00,0x42,0x00,0x42,0x00,0x44,0x00,0x78,0x00,0x44,0x00,0x42,0x00,0x41,0x00,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x53 'S' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x20,0x80,0x40,0x00,0x40,0x00,0x38,0x00,0x07,0x00,0x00,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x54 'T' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x56 'V' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x80,0x40,0x40,0x80,0x40,0x80,0x21,0x00,0x21,0x00,0x21,0x00,0x12,0x00,0x12,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 15, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x04,0x41,0x04,0x22,0x88,0x22,0x88,0x22,0x88,0x14,0x50,0x14,0x50,0x14,0x50,0x08,0x20,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x58 'X' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x21,0x00,0x12,0x00,0x12,0x00,0x0C,0x00,0x0C,0x00,0x12,0x00,0x12,0x00,0x21,0x00,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x59 'Y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x41,0x00,0x22,0x00,0x22,0x00,0x14,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x5A 'Z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x00,0x80,0x01,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x5B '[' - 0x00,0x00,0x00,0x3C,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3C, - - 6, // 0x5C '\' - 0x00,0x00,0x00,0x80,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x08,0x08,0x04,0x00, - - 6, // 0x5D ']' - 0x00,0x00,0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x78, - - 11, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,0x00,0x00, - - 9, // 0x60 '`' - 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x02,0x3E,0x42,0x42,0x46,0x3A,0x00,0x00,0x00, - - 9, // 0x62 'b' - 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x5C,0x00,0x62,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x42,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x40,0x40,0x40,0x40,0x22,0x1C,0x00,0x00,0x00, - - 9, // 0x64 'd' - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x1F,0x00,0x21,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x23,0x00,0x1D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x24,0x42,0x7E,0x40,0x40,0x22,0x1C,0x00,0x00,0x00, - - 6, // 0x66 'f' - 0x00,0x00,0x00,0x1C,0x20,0x20,0x7C,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00, - - 9, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x21,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x23,0x00,0x1D,0x00,0x01,0x00,0x22,0x00,0x1C,0x00, - - 9, // 0x68 'h' - 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x5E,0x00,0x61,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 5, // 0x6A 'j' - 0x00,0x00,0x00,0x00,0x10,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xE0, - - 8, // 0x6B 'k' - 0x00,0x00,0x00,0x40,0x40,0x40,0x42,0x44,0x48,0x50,0x70,0x48,0x44,0x42,0x00,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 13, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0xE0,0x63,0x10,0x42,0x10,0x42,0x10,0x42,0x10,0x42,0x10,0x42,0x10,0x42,0x10,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5E,0x00,0x61,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x00,0x62,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x42,0x00,0x7C,0x00,0x40,0x00,0x40,0x00,0x40,0x00, - - 9, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x21,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x23,0x00,0x1D,0x00,0x01,0x00,0x01,0x00,0x01,0x00, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 8, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x40,0x30,0x0C,0x02,0x42,0x3C,0x00,0x00,0x00, - - 6, // 0x74 't' - 0x00,0x00,0x00,0x00,0x20,0x20,0x7C,0x20,0x20,0x20,0x20,0x20,0x20,0x1C,0x00,0x00,0x00, - - 9, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x43,0x00,0x3D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x18,0x00,0x00,0x00, - - 11, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x40,0x44,0x40,0x2A,0x80,0x2A,0x80,0x2A,0x80,0x2A,0x80,0x11,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00,0x08,0x00,0x14,0x00,0x22,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x18,0x10,0x10,0x20, - - 8, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x02,0x04,0x08,0x10,0x20,0x40,0x7E,0x00,0x00,0x00, - - 9, // 0x7B '{' - 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x60,0x00,0x10,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x07,0x00, - - 6, // 0x7C '|' - 0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - - 9, // 0x7D '}' - 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x04,0x00,0x03,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x70,0x00, - - 11, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x40,0x44,0x40,0x44,0x40,0x43,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana17_bold[] = - { - 17, 4, 32, 128-32, - 0x00,0x00,0x12,0x00,0x24,0x00,0x36,0x00,0x59,0x00,0x7C,0x00,0xB0,0x00,0xD3,0x00,0xE5,0x00, - 0xF7,0x00,0x09,0x01,0x2C,0x01,0x4F,0x01,0x61,0x01,0x73,0x01,0x85,0x01,0xA8,0x01,0xCB,0x01, - 0xEE,0x01,0x11,0x02,0x34,0x02,0x57,0x02,0x7A,0x02,0x9D,0x02,0xC0,0x02,0xE3,0x02,0x06,0x03, - 0x18,0x03,0x2A,0x03,0x4D,0x03,0x70,0x03,0x93,0x03,0xB6,0x03,0xD9,0x03,0xFC,0x03,0x1F,0x04, - 0x42,0x04,0x65,0x04,0x88,0x04,0xAB,0x04,0xCE,0x04,0xF1,0x04,0x03,0x05,0x15,0x05,0x38,0x05, - 0x5B,0x05,0x7E,0x05,0xA1,0x05,0xC4,0x05,0xE7,0x05,0x0A,0x06,0x2D,0x06,0x50,0x06,0x73,0x06, - 0x96,0x06,0xB9,0x06,0xDC,0x06,0xFF,0x06,0x22,0x07,0x45,0x07,0x57,0x07,0x7A,0x07,0x8C,0x07, - 0xAF,0x07,0xD2,0x07,0xF5,0x07,0x18,0x08,0x3B,0x08,0x4D,0x08,0x70,0x08,0x93,0x08,0xA5,0x08, - 0xC8,0x08,0xEB,0x08,0xFD,0x08,0x0F,0x09,0x32,0x09,0x44,0x09,0x67,0x09,0x8A,0x09,0xAD,0x09, - 0xD0,0x09,0xF3,0x09,0x05,0x0A,0x17,0x0A,0x29,0x0A,0x4C,0x0A,0x6F,0x0A,0x92,0x0A,0xB5,0x0A, - 0xD8,0x0A,0xEA,0x0A,0x0D,0x0B,0x1F,0x0B,0x42,0x0B,0x65,0x0B, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00, - - 8, // 0x22 '"' - 0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x40,0x04,0x40,0x3F,0xE0,0x3F,0xE0,0x08,0x80,0x11,0x00,0x7F,0xC0,0x7F,0xC0,0x22,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x24 '$' - 0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x1F,0x00,0x34,0x80,0x64,0x00,0x74,0x00,0x3C,0x00,0x0F,0x00,0x0B,0x80,0x09,0x80,0x4B,0x00,0x3E,0x00,0x08,0x00,0x08,0x00,0x00,0x00, - - 18, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x08,0x00,0x66,0x10,0x00,0x66,0x20,0x00,0x66,0x2F,0x00,0x66,0x59,0x80,0x66,0x99,0x80,0x3D,0x19,0x80,0x01,0x19,0x80,0x02,0x19,0x80,0x04,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x33,0x00,0x33,0x00,0x36,0x00,0x1C,0x60,0x36,0x60,0x63,0x60,0x61,0xC0,0x31,0xC0,0x1F,0x60,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x27 ''' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x28 '(' - 0x00,0x00,0x00,0x0C,0x18,0x30,0x30,0x60,0x60,0x60,0x60,0x60,0x60,0x30,0x30,0x18,0x0C, - - 8, // 0x29 ')' - 0x00,0x00,0x00,0x30,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x30, - - 10, // 0x2A '*' - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x49,0x00,0x2A,0x00,0x1C,0x00,0x2A,0x00,0x49,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x7F,0xC0,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x60,0x60,0xC0,0xC0,0x00, - - 7, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x00, - - 10, // 0x2F '/' - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x60,0x00,0x00,0x00, - - 10, // 0x30 '0' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x33,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x31 '1' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x3C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x32 '2' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x61,0x80,0x61,0x80,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x33 '3' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x61,0x80,0x61,0x80,0x01,0x80,0x0F,0x00,0x03,0x00,0x01,0x80,0x61,0x80,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x34 '4' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x07,0x00,0x0B,0x00,0x13,0x00,0x23,0x00,0x43,0x00,0x7F,0xC0,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x35 '5' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x80,0x30,0x00,0x30,0x00,0x3E,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x61,0x80,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x36 '6' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x38,0x00,0x30,0x00,0x6E,0x00,0x73,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x37 '7' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x38 '8' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x3F,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x39 '9' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x33,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x80,0x1D,0x80,0x03,0x00,0x07,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x00, - - 6, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x38,0x30,0x30,0x60,0x60,0x00, - - 12, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x80,0x00,0x40,0x01,0x80,0x06,0x00,0x18,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3F '?' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x18,0x20,0x20,0x10,0x27,0xC8,0x4C,0xC8,0x4C,0xC8,0x4C,0xC8,0x4C,0xC8,0x27,0xF0,0x20,0x00,0x18,0x00,0x07,0xC0,0x00,0x00, - - 11, // 0x41 'A' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x1B,0x00,0x1B,0x00,0x31,0x80,0x3F,0x80,0x31,0x80,0x60,0xC0,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x42 'B' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x7F,0x00,0x61,0x80,0x60,0xC0,0x60,0xC0,0x61,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x30,0xC0,0x30,0xC0,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x30,0xC0,0x30,0xC0,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x61,0x80,0x61,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x61,0x80,0x61,0x80,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x45 'E' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x80,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x46 'F' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x30,0xC0,0x30,0xC0,0x60,0x00,0x60,0x00,0x63,0xC0,0x60,0xC0,0x30,0xC0,0x30,0xC0,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x7F,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x49 'I' - 0x00,0x00,0x00,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00, - - 8, // 0x4A 'J' - 0x00,0x00,0x00,0x00,0x3E,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0xF8,0x00,0x00,0x00, - - 11, // 0x4B 'K' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x61,0x80,0x63,0x00,0x66,0x00,0x6C,0x00,0x7C,0x00,0x76,0x00,0x63,0x00,0x61,0x80,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x4C 'L' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x70,0x70,0x70,0x70,0xF0,0x58,0xB0,0x59,0xB0,0x4D,0x30,0x4F,0x30,0x46,0x30,0x46,0x30,0x40,0x30,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x40,0x70,0x40,0x58,0x40,0x4C,0x40,0x4C,0x40,0x46,0x40,0x43,0x40,0x43,0x40,0x41,0xC0,0x40,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0xC0,0x30,0xC0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x30,0xC0,0x30,0xC0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x50 'P' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x63,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x00,0x7E,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0xC0,0x30,0xC0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x30,0xC0,0x30,0xC0,0x0F,0x80,0x03,0x00,0x03,0x00,0x01,0xE0, - - 11, // 0x52 'R' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x61,0x80,0x60,0xC0,0x60,0xC0,0x61,0x80,0x7F,0x00,0x63,0x00,0x61,0x80,0x60,0xC0,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x53 'S' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x61,0x80,0x60,0x00,0x3E,0x00,0x1F,0x00,0x01,0x80,0x61,0x80,0x63,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x54 'T' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x56 'V' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x31,0x80,0x31,0x80,0x1B,0x00,0x1B,0x00,0x0E,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 16, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x86,0x61,0x86,0x63,0xC6,0x32,0x4C,0x36,0x6C,0x36,0x6C,0x34,0x2C,0x1C,0x38,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x58 'X' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x31,0x80,0x31,0x80,0x1B,0x00,0x0E,0x00,0x0E,0x00,0x1B,0x00,0x31,0x80,0x31,0x80,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x59 'Y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x61,0x80,0x61,0x80,0x33,0x00,0x1E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x5A 'Z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x5B '[' - 0x00,0x00,0x00,0x3E,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3E, - - 10, // 0x5C '\' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x06,0x00,0x03,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x00,0x00, - - 8, // 0x5D ']' - 0x00,0x00,0x00,0x7C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x7C, - - 12, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x0E,0x00,0x1B,0x00,0x31,0x80,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xC0,0x00,0x00, - - 10, // 0x60 '`' - 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x03,0x00,0x3F,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x62 'b' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x6E,0x00,0x73,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x33,0x60,0x60,0x60,0x60,0x33,0x1E,0x00,0x00,0x00, - - 10, // 0x64 'd' - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0x80,0x31,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x80,0x1D,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x33,0x00,0x63,0x00,0x7F,0x00,0x60,0x00,0x60,0x00,0x33,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x66 'f' - 0x00,0x00,0x00,0x1C,0x30,0x30,0x7C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00, - - 10, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x31,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x80,0x1D,0x80,0x01,0x80,0x03,0x00,0x3E,0x00, - - 10, // 0x68 'h' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x6F,0x00,0x71,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x69 'i' - 0x00,0x00,0x00,0x60,0x60,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 6, // 0x6A 'j' - 0x00,0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF0, - - 9, // 0x6B 'k' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x63,0x00,0x66,0x00,0x6C,0x00,0x78,0x00,0x7C,0x00,0x66,0x00,0x63,0x00,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x6C 'l' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 14, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x70,0x73,0x98,0x63,0x18,0x63,0x18,0x63,0x18,0x63,0x18,0x63,0x18,0x63,0x18,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6F,0x00,0x71,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x33,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x00,0x73,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x00,0x7E,0x00,0x60,0x00,0x60,0x00,0x60,0x00, - - 10, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x31,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x80,0x1D,0x80,0x01,0x80,0x01,0x80,0x01,0x80, - - 7, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x7E,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 8, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x62,0x60,0x7C,0x3E,0x06,0x46,0x3C,0x00,0x00,0x00, - - 6, // 0x74 't' - 0x00,0x00,0x00,0x00,0x60,0x60,0xFC,0x60,0x60,0x60,0x60,0x60,0x60,0x3C,0x00,0x00,0x00, - - 10, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x80,0x3D,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x1C,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x18,0x63,0x18,0x33,0x30,0x37,0xB0,0x34,0xB0,0x1C,0xE0,0x1C,0xE0,0x0C,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x36,0x00,0x1C,0x00,0x1C,0x00,0x36,0x00,0x63,0x00,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x00,0x63,0x00,0x63,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x1C,0x00,0x1C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00, - - 8, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x06,0x0C,0x18,0x18,0x30,0x60,0x7E,0x00,0x00,0x00, - - 10, // 0x7B '{' - 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x70,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x07,0x80, - - 8, // 0x7C '|' - 0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - - 10, // 0x7D '}' - 0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x06,0x00,0x03,0x80,0x06,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x78,0x00, - - 12, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x20,0x24,0x20,0x46,0x20,0x42,0x40,0x41,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana18[] = - { - 18, 4, 32, 128-32, - 0x00,0x00,0x13,0x00,0x26,0x00,0x39,0x00,0x5E,0x00,0x83,0x00,0xA8,0x00,0xCD,0x00,0xE0,0x00, - 0xF3,0x00,0x06,0x01,0x2B,0x01,0x50,0x01,0x63,0x01,0x76,0x01,0x89,0x01,0x9C,0x01,0xC1,0x01, - 0xE6,0x01,0x0B,0x02,0x30,0x02,0x55,0x02,0x7A,0x02,0x9F,0x02,0xC4,0x02,0xE9,0x02,0x0E,0x03, - 0x21,0x03,0x34,0x03,0x59,0x03,0x7E,0x03,0xA3,0x03,0xB6,0x03,0xDB,0x03,0x00,0x04,0x25,0x04, - 0x4A,0x04,0x6F,0x04,0x94,0x04,0xB9,0x04,0xDE,0x04,0x03,0x05,0x16,0x05,0x29,0x05,0x4E,0x05, - 0x61,0x05,0x86,0x05,0xAB,0x05,0xD0,0x05,0xF5,0x05,0x1A,0x06,0x3F,0x06,0x64,0x06,0x89,0x06, - 0xAE,0x06,0xD3,0x06,0xF8,0x06,0x1D,0x07,0x42,0x07,0x67,0x07,0x7A,0x07,0x8D,0x07,0xA0,0x07, - 0xC5,0x07,0xEA,0x07,0x0F,0x08,0x34,0x08,0x59,0x08,0x6C,0x08,0x91,0x08,0xB6,0x08,0xC9,0x08, - 0xEE,0x08,0x13,0x09,0x26,0x09,0x39,0x09,0x5E,0x09,0x71,0x09,0x96,0x09,0xBB,0x09,0xE0,0x09, - 0x05,0x0A,0x2A,0x0A,0x3D,0x0A,0x50,0x0A,0x63,0x0A,0x88,0x0A,0xAD,0x0A,0xD2,0x0A,0xF7,0x0A, - 0x1C,0x0B,0x41,0x0B,0x66,0x0B,0x79,0x0B,0x9E,0x0B,0xC3,0x0B, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x20,0x00,0x00,0x00, - - 7, // 0x22 '"' - 0x00,0x00,0x00,0x48,0x48,0x48,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x80,0x04,0x80,0x09,0x00,0x3F,0xC0,0x09,0x00,0x11,0x00,0x12,0x00,0x7F,0x80,0x12,0x00,0x24,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x24 '$' - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x3E,0x00,0x49,0x00,0x48,0x00,0x48,0x00,0x38,0x00,0x0E,0x00,0x09,0x00,0x09,0x00,0x49,0x00,0x3E,0x00,0x08,0x00,0x08,0x00,0x08,0x00, - - 16, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x20,0x44,0x40,0x44,0x40,0x44,0x80,0x44,0x80,0x38,0x9C,0x01,0x22,0x01,0x22,0x02,0x22,0x02,0x22,0x04,0x1C,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x21,0x00,0x21,0x00,0x1E,0x40,0x24,0x40,0x42,0x40,0x41,0x40,0x40,0x80,0x21,0x40,0x1E,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x27 ''' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x28 '(' - 0x00,0x00,0x00,0x08,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10,0x08, - - 7, // 0x29 ')' - 0x00,0x00,0x00,0x20,0x10,0x08,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x08,0x10,0x20, - - 10, // 0x2A '*' - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x49,0x00,0x2A,0x00,0x1C,0x00,0x2A,0x00,0x49,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x3F,0xE0,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x40,0x40, - - 7, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00, - - 7, // 0x2F '/' - 0x00,0x00,0x00,0x02,0x04,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x00, - - 10, // 0x30 '0' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x31 '1' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x1C,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x32 '2' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x41,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x01,0x00,0x02,0x00,0x0C,0x00,0x30,0x00,0x40,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x33 '3' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x40,0x80,0x00,0x80,0x01,0x00,0x0E,0x00,0x01,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x41,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x34 '4' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x03,0x00,0x05,0x00,0x09,0x00,0x11,0x00,0x21,0x00,0x41,0x00,0x7F,0xC0,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x35 '5' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x80,0x20,0x00,0x20,0x00,0x20,0x00,0x3E,0x00,0x01,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x41,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x36 '6' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x5E,0x00,0x61,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x37 '7' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x04,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x10,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x38 '8' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x39 '9' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x20,0x80,0x1F,0x80,0x00,0x80,0x01,0x00,0x02,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x00, - - 7, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x20,0x20, - - 12, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0xC0,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x3F '?' - 0x00,0x00,0x00,0x00,0x3C,0x42,0x02,0x02,0x04,0x08,0x10,0x10,0x00,0x10,0x10,0x00,0x00,0x00, - - 15, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x18,0x60,0x20,0x10,0x23,0xD0,0x44,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x44,0x48,0x23,0xF0,0x20,0x00,0x18,0x00,0x07,0xC0,0x00,0x00, - - 10, // 0x41 'A' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x12,0x00,0x12,0x00,0x12,0x00,0x21,0x00,0x21,0x00,0x40,0x80,0x7F,0x80,0x40,0x80,0x80,0x40,0x80,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x42 'B' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x7E,0x00,0x41,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x41,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0xC0,0x20,0x40,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x20,0x40,0x30,0xC0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x41,0x80,0x40,0x80,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x41,0x80,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x45 'E' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x7F,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x46 'F' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x40,0x00,0x40,0x00,0x40,0x00,0x7F,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x30,0x60,0x20,0x20,0x40,0x00,0x40,0x00,0x41,0xE0,0x40,0x20,0x40,0x20,0x20,0x20,0x30,0x20,0x0F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7F,0xC0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x49 'I' - 0x00,0x00,0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,0x00, - - 7, // 0x4A 'J' - 0x00,0x00,0x00,0x00,0x3C,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0xF0,0x00,0x00,0x00, - - 10, // 0x4B 'K' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x41,0x00,0x42,0x00,0x44,0x00,0x48,0x00,0x50,0x00,0x68,0x00,0x44,0x00,0x42,0x00,0x41,0x00,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x4C 'L' - 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7F,0x00,0x00,0x00, - - 13, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x30,0x50,0x50,0x50,0x50,0x48,0x90,0x48,0x90,0x45,0x10,0x45,0x10,0x42,0x10,0x42,0x10,0x40,0x10,0x40,0x10,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x60,0x40,0x50,0x40,0x48,0x40,0x48,0x40,0x44,0x40,0x42,0x40,0x42,0x40,0x41,0x40,0x40,0xC0,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0xC0,0x20,0x40,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x20,0x40,0x30,0xC0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x50 'P' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x41,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x41,0x00,0x7E,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x30,0xC0,0x20,0x40,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x20,0x40,0x30,0xC0,0x0F,0x00,0x01,0x00,0x01,0x00,0x00,0xE0, - - 10, // 0x52 'R' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x42,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x42,0x00,0x7C,0x00,0x42,0x00,0x41,0x00,0x40,0x80,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x53 'S' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x20,0x80,0x40,0x00,0x40,0x00,0x20,0x00,0x1E,0x00,0x01,0x00,0x00,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x54 'T' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x20,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x56 'V' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x80,0x40,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x21,0x00,0x12,0x00,0x12,0x00,0x12,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 15, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x04,0x41,0x04,0x22,0x88,0x22,0x88,0x22,0x88,0x12,0x90,0x14,0x50,0x14,0x50,0x14,0x50,0x08,0x20,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x58 'X' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x21,0x00,0x21,0x00,0x12,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x12,0x00,0x21,0x00,0x21,0x00,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x59 'Y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x41,0x00,0x22,0x00,0x22,0x00,0x14,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x5A 'Z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x00,0x80,0x01,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x5B '[' - 0x00,0x00,0x00,0x3C,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3C, - - 7, // 0x5C '\' - 0x00,0x00,0x00,0x80,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x04,0x02,0x00, - - 7, // 0x5D ']' - 0x00,0x00,0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x78, - - 12, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x09,0x00,0x10,0x80,0x20,0x40,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xC0,0x00,0x00, - - 10, // 0x60 '`' - 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x01,0x00,0x3F,0x00,0x41,0x00,0x41,0x00,0x43,0x00,0x3D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x62 'b' - 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x5C,0x00,0x62,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x42,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x21,0x40,0x40,0x40,0x40,0x21,0x1E,0x00,0x00,0x00, - - 9, // 0x64 'd' - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x1F,0x00,0x21,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x23,0x00,0x1D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x22,0x00,0x41,0x00,0x7F,0x00,0x40,0x00,0x40,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x66 'f' - 0x00,0x00,0x00,0x1C,0x20,0x20,0x20,0x7C,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00, - - 9, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x21,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x23,0x00,0x1D,0x00,0x01,0x00,0x22,0x00,0x1C,0x00, - - 9, // 0x68 'h' - 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x5E,0x00,0x61,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 3, // 0x69 'i' - 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 5, // 0x6A 'j' - 0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xE0, - - 9, // 0x6B 'k' - 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x42,0x00,0x44,0x00,0x48,0x00,0x50,0x00,0x68,0x00,0x44,0x00,0x42,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 3, // 0x6C 'l' - 0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 15, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2E,0x70,0x31,0x88,0x21,0x08,0x21,0x08,0x21,0x08,0x21,0x08,0x21,0x08,0x21,0x08,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5E,0x00,0x61,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x21,0x00,0x40,0x80,0x40,0x80,0x40,0x80,0x40,0x80,0x21,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x00,0x62,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x42,0x00,0x7C,0x00,0x40,0x00,0x40,0x00,0x40,0x00, - - 9, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x21,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x23,0x00,0x1D,0x00,0x01,0x00,0x01,0x00,0x01,0x00, - - 6, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00, - - 8, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x40,0x30,0x0C,0x02,0x42,0x3C,0x00,0x00,0x00, - - 6, // 0x74 't' - 0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x7C,0x20,0x20,0x20,0x20,0x20,0x20,0x1C,0x00,0x00,0x00, - - 9, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x41,0x00,0x43,0x00,0x3D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x22,0x00,0x22,0x00,0x14,0x00,0x14,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x10,0x42,0x10,0x25,0x20,0x25,0x20,0x28,0xA0,0x28,0xA0,0x10,0x40,0x10,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00,0x08,0x00,0x14,0x00,0x22,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x41,0x00,0x22,0x00,0x22,0x00,0x22,0x00,0x14,0x00,0x14,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x10,0x00, - - 9, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x7B '{' - 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x60,0x00,0x10,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x07,0x00, - - 7, // 0x7C '|' - 0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - - 10, // 0x7D '}' - 0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x02,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x38,0x00, - - 12, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x20,0x24,0x20,0x42,0x40,0x41,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 15, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - - const int8u verdana18_bold[] = - { - 18, 4, 32, 128-32, - 0x00,0x00,0x13,0x00,0x26,0x00,0x4B,0x00,0x70,0x00,0x95,0x00,0xCC,0x00,0xF1,0x00,0x04,0x01, - 0x17,0x01,0x2A,0x01,0x4F,0x01,0x74,0x01,0x87,0x01,0x9A,0x01,0xAD,0x01,0xD2,0x01,0xF7,0x01, - 0x1C,0x02,0x41,0x02,0x66,0x02,0x8B,0x02,0xB0,0x02,0xD5,0x02,0xFA,0x02,0x1F,0x03,0x44,0x03, - 0x57,0x03,0x6A,0x03,0x8F,0x03,0xB4,0x03,0xD9,0x03,0xFE,0x03,0x23,0x04,0x48,0x04,0x6D,0x04, - 0x92,0x04,0xB7,0x04,0xDC,0x04,0x01,0x05,0x26,0x05,0x4B,0x05,0x5E,0x05,0x71,0x05,0x96,0x05, - 0xBB,0x05,0xE0,0x05,0x05,0x06,0x2A,0x06,0x4F,0x06,0x74,0x06,0x99,0x06,0xBE,0x06,0xE3,0x06, - 0x08,0x07,0x2D,0x07,0x52,0x07,0x77,0x07,0x9C,0x07,0xC1,0x07,0xD4,0x07,0xF9,0x07,0x0C,0x08, - 0x31,0x08,0x56,0x08,0x7B,0x08,0xA0,0x08,0xC5,0x08,0xD8,0x08,0xFD,0x08,0x22,0x09,0x35,0x09, - 0x5A,0x09,0x7F,0x09,0x92,0x09,0xA5,0x09,0xCA,0x09,0xDD,0x09,0x02,0x0A,0x27,0x0A,0x4C,0x0A, - 0x71,0x0A,0x96,0x0A,0xA9,0x0A,0xCE,0x0A,0xE1,0x0A,0x06,0x0B,0x2B,0x0B,0x50,0x0B,0x75,0x0B, - 0x9A,0x0B,0xBF,0x0B,0xE4,0x0B,0xF7,0x0B,0x1C,0x0C,0x41,0x0C, - - 5, // 0x20 ' ' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x21 '!' - 0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00, - - 9, // 0x22 '"' - 0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x23 '#' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x20,0x04,0x20,0x08,0x40,0x3F,0xF0,0x3F,0xF0,0x08,0x40,0x10,0x80,0x7F,0xE0,0x7F,0xE0,0x21,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x24 '$' - 0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x1F,0x80,0x34,0xC0,0x64,0xC0,0x64,0x00,0x3C,0x00,0x07,0x80,0x04,0xC0,0x64,0xC0,0x65,0x80,0x3F,0x00,0x04,0x00,0x04,0x00,0x00,0x00, - - 19, // 0x25 '%' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x08,0x00,0x63,0x10,0x00,0x63,0x10,0x00,0x63,0x20,0x00,0x63,0x2F,0x80,0x63,0x58,0xC0,0x3E,0x98,0xC0,0x00,0x98,0xC0,0x01,0x18,0xC0,0x01,0x18,0xC0,0x02,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x26 '&' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x33,0x00,0x33,0x00,0x33,0x00,0x1E,0x60,0x36,0x60,0x63,0x60,0x61,0xC0,0x60,0xC0,0x30,0xE0,0x1F,0x30,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x27 ''' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x28 '(' - 0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x30,0x18,0x0C,0x06, - - 8, // 0x29 ')' - 0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x30,0x60, - - 11, // 0x2A '*' - 0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x24,0x80,0x15,0x00,0x0E,0x00,0x15,0x00,0x24,0x80,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x2B '+' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x3F,0xE0,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x60,0x60,0x60,0xC0,0xC0, - - 7, // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 5, // 0x2E '.' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x00, - - 10, // 0x2F '/' - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x60,0x00,0x00,0x00, - - 11, // 0x30 '0' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x31 '1' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x1E,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x1F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x32 '2' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x61,0x80,0x60,0xC0,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x7F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x33 '3' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x61,0x80,0x60,0xC0,0x00,0xC0,0x01,0x80,0x0F,0x00,0x01,0x80,0x00,0xC0,0x60,0xC0,0x61,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x34 '4' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x80,0x05,0x80,0x09,0x80,0x11,0x80,0x21,0x80,0x41,0x80,0x7F,0xE0,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x35 '5' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xC0,0x30,0x00,0x30,0x00,0x30,0x00,0x3F,0x00,0x01,0x80,0x00,0xC0,0x00,0xC0,0x60,0xC0,0x61,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x36 '6' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x18,0x00,0x30,0x00,0x60,0x00,0x6F,0x00,0x71,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x37 '7' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xC0,0x00,0xC0,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x38 '8' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x31,0x80,0x60,0xC0,0x60,0xC0,0x31,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x39 '9' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x31,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0xC0,0x1E,0xC0,0x00,0xC0,0x01,0x80,0x03,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x3A ':' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x00, - - 6, // 0x3B ';' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x38,0x30,0x30,0x30,0x60,0x60, - - 13, // 0x3C '<' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x30,0x00,0x0C,0x00,0x03,0x00,0x00,0xC0,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x3D '=' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x3E '>' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x18,0x00,0x06,0x00,0x01,0x80,0x00,0x60,0x00,0x60,0x01,0x80,0x06,0x00,0x18,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 9, // 0x3F '?' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x63,0x00,0x03,0x00,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x40 '@' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x18,0x60,0x20,0x10,0x27,0xD0,0x4C,0xC8,0x4C,0xC8,0x4C,0xC8,0x4C,0xC8,0x4C,0xC8,0x27,0xF0,0x20,0x00,0x18,0x00,0x07,0xC0,0x00,0x00, - - 12, // 0x41 'A' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x0F,0x00,0x0F,0x00,0x19,0x80,0x19,0x80,0x30,0xC0,0x3F,0xC0,0x30,0xC0,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x42 'B' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x00,0x7F,0x00,0x61,0x80,0x60,0xC0,0x60,0xC0,0x61,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x43 'C' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x38,0xC0,0x30,0xC0,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x30,0xC0,0x38,0xC0,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x44 'D' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x61,0xC0,0x60,0xC0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xC0,0x61,0xC0,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x45 'E' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x80,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x46 'F' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x80,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x47 'G' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xC0,0x38,0x60,0x30,0x60,0x60,0x00,0x60,0x00,0x63,0xE0,0x60,0x60,0x60,0x60,0x30,0x60,0x38,0x60,0x0F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x48 'H' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7F,0xE0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x49 'I' - 0x00,0x00,0x00,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00, - - 8, // 0x4A 'J' - 0x00,0x00,0x00,0x00,0x3E,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0xF8,0x00,0x00,0x00, - - 12, // 0x4B 'K' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x60,0xC0,0x61,0x80,0x63,0x00,0x66,0x00,0x6C,0x00,0x7E,0x00,0x73,0x00,0x61,0x80,0x60,0xC0,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x4C 'L' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x4D 'M' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x38,0x70,0x38,0x70,0x78,0x58,0x58,0x58,0xD8,0x4C,0x98,0x4D,0x98,0x47,0x18,0x47,0x18,0x42,0x18,0x40,0x18,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x4E 'N' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x20,0x70,0x20,0x58,0x20,0x4C,0x20,0x4C,0x20,0x46,0x20,0x43,0x20,0x43,0x20,0x41,0xA0,0x40,0xE0,0x40,0xE0,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x4F 'O' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x38,0xE0,0x30,0x60,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x30,0x60,0x38,0xE0,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x50 'P' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x61,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x61,0x80,0x7F,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 13, // 0x51 'Q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x38,0xE0,0x30,0x60,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x30,0x60,0x38,0xE0,0x0F,0x80,0x03,0x00,0x03,0x80,0x01,0xF0, - - 12, // 0x52 'R' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x61,0x80,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x61,0x80,0x7F,0x00,0x61,0x80,0x60,0xC0,0x60,0x60,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x53 'S' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x30,0xC0,0x60,0xC0,0x60,0x00,0x7C,0x00,0x3F,0x80,0x03,0xC0,0x00,0xC0,0x60,0xC0,0x61,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x54 'T' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 12, // 0x55 'U' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x30,0xC0,0x1F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x56 'V' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x31,0x80,0x31,0x80,0x31,0x80,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x0E,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 16, // 0x57 'W' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x86,0x61,0x86,0x63,0xC6,0x33,0xCC,0x32,0x4C,0x32,0x4C,0x1E,0x78,0x1C,0x38,0x1C,0x38,0x0C,0x30,0x0C,0x30,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x58 'X' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x31,0x80,0x31,0x80,0x1B,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x1B,0x00,0x31,0x80,0x31,0x80,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x59 'Y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x61,0x80,0x61,0x80,0x33,0x00,0x1E,0x00,0x1E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x5A 'Z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0x80,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0x7F,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x5B '[' - 0x00,0x00,0x00,0x3E,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3E, - - 10, // 0x5C '\' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x06,0x00,0x06,0x00,0x03,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x00,0x00, - - 8, // 0x5D ']' - 0x00,0x00,0x00,0x7C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x7C, - - 13, // 0x5E '^' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0F,0x00,0x19,0x80,0x30,0xC0,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xE0,0x00,0x00, - - 11, // 0x60 '`' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x61 'a' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x01,0x80,0x01,0x80,0x3F,0x80,0x61,0x80,0x61,0x80,0x63,0x80,0x3D,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x62 'b' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x6E,0x00,0x73,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 8, // 0x63 'c' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x33,0x60,0x60,0x60,0x60,0x33,0x1E,0x00,0x00,0x00, - - 10, // 0x64 'd' - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0x80,0x31,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x80,0x1D,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x65 'e' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x33,0x00,0x61,0x80,0x7F,0x80,0x60,0x00,0x60,0x00,0x31,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 6, // 0x66 'f' - 0x00,0x00,0x00,0x1C,0x30,0x30,0x30,0x7C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00, - - 10, // 0x67 'g' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x31,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x80,0x1D,0x80,0x01,0x80,0x03,0x00,0x3E,0x00, - - 10, // 0x68 'h' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x6F,0x00,0x71,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x69 'i' - 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 6, // 0x6A 'j' - 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF0, - - 10, // 0x6B 'k' - 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x61,0x80,0x63,0x00,0x66,0x00,0x6C,0x00,0x7E,0x00,0x73,0x00,0x61,0x80,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, - - 4, // 0x6C 'l' - 0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 16, // 0x6D 'm' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6F,0x3C,0x71,0xC6,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x6E 'n' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6F,0x00,0x71,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x6F 'o' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x33,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x70 'p' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x00,0x73,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x00,0x7E,0x00,0x60,0x00,0x60,0x00,0x60,0x00, - - 10, // 0x71 'q' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x31,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x33,0x80,0x1D,0x80,0x01,0x80,0x01,0x80,0x01,0x80, - - 7, // 0x72 'r' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x7E,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00, - - 9, // 0x73 's' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x61,0x00,0x60,0x00,0x7E,0x00,0x3F,0x00,0x03,0x00,0x43,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 7, // 0x74 't' - 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x7E,0x30,0x30,0x30,0x30,0x30,0x30,0x1E,0x00,0x00,0x00, - - 10, // 0x75 'u' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x61,0x80,0x63,0x80,0x3D,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x76 'v' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x33,0x00,0x33,0x00,0x33,0x00,0x1E,0x00,0x1E,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 14, // 0x77 'w' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x18,0x63,0x18,0x63,0x18,0x37,0xB0,0x34,0xB0,0x3C,0xF0,0x18,0x60,0x18,0x60,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x78 'x' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x33,0x00,0x33,0x00,0x1E,0x00,0x1E,0x00,0x33,0x00,0x33,0x00,0x61,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 10, // 0x79 'y' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x80,0x61,0x80,0x33,0x00,0x33,0x00,0x33,0x00,0x1E,0x00,0x1E,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00, - - 9, // 0x7A 'z' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 11, // 0x7B '{' - 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x70,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x07,0x80, - - 8, // 0x7C '|' - 0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - - 11, // 0x7D '}' - 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x03,0x00,0x01,0xC0,0x03,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x3C,0x00, - - 13, // 0x7E '~' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x10,0x24,0x10,0x42,0x10,0x41,0x20,0x40,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 15, // 0x7F '' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, - - 0 - }; - -} - diff -Nru corsix-th-0.30/agg/src/agg_gsv_text.cpp corsix-th-0.62/agg/src/agg_gsv_text.cpp --- corsix-th-0.30/agg/src/agg_gsv_text.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_gsv_text.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,675 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Class gsv_text -// -//---------------------------------------------------------------------------- -#include -#include -#include "agg_gsv_text.h" -#include "agg_bounding_rect.h" - - - -namespace agg -{ - int8u gsv_default_font[] = - { - 0x40,0x00,0x6c,0x0f,0x15,0x00,0x0e,0x00,0xf9,0xff, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x0d,0x0a,0x0d,0x0a,0x46,0x6f,0x6e,0x74,0x20,0x28, - 0x63,0x29,0x20,0x4d,0x69,0x63,0x72,0x6f,0x50,0x72, - 0x6f,0x66,0x20,0x32,0x37,0x20,0x53,0x65,0x70,0x74, - 0x65,0x6d,0x62,0x2e,0x31,0x39,0x38,0x39,0x00,0x0d, - 0x0a,0x0d,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x02,0x00,0x12,0x00,0x34,0x00,0x46,0x00,0x94,0x00, - 0xd0,0x00,0x2e,0x01,0x3e,0x01,0x64,0x01,0x8a,0x01, - 0x98,0x01,0xa2,0x01,0xb4,0x01,0xba,0x01,0xc6,0x01, - 0xcc,0x01,0xf0,0x01,0xfa,0x01,0x18,0x02,0x38,0x02, - 0x44,0x02,0x68,0x02,0x98,0x02,0xa2,0x02,0xde,0x02, - 0x0e,0x03,0x24,0x03,0x40,0x03,0x48,0x03,0x52,0x03, - 0x5a,0x03,0x82,0x03,0xec,0x03,0xfa,0x03,0x26,0x04, - 0x4c,0x04,0x6a,0x04,0x7c,0x04,0x8a,0x04,0xb6,0x04, - 0xc4,0x04,0xca,0x04,0xe0,0x04,0xee,0x04,0xf8,0x04, - 0x0a,0x05,0x18,0x05,0x44,0x05,0x5e,0x05,0x8e,0x05, - 0xac,0x05,0xd6,0x05,0xe0,0x05,0xf6,0x05,0x00,0x06, - 0x12,0x06,0x1c,0x06,0x28,0x06,0x36,0x06,0x48,0x06, - 0x4e,0x06,0x60,0x06,0x6e,0x06,0x74,0x06,0x84,0x06, - 0xa6,0x06,0xc8,0x06,0xe6,0x06,0x08,0x07,0x2c,0x07, - 0x3c,0x07,0x68,0x07,0x7c,0x07,0x8c,0x07,0xa2,0x07, - 0xb0,0x07,0xb6,0x07,0xd8,0x07,0xec,0x07,0x10,0x08, - 0x32,0x08,0x54,0x08,0x64,0x08,0x88,0x08,0x98,0x08, - 0xac,0x08,0xb6,0x08,0xc8,0x08,0xd2,0x08,0xe4,0x08, - 0xf2,0x08,0x3e,0x09,0x48,0x09,0x94,0x09,0xc2,0x09, - 0xc4,0x09,0xd0,0x09,0xe2,0x09,0x04,0x0a,0x0e,0x0a, - 0x26,0x0a,0x34,0x0a,0x4a,0x0a,0x66,0x0a,0x70,0x0a, - 0x7e,0x0a,0x8e,0x0a,0x9a,0x0a,0xa6,0x0a,0xb4,0x0a, - 0xd8,0x0a,0xe2,0x0a,0xf6,0x0a,0x18,0x0b,0x22,0x0b, - 0x32,0x0b,0x56,0x0b,0x60,0x0b,0x6e,0x0b,0x7c,0x0b, - 0x8a,0x0b,0x9c,0x0b,0x9e,0x0b,0xb2,0x0b,0xc2,0x0b, - 0xd8,0x0b,0xf4,0x0b,0x08,0x0c,0x30,0x0c,0x56,0x0c, - 0x72,0x0c,0x90,0x0c,0xb2,0x0c,0xce,0x0c,0xe2,0x0c, - 0xfe,0x0c,0x10,0x0d,0x26,0x0d,0x36,0x0d,0x42,0x0d, - 0x4e,0x0d,0x5c,0x0d,0x78,0x0d,0x8c,0x0d,0x8e,0x0d, - 0x90,0x0d,0x92,0x0d,0x94,0x0d,0x96,0x0d,0x98,0x0d, - 0x9a,0x0d,0x9c,0x0d,0x9e,0x0d,0xa0,0x0d,0xa2,0x0d, - 0xa4,0x0d,0xa6,0x0d,0xa8,0x0d,0xaa,0x0d,0xac,0x0d, - 0xae,0x0d,0xb0,0x0d,0xb2,0x0d,0xb4,0x0d,0xb6,0x0d, - 0xb8,0x0d,0xba,0x0d,0xbc,0x0d,0xbe,0x0d,0xc0,0x0d, - 0xc2,0x0d,0xc4,0x0d,0xc6,0x0d,0xc8,0x0d,0xca,0x0d, - 0xcc,0x0d,0xce,0x0d,0xd0,0x0d,0xd2,0x0d,0xd4,0x0d, - 0xd6,0x0d,0xd8,0x0d,0xda,0x0d,0xdc,0x0d,0xde,0x0d, - 0xe0,0x0d,0xe2,0x0d,0xe4,0x0d,0xe6,0x0d,0xe8,0x0d, - 0xea,0x0d,0xec,0x0d,0x0c,0x0e,0x26,0x0e,0x48,0x0e, - 0x64,0x0e,0x88,0x0e,0x92,0x0e,0xa6,0x0e,0xb4,0x0e, - 0xd0,0x0e,0xee,0x0e,0x02,0x0f,0x16,0x0f,0x26,0x0f, - 0x3c,0x0f,0x58,0x0f,0x6c,0x0f,0x6c,0x0f,0x6c,0x0f, - 0x6c,0x0f,0x6c,0x0f,0x6c,0x0f,0x6c,0x0f,0x6c,0x0f, - 0x6c,0x0f,0x6c,0x0f,0x6c,0x0f,0x6c,0x0f,0x6c,0x0f, - 0x6c,0x0f,0x6c,0x0f,0x6c,0x0f,0x6c,0x0f,0x10,0x80, - 0x05,0x95,0x00,0x72,0x00,0xfb,0xff,0x7f,0x01,0x7f, - 0x01,0x01,0xff,0x01,0x05,0xfe,0x05,0x95,0xff,0x7f, - 0x00,0x7a,0x01,0x86,0xff,0x7a,0x01,0x87,0x01,0x7f, - 0xfe,0x7a,0x0a,0x87,0xff,0x7f,0x00,0x7a,0x01,0x86, - 0xff,0x7a,0x01,0x87,0x01,0x7f,0xfe,0x7a,0x05,0xf2, - 0x0b,0x95,0xf9,0x64,0x0d,0x9c,0xf9,0x64,0xfa,0x91, - 0x0e,0x00,0xf1,0xfa,0x0e,0x00,0x04,0xfc,0x08,0x99, - 0x00,0x63,0x04,0x9d,0x00,0x63,0x04,0x96,0xff,0x7f, - 0x01,0x7f,0x01,0x01,0x00,0x01,0xfe,0x02,0xfd,0x01, - 0xfc,0x00,0xfd,0x7f,0xfe,0x7e,0x00,0x7e,0x01,0x7e, - 0x01,0x7f,0x02,0x7f,0x06,0x7e,0x02,0x7f,0x02,0x7e, - 0xf2,0x89,0x02,0x7e,0x02,0x7f,0x06,0x7e,0x02,0x7f, - 0x01,0x7f,0x01,0x7e,0x00,0x7c,0xfe,0x7e,0xfd,0x7f, - 0xfc,0x00,0xfd,0x01,0xfe,0x02,0x00,0x01,0x01,0x01, - 0x01,0x7f,0xff,0x7f,0x10,0xfd,0x15,0x95,0xee,0x6b, - 0x05,0x95,0x02,0x7e,0x00,0x7e,0xff,0x7e,0xfe,0x7f, - 0xfe,0x00,0xfe,0x02,0x00,0x02,0x01,0x02,0x02,0x01, - 0x02,0x00,0x02,0x7f,0x03,0x7f,0x03,0x00,0x03,0x01, - 0x02,0x01,0xfc,0xf2,0xfe,0x7f,0xff,0x7e,0x00,0x7e, - 0x02,0x7e,0x02,0x00,0x02,0x01,0x01,0x02,0x00,0x02, - 0xfe,0x02,0xfe,0x00,0x07,0xf9,0x15,0x8d,0xff,0x7f, - 0x01,0x7f,0x01,0x01,0x00,0x01,0xff,0x01,0xff,0x00, - 0xff,0x7f,0xff,0x7e,0xfe,0x7b,0xfe,0x7d,0xfe,0x7e, - 0xfe,0x7f,0xfd,0x00,0xfd,0x01,0xff,0x02,0x00,0x03, - 0x01,0x02,0x06,0x04,0x02,0x02,0x01,0x02,0x00,0x02, - 0xff,0x02,0xfe,0x01,0xfe,0x7f,0xff,0x7e,0x00,0x7e, - 0x01,0x7d,0x02,0x7d,0x05,0x79,0x02,0x7e,0x03,0x7f, - 0x01,0x00,0x01,0x01,0x00,0x01,0xf1,0xfe,0xfe,0x01, - 0xff,0x02,0x00,0x03,0x01,0x02,0x02,0x02,0x00,0x86, - 0x01,0x7e,0x08,0x75,0x02,0x7e,0x02,0x7f,0x05,0x80, - 0x05,0x93,0xff,0x01,0x01,0x01,0x01,0x7f,0x00,0x7e, - 0xff,0x7e,0xff,0x7f,0x06,0xf1,0x0b,0x99,0xfe,0x7e, - 0xfe,0x7d,0xfe,0x7c,0xff,0x7b,0x00,0x7c,0x01,0x7b, - 0x02,0x7c,0x02,0x7d,0x02,0x7e,0xfe,0x9e,0xfe,0x7c, - 0xff,0x7d,0xff,0x7b,0x00,0x7c,0x01,0x7b,0x01,0x7d, - 0x02,0x7c,0x05,0x85,0x03,0x99,0x02,0x7e,0x02,0x7d, - 0x02,0x7c,0x01,0x7b,0x00,0x7c,0xff,0x7b,0xfe,0x7c, - 0xfe,0x7d,0xfe,0x7e,0x02,0x9e,0x02,0x7c,0x01,0x7d, - 0x01,0x7b,0x00,0x7c,0xff,0x7b,0xff,0x7d,0xfe,0x7c, - 0x09,0x85,0x08,0x95,0x00,0x74,0xfb,0x89,0x0a,0x7a, - 0x00,0x86,0xf6,0x7a,0x0d,0xf4,0x0d,0x92,0x00,0x6e, - 0xf7,0x89,0x12,0x00,0x04,0xf7,0x06,0x81,0xff,0x7f, - 0xff,0x01,0x01,0x01,0x01,0x7f,0x00,0x7e,0xff,0x7e, - 0xff,0x7f,0x06,0x84,0x04,0x89,0x12,0x00,0x04,0xf7, - 0x05,0x82,0xff,0x7f,0x01,0x7f,0x01,0x01,0xff,0x01, - 0x05,0xfe,0x00,0xfd,0x0e,0x18,0x00,0xeb,0x09,0x95, - 0xfd,0x7f,0xfe,0x7d,0xff,0x7b,0x00,0x7d,0x01,0x7b, - 0x02,0x7d,0x03,0x7f,0x02,0x00,0x03,0x01,0x02,0x03, - 0x01,0x05,0x00,0x03,0xff,0x05,0xfe,0x03,0xfd,0x01, - 0xfe,0x00,0x0b,0xeb,0x06,0x91,0x02,0x01,0x03,0x03, - 0x00,0x6b,0x09,0x80,0x04,0x90,0x00,0x01,0x01,0x02, - 0x01,0x01,0x02,0x01,0x04,0x00,0x02,0x7f,0x01,0x7f, - 0x01,0x7e,0x00,0x7e,0xff,0x7e,0xfe,0x7d,0xf6,0x76, - 0x0e,0x00,0x03,0x80,0x05,0x95,0x0b,0x00,0xfa,0x78, - 0x03,0x00,0x02,0x7f,0x01,0x7f,0x01,0x7d,0x00,0x7e, - 0xff,0x7d,0xfe,0x7e,0xfd,0x7f,0xfd,0x00,0xfd,0x01, - 0xff,0x01,0xff,0x02,0x11,0xfc,0x0d,0x95,0xf6,0x72, - 0x0f,0x00,0xfb,0x8e,0x00,0x6b,0x07,0x80,0x0f,0x95, - 0xf6,0x00,0xff,0x77,0x01,0x01,0x03,0x01,0x03,0x00, - 0x03,0x7f,0x02,0x7e,0x01,0x7d,0x00,0x7e,0xff,0x7d, - 0xfe,0x7e,0xfd,0x7f,0xfd,0x00,0xfd,0x01,0xff,0x01, - 0xff,0x02,0x11,0xfc,0x10,0x92,0xff,0x02,0xfd,0x01, - 0xfe,0x00,0xfd,0x7f,0xfe,0x7d,0xff,0x7b,0x00,0x7b, - 0x01,0x7c,0x02,0x7e,0x03,0x7f,0x01,0x00,0x03,0x01, - 0x02,0x02,0x01,0x03,0x00,0x01,0xff,0x03,0xfe,0x02, - 0xfd,0x01,0xff,0x00,0xfd,0x7f,0xfe,0x7e,0xff,0x7d, - 0x10,0xf9,0x11,0x95,0xf6,0x6b,0xfc,0x95,0x0e,0x00, - 0x03,0xeb,0x08,0x95,0xfd,0x7f,0xff,0x7e,0x00,0x7e, - 0x01,0x7e,0x02,0x7f,0x04,0x7f,0x03,0x7f,0x02,0x7e, - 0x01,0x7e,0x00,0x7d,0xff,0x7e,0xff,0x7f,0xfd,0x7f, - 0xfc,0x00,0xfd,0x01,0xff,0x01,0xff,0x02,0x00,0x03, - 0x01,0x02,0x02,0x02,0x03,0x01,0x04,0x01,0x02,0x01, - 0x01,0x02,0x00,0x02,0xff,0x02,0xfd,0x01,0xfc,0x00, - 0x0c,0xeb,0x10,0x8e,0xff,0x7d,0xfe,0x7e,0xfd,0x7f, - 0xff,0x00,0xfd,0x01,0xfe,0x02,0xff,0x03,0x00,0x01, - 0x01,0x03,0x02,0x02,0x03,0x01,0x01,0x00,0x03,0x7f, - 0x02,0x7e,0x01,0x7c,0x00,0x7b,0xff,0x7b,0xfe,0x7d, - 0xfd,0x7f,0xfe,0x00,0xfd,0x01,0xff,0x02,0x10,0xfd, - 0x05,0x8e,0xff,0x7f,0x01,0x7f,0x01,0x01,0xff,0x01, - 0x00,0xf4,0xff,0x7f,0x01,0x7f,0x01,0x01,0xff,0x01, - 0x05,0xfe,0x05,0x8e,0xff,0x7f,0x01,0x7f,0x01,0x01, - 0xff,0x01,0x01,0xf3,0xff,0x7f,0xff,0x01,0x01,0x01, - 0x01,0x7f,0x00,0x7e,0xff,0x7e,0xff,0x7f,0x06,0x84, - 0x14,0x92,0xf0,0x77,0x10,0x77,0x04,0x80,0x04,0x8c, - 0x12,0x00,0xee,0xfa,0x12,0x00,0x04,0xfa,0x04,0x92, - 0x10,0x77,0xf0,0x77,0x14,0x80,0x03,0x90,0x00,0x01, - 0x01,0x02,0x01,0x01,0x02,0x01,0x04,0x00,0x02,0x7f, - 0x01,0x7f,0x01,0x7e,0x00,0x7e,0xff,0x7e,0xff,0x7f, - 0xfc,0x7e,0x00,0x7d,0x00,0xfb,0xff,0x7f,0x01,0x7f, - 0x01,0x01,0xff,0x01,0x09,0xfe,0x12,0x8d,0xff,0x02, - 0xfe,0x01,0xfd,0x00,0xfe,0x7f,0xff,0x7f,0xff,0x7d, - 0x00,0x7d,0x01,0x7e,0x02,0x7f,0x03,0x00,0x02,0x01, - 0x01,0x02,0xfb,0x88,0xfe,0x7e,0xff,0x7d,0x00,0x7d, - 0x01,0x7e,0x01,0x7f,0x07,0x8b,0xff,0x78,0x00,0x7e, - 0x02,0x7f,0x02,0x00,0x02,0x02,0x01,0x03,0x00,0x02, - 0xff,0x03,0xff,0x02,0xfe,0x02,0xfe,0x01,0xfd,0x01, - 0xfd,0x00,0xfd,0x7f,0xfe,0x7f,0xfe,0x7e,0xff,0x7e, - 0xff,0x7d,0x00,0x7d,0x01,0x7d,0x01,0x7e,0x02,0x7e, - 0x02,0x7f,0x03,0x7f,0x03,0x00,0x03,0x01,0x02,0x01, - 0x01,0x01,0xfe,0x8d,0xff,0x78,0x00,0x7e,0x01,0x7f, - 0x08,0xfb,0x09,0x95,0xf8,0x6b,0x08,0x95,0x08,0x6b, - 0xf3,0x87,0x0a,0x00,0x04,0xf9,0x04,0x95,0x00,0x6b, - 0x00,0x95,0x09,0x00,0x03,0x7f,0x01,0x7f,0x01,0x7e, - 0x00,0x7e,0xff,0x7e,0xff,0x7f,0xfd,0x7f,0xf7,0x80, - 0x09,0x00,0x03,0x7f,0x01,0x7f,0x01,0x7e,0x00,0x7d, - 0xff,0x7e,0xff,0x7f,0xfd,0x7f,0xf7,0x00,0x11,0x80, - 0x12,0x90,0xff,0x02,0xfe,0x02,0xfe,0x01,0xfc,0x00, - 0xfe,0x7f,0xfe,0x7e,0xff,0x7e,0xff,0x7d,0x00,0x7b, - 0x01,0x7d,0x01,0x7e,0x02,0x7e,0x02,0x7f,0x04,0x00, - 0x02,0x01,0x02,0x02,0x01,0x02,0x03,0xfb,0x04,0x95, - 0x00,0x6b,0x00,0x95,0x07,0x00,0x03,0x7f,0x02,0x7e, - 0x01,0x7e,0x01,0x7d,0x00,0x7b,0xff,0x7d,0xff,0x7e, - 0xfe,0x7e,0xfd,0x7f,0xf9,0x00,0x11,0x80,0x04,0x95, - 0x00,0x6b,0x00,0x95,0x0d,0x00,0xf3,0xf6,0x08,0x00, - 0xf8,0xf5,0x0d,0x00,0x02,0x80,0x04,0x95,0x00,0x6b, - 0x00,0x95,0x0d,0x00,0xf3,0xf6,0x08,0x00,0x06,0xf5, - 0x12,0x90,0xff,0x02,0xfe,0x02,0xfe,0x01,0xfc,0x00, - 0xfe,0x7f,0xfe,0x7e,0xff,0x7e,0xff,0x7d,0x00,0x7b, - 0x01,0x7d,0x01,0x7e,0x02,0x7e,0x02,0x7f,0x04,0x00, - 0x02,0x01,0x02,0x02,0x01,0x02,0x00,0x03,0xfb,0x80, - 0x05,0x00,0x03,0xf8,0x04,0x95,0x00,0x6b,0x0e,0x95, - 0x00,0x6b,0xf2,0x8b,0x0e,0x00,0x04,0xf5,0x04,0x95, - 0x00,0x6b,0x04,0x80,0x0c,0x95,0x00,0x70,0xff,0x7d, - 0xff,0x7f,0xfe,0x7f,0xfe,0x00,0xfe,0x01,0xff,0x01, - 0xff,0x03,0x00,0x02,0x0e,0xf9,0x04,0x95,0x00,0x6b, - 0x0e,0x95,0xf2,0x72,0x05,0x85,0x09,0x74,0x03,0x80, - 0x04,0x95,0x00,0x6b,0x00,0x80,0x0c,0x00,0x01,0x80, - 0x04,0x95,0x00,0x6b,0x00,0x95,0x08,0x6b,0x08,0x95, - 0xf8,0x6b,0x08,0x95,0x00,0x6b,0x04,0x80,0x04,0x95, - 0x00,0x6b,0x00,0x95,0x0e,0x6b,0x00,0x95,0x00,0x6b, - 0x04,0x80,0x09,0x95,0xfe,0x7f,0xfe,0x7e,0xff,0x7e, - 0xff,0x7d,0x00,0x7b,0x01,0x7d,0x01,0x7e,0x02,0x7e, - 0x02,0x7f,0x04,0x00,0x02,0x01,0x02,0x02,0x01,0x02, - 0x01,0x03,0x00,0x05,0xff,0x03,0xff,0x02,0xfe,0x02, - 0xfe,0x01,0xfc,0x00,0x0d,0xeb,0x04,0x95,0x00,0x6b, - 0x00,0x95,0x09,0x00,0x03,0x7f,0x01,0x7f,0x01,0x7e, - 0x00,0x7d,0xff,0x7e,0xff,0x7f,0xfd,0x7f,0xf7,0x00, - 0x11,0xf6,0x09,0x95,0xfe,0x7f,0xfe,0x7e,0xff,0x7e, - 0xff,0x7d,0x00,0x7b,0x01,0x7d,0x01,0x7e,0x02,0x7e, - 0x02,0x7f,0x04,0x00,0x02,0x01,0x02,0x02,0x01,0x02, - 0x01,0x03,0x00,0x05,0xff,0x03,0xff,0x02,0xfe,0x02, - 0xfe,0x01,0xfc,0x00,0x03,0xef,0x06,0x7a,0x04,0x82, - 0x04,0x95,0x00,0x6b,0x00,0x95,0x09,0x00,0x03,0x7f, - 0x01,0x7f,0x01,0x7e,0x00,0x7e,0xff,0x7e,0xff,0x7f, - 0xfd,0x7f,0xf7,0x00,0x07,0x80,0x07,0x75,0x03,0x80, - 0x11,0x92,0xfe,0x02,0xfd,0x01,0xfc,0x00,0xfd,0x7f, - 0xfe,0x7e,0x00,0x7e,0x01,0x7e,0x01,0x7f,0x02,0x7f, - 0x06,0x7e,0x02,0x7f,0x01,0x7f,0x01,0x7e,0x00,0x7d, - 0xfe,0x7e,0xfd,0x7f,0xfc,0x00,0xfd,0x01,0xfe,0x02, - 0x11,0xfd,0x08,0x95,0x00,0x6b,0xf9,0x95,0x0e,0x00, - 0x01,0xeb,0x04,0x95,0x00,0x71,0x01,0x7d,0x02,0x7e, - 0x03,0x7f,0x02,0x00,0x03,0x01,0x02,0x02,0x01,0x03, - 0x00,0x0f,0x04,0xeb,0x01,0x95,0x08,0x6b,0x08,0x95, - 0xf8,0x6b,0x09,0x80,0x02,0x95,0x05,0x6b,0x05,0x95, - 0xfb,0x6b,0x05,0x95,0x05,0x6b,0x05,0x95,0xfb,0x6b, - 0x07,0x80,0x03,0x95,0x0e,0x6b,0x00,0x95,0xf2,0x6b, - 0x11,0x80,0x01,0x95,0x08,0x76,0x00,0x75,0x08,0x95, - 0xf8,0x76,0x09,0xf5,0x11,0x95,0xf2,0x6b,0x00,0x95, - 0x0e,0x00,0xf2,0xeb,0x0e,0x00,0x03,0x80,0x03,0x93, - 0x00,0x6c,0x01,0x94,0x00,0x6c,0xff,0x94,0x05,0x00, - 0xfb,0xec,0x05,0x00,0x02,0x81,0x00,0x95,0x0e,0x68, - 0x00,0x83,0x06,0x93,0x00,0x6c,0x01,0x94,0x00,0x6c, - 0xfb,0x94,0x05,0x00,0xfb,0xec,0x05,0x00,0x03,0x81, - 0x03,0x87,0x08,0x05,0x08,0x7b,0xf0,0x80,0x08,0x04, - 0x08,0x7c,0x03,0xf9,0x01,0x80,0x10,0x00,0x01,0x80, - 0x06,0x95,0xff,0x7f,0xff,0x7e,0x00,0x7e,0x01,0x7f, - 0x01,0x01,0xff,0x01,0x05,0xef,0x0f,0x8e,0x00,0x72, - 0x00,0x8b,0xfe,0x02,0xfe,0x01,0xfd,0x00,0xfe,0x7f, - 0xfe,0x7e,0xff,0x7d,0x00,0x7e,0x01,0x7d,0x02,0x7e, - 0x02,0x7f,0x03,0x00,0x02,0x01,0x02,0x02,0x04,0xfd, - 0x04,0x95,0x00,0x6b,0x00,0x8b,0x02,0x02,0x02,0x01, - 0x03,0x00,0x02,0x7f,0x02,0x7e,0x01,0x7d,0x00,0x7e, - 0xff,0x7d,0xfe,0x7e,0xfe,0x7f,0xfd,0x00,0xfe,0x01, - 0xfe,0x02,0x0f,0xfd,0x0f,0x8b,0xfe,0x02,0xfe,0x01, - 0xfd,0x00,0xfe,0x7f,0xfe,0x7e,0xff,0x7d,0x00,0x7e, - 0x01,0x7d,0x02,0x7e,0x02,0x7f,0x03,0x00,0x02,0x01, - 0x02,0x02,0x03,0xfd,0x0f,0x95,0x00,0x6b,0x00,0x8b, - 0xfe,0x02,0xfe,0x01,0xfd,0x00,0xfe,0x7f,0xfe,0x7e, - 0xff,0x7d,0x00,0x7e,0x01,0x7d,0x02,0x7e,0x02,0x7f, - 0x03,0x00,0x02,0x01,0x02,0x02,0x04,0xfd,0x03,0x88, - 0x0c,0x00,0x00,0x02,0xff,0x02,0xff,0x01,0xfe,0x01, - 0xfd,0x00,0xfe,0x7f,0xfe,0x7e,0xff,0x7d,0x00,0x7e, - 0x01,0x7d,0x02,0x7e,0x02,0x7f,0x03,0x00,0x02,0x01, - 0x02,0x02,0x03,0xfd,0x0a,0x95,0xfe,0x00,0xfe,0x7f, - 0xff,0x7d,0x00,0x6f,0xfd,0x8e,0x07,0x00,0x03,0xf2, - 0x0f,0x8e,0x00,0x70,0xff,0x7d,0xff,0x7f,0xfe,0x7f, - 0xfd,0x00,0xfe,0x01,0x09,0x91,0xfe,0x02,0xfe,0x01, - 0xfd,0x00,0xfe,0x7f,0xfe,0x7e,0xff,0x7d,0x00,0x7e, - 0x01,0x7d,0x02,0x7e,0x02,0x7f,0x03,0x00,0x02,0x01, - 0x02,0x02,0x04,0xfd,0x04,0x95,0x00,0x6b,0x00,0x8a, - 0x03,0x03,0x02,0x01,0x03,0x00,0x02,0x7f,0x01,0x7d, - 0x00,0x76,0x04,0x80,0x03,0x95,0x01,0x7f,0x01,0x01, - 0xff,0x01,0xff,0x7f,0x01,0xf9,0x00,0x72,0x04,0x80, - 0x05,0x95,0x01,0x7f,0x01,0x01,0xff,0x01,0xff,0x7f, - 0x01,0xf9,0x00,0x6f,0xff,0x7d,0xfe,0x7f,0xfe,0x00, - 0x09,0x87,0x04,0x95,0x00,0x6b,0x0a,0x8e,0xf6,0x76, - 0x04,0x84,0x07,0x78,0x02,0x80,0x04,0x95,0x00,0x6b, - 0x04,0x80,0x04,0x8e,0x00,0x72,0x00,0x8a,0x03,0x03, - 0x02,0x01,0x03,0x00,0x02,0x7f,0x01,0x7d,0x00,0x76, - 0x00,0x8a,0x03,0x03,0x02,0x01,0x03,0x00,0x02,0x7f, - 0x01,0x7d,0x00,0x76,0x04,0x80,0x04,0x8e,0x00,0x72, - 0x00,0x8a,0x03,0x03,0x02,0x01,0x03,0x00,0x02,0x7f, - 0x01,0x7d,0x00,0x76,0x04,0x80,0x08,0x8e,0xfe,0x7f, - 0xfe,0x7e,0xff,0x7d,0x00,0x7e,0x01,0x7d,0x02,0x7e, - 0x02,0x7f,0x03,0x00,0x02,0x01,0x02,0x02,0x01,0x03, - 0x00,0x02,0xff,0x03,0xfe,0x02,0xfe,0x01,0xfd,0x00, - 0x0b,0xf2,0x04,0x8e,0x00,0x6b,0x00,0x92,0x02,0x02, - 0x02,0x01,0x03,0x00,0x02,0x7f,0x02,0x7e,0x01,0x7d, - 0x00,0x7e,0xff,0x7d,0xfe,0x7e,0xfe,0x7f,0xfd,0x00, - 0xfe,0x01,0xfe,0x02,0x0f,0xfd,0x0f,0x8e,0x00,0x6b, - 0x00,0x92,0xfe,0x02,0xfe,0x01,0xfd,0x00,0xfe,0x7f, - 0xfe,0x7e,0xff,0x7d,0x00,0x7e,0x01,0x7d,0x02,0x7e, - 0x02,0x7f,0x03,0x00,0x02,0x01,0x02,0x02,0x04,0xfd, - 0x04,0x8e,0x00,0x72,0x00,0x88,0x01,0x03,0x02,0x02, - 0x02,0x01,0x03,0x00,0x01,0xf2,0x0e,0x8b,0xff,0x02, - 0xfd,0x01,0xfd,0x00,0xfd,0x7f,0xff,0x7e,0x01,0x7e, - 0x02,0x7f,0x05,0x7f,0x02,0x7f,0x01,0x7e,0x00,0x7f, - 0xff,0x7e,0xfd,0x7f,0xfd,0x00,0xfd,0x01,0xff,0x02, - 0x0e,0xfd,0x05,0x95,0x00,0x6f,0x01,0x7d,0x02,0x7f, - 0x02,0x00,0xf8,0x8e,0x07,0x00,0x03,0xf2,0x04,0x8e, - 0x00,0x76,0x01,0x7d,0x02,0x7f,0x03,0x00,0x02,0x01, - 0x03,0x03,0x00,0x8a,0x00,0x72,0x04,0x80,0x02,0x8e, - 0x06,0x72,0x06,0x8e,0xfa,0x72,0x08,0x80,0x03,0x8e, - 0x04,0x72,0x04,0x8e,0xfc,0x72,0x04,0x8e,0x04,0x72, - 0x04,0x8e,0xfc,0x72,0x07,0x80,0x03,0x8e,0x0b,0x72, - 0x00,0x8e,0xf5,0x72,0x0e,0x80,0x02,0x8e,0x06,0x72, - 0x06,0x8e,0xfa,0x72,0xfe,0x7c,0xfe,0x7e,0xfe,0x7f, - 0xff,0x00,0x0f,0x87,0x0e,0x8e,0xf5,0x72,0x00,0x8e, - 0x0b,0x00,0xf5,0xf2,0x0b,0x00,0x03,0x80,0x09,0x99, - 0xfe,0x7f,0xff,0x7f,0xff,0x7e,0x00,0x7e,0x01,0x7e, - 0x01,0x7f,0x01,0x7e,0x00,0x7e,0xfe,0x7e,0x01,0x8e, - 0xff,0x7e,0x00,0x7e,0x01,0x7e,0x01,0x7f,0x01,0x7e, - 0x00,0x7e,0xff,0x7e,0xfc,0x7e,0x04,0x7e,0x01,0x7e, - 0x00,0x7e,0xff,0x7e,0xff,0x7f,0xff,0x7e,0x00,0x7e, - 0x01,0x7e,0xff,0x8e,0x02,0x7e,0x00,0x7e,0xff,0x7e, - 0xff,0x7f,0xff,0x7e,0x00,0x7e,0x01,0x7e,0x01,0x7f, - 0x02,0x7f,0x05,0x87,0x04,0x95,0x00,0x77,0x00,0xfd, - 0x00,0x77,0x04,0x80,0x05,0x99,0x02,0x7f,0x01,0x7f, - 0x01,0x7e,0x00,0x7e,0xff,0x7e,0xff,0x7f,0xff,0x7e, - 0x00,0x7e,0x02,0x7e,0xff,0x8e,0x01,0x7e,0x00,0x7e, - 0xff,0x7e,0xff,0x7f,0xff,0x7e,0x00,0x7e,0x01,0x7e, - 0x04,0x7e,0xfc,0x7e,0xff,0x7e,0x00,0x7e,0x01,0x7e, - 0x01,0x7f,0x01,0x7e,0x00,0x7e,0xff,0x7e,0x01,0x8e, - 0xfe,0x7e,0x00,0x7e,0x01,0x7e,0x01,0x7f,0x01,0x7e, - 0x00,0x7e,0xff,0x7e,0xff,0x7f,0xfe,0x7f,0x09,0x87, - 0x03,0x86,0x00,0x02,0x01,0x03,0x02,0x01,0x02,0x00, - 0x02,0x7f,0x04,0x7d,0x02,0x7f,0x02,0x00,0x02,0x01, - 0x01,0x02,0xee,0xfe,0x01,0x02,0x02,0x01,0x02,0x00, - 0x02,0x7f,0x04,0x7d,0x02,0x7f,0x02,0x00,0x02,0x01, - 0x01,0x03,0x00,0x02,0x03,0xf4,0x10,0x80,0x03,0x80, - 0x07,0x15,0x08,0x6b,0xfe,0x85,0xf5,0x00,0x10,0xfb, - 0x0d,0x95,0xf6,0x00,0x00,0x6b,0x0a,0x00,0x02,0x02, - 0x00,0x08,0xfe,0x02,0xf6,0x00,0x0e,0xf4,0x03,0x80, - 0x00,0x15,0x0a,0x00,0x02,0x7e,0x00,0x7e,0x00,0x7d, - 0x00,0x7e,0xfe,0x7f,0xf6,0x00,0x0a,0x80,0x02,0x7e, - 0x01,0x7e,0x00,0x7d,0xff,0x7d,0xfe,0x7f,0xf6,0x00, - 0x10,0x80,0x03,0x80,0x00,0x15,0x0c,0x00,0xff,0x7e, - 0x03,0xed,0x03,0xfd,0x00,0x03,0x02,0x00,0x00,0x12, - 0x02,0x03,0x0a,0x00,0x00,0x6b,0x02,0x00,0x00,0x7d, - 0xfe,0x83,0xf4,0x00,0x11,0x80,0x0f,0x80,0xf4,0x00, - 0x00,0x15,0x0c,0x00,0xff,0xf6,0xf5,0x00,0x0f,0xf5, - 0x04,0x95,0x07,0x76,0x00,0x0a,0x07,0x80,0xf9,0x76, - 0x00,0x75,0xf8,0x80,0x07,0x0c,0x09,0xf4,0xf9,0x0c, - 0x09,0xf4,0x03,0x92,0x02,0x03,0x07,0x00,0x03,0x7d, - 0x00,0x7b,0xfc,0x7e,0x04,0x7d,0x00,0x7a,0xfd,0x7e, - 0xf9,0x00,0xfe,0x02,0x06,0x89,0x02,0x00,0x06,0xf5, - 0x03,0x95,0x00,0x6b,0x0c,0x15,0x00,0x6b,0x02,0x80, - 0x03,0x95,0x00,0x6b,0x0c,0x15,0x00,0x6b,0xf8,0x96, - 0x03,0x00,0x07,0xea,0x03,0x80,0x00,0x15,0x0c,0x80, - 0xf7,0x76,0xfd,0x00,0x03,0x80,0x0a,0x75,0x03,0x80, - 0x03,0x80,0x07,0x13,0x02,0x02,0x03,0x00,0x00,0x6b, - 0x02,0x80,0x03,0x80,0x00,0x15,0x09,0x6b,0x09,0x15, - 0x00,0x6b,0x03,0x80,0x03,0x80,0x00,0x15,0x00,0xf6, - 0x0d,0x00,0x00,0x8a,0x00,0x6b,0x03,0x80,0x07,0x80, - 0xfd,0x00,0xff,0x03,0x00,0x04,0x00,0x07,0x00,0x04, - 0x01,0x02,0x03,0x01,0x06,0x00,0x03,0x7f,0x01,0x7e, - 0x01,0x7c,0x00,0x79,0xff,0x7c,0xff,0x7d,0xfd,0x00, - 0xfa,0x00,0x0e,0x80,0x03,0x80,0x00,0x15,0x0c,0x00, - 0x00,0x6b,0x02,0x80,0x03,0x80,0x00,0x15,0x0a,0x00, - 0x02,0x7f,0x01,0x7d,0x00,0x7b,0xff,0x7e,0xfe,0x7f, - 0xf6,0x00,0x10,0xf7,0x11,0x8f,0xff,0x03,0xff,0x02, - 0xfe,0x01,0xfa,0x00,0xfd,0x7f,0xff,0x7e,0x00,0x7c, - 0x00,0x79,0x00,0x7b,0x01,0x7e,0x03,0x00,0x06,0x00, - 0x02,0x00,0x01,0x03,0x01,0x02,0x03,0xfb,0x03,0x95, - 0x0c,0x00,0xfa,0x80,0x00,0x6b,0x09,0x80,0x03,0x95, - 0x00,0x77,0x06,0x7a,0x06,0x06,0x00,0x09,0xfa,0xf1, - 0xfa,0x7a,0x0e,0x80,0x03,0x87,0x00,0x0b,0x02,0x02, - 0x03,0x00,0x02,0x7e,0x01,0x02,0x04,0x00,0x02,0x7e, - 0x00,0x75,0xfe,0x7e,0xfc,0x00,0xff,0x01,0xfe,0x7f, - 0xfd,0x00,0xfe,0x02,0x07,0x8e,0x00,0x6b,0x09,0x80, - 0x03,0x80,0x0e,0x15,0xf2,0x80,0x0e,0x6b,0x03,0x80, - 0x03,0x95,0x00,0x6b,0x0e,0x00,0x00,0x7d,0xfe,0x98, - 0x00,0x6b,0x05,0x80,0x03,0x95,0x00,0x75,0x02,0x7d, - 0x0a,0x00,0x00,0x8e,0x00,0x6b,0x02,0x80,0x03,0x95, - 0x00,0x6b,0x10,0x00,0x00,0x15,0xf8,0x80,0x00,0x6b, - 0x0a,0x80,0x03,0x95,0x00,0x6b,0x10,0x00,0x00,0x15, - 0xf8,0x80,0x00,0x6b,0x0a,0x00,0x00,0x7d,0x02,0x83, - 0x10,0x80,0x03,0x95,0x00,0x6b,0x09,0x00,0x03,0x02, - 0x00,0x08,0xfd,0x02,0xf7,0x00,0x0e,0x89,0x00,0x6b, - 0x03,0x80,0x03,0x95,0x00,0x6b,0x09,0x00,0x03,0x02, - 0x00,0x08,0xfd,0x02,0xf7,0x00,0x0e,0xf4,0x03,0x92, - 0x02,0x03,0x07,0x00,0x03,0x7d,0x00,0x70,0xfd,0x7e, - 0xf9,0x00,0xfe,0x02,0x03,0x89,0x09,0x00,0x02,0xf5, - 0x03,0x80,0x00,0x15,0x00,0xf5,0x07,0x00,0x00,0x08, - 0x02,0x03,0x06,0x00,0x02,0x7d,0x00,0x70,0xfe,0x7e, - 0xfa,0x00,0xfe,0x02,0x00,0x08,0x0c,0xf6,0x0f,0x80, - 0x00,0x15,0xf6,0x00,0xfe,0x7d,0x00,0x79,0x02,0x7e, - 0x0a,0x00,0xf4,0xf7,0x07,0x09,0x07,0xf7,0x03,0x8c, - 0x01,0x02,0x01,0x01,0x05,0x00,0x02,0x7f,0x01,0x7e, - 0x00,0x74,0x00,0x86,0xff,0x01,0xfe,0x01,0xfb,0x00, - 0xff,0x7f,0xff,0x7f,0x00,0x7c,0x01,0x7e,0x01,0x00, - 0x05,0x00,0x02,0x00,0x01,0x02,0x03,0xfe,0x04,0x8e, - 0x02,0x01,0x04,0x00,0x02,0x7f,0x01,0x7e,0x00,0x77, - 0xff,0x7e,0xfe,0x7f,0xfc,0x00,0xfe,0x01,0xff,0x02, - 0x00,0x09,0x01,0x02,0x02,0x02,0x03,0x01,0x02,0x01, - 0x01,0x01,0x01,0x02,0x02,0xeb,0x03,0x80,0x00,0x15, - 0x03,0x00,0x02,0x7e,0x00,0x7b,0xfe,0x7e,0xfd,0x00, - 0x03,0x80,0x04,0x00,0x03,0x7e,0x00,0x78,0xfd,0x7e, - 0xf9,0x00,0x0c,0x80,0x03,0x8c,0x02,0x02,0x02,0x01, - 0x03,0x00,0x02,0x7f,0x01,0x7d,0xfe,0x7e,0xf9,0x7d, - 0xff,0x7e,0x00,0x7d,0x03,0x7f,0x02,0x00,0x03,0x01, - 0x02,0x01,0x02,0xfe,0x0d,0x8c,0xff,0x02,0xfe,0x01, - 0xfc,0x00,0xfe,0x7f,0xff,0x7e,0x00,0x77,0x01,0x7e, - 0x02,0x7f,0x04,0x00,0x02,0x01,0x01,0x02,0x00,0x0f, - 0xff,0x02,0xfe,0x01,0xf9,0x00,0x0c,0xeb,0x03,0x88, - 0x0a,0x00,0x00,0x02,0x00,0x03,0xfe,0x02,0xfa,0x00, - 0xff,0x7e,0xff,0x7d,0x00,0x7b,0x01,0x7c,0x01,0x7f, - 0x06,0x00,0x02,0x02,0x03,0xfe,0x03,0x8f,0x06,0x77, - 0x06,0x09,0xfa,0x80,0x00,0x71,0xff,0x87,0xfb,0x79, - 0x07,0x87,0x05,0x79,0x02,0x80,0x03,0x8d,0x02,0x02, - 0x06,0x00,0x02,0x7e,0x00,0x7d,0xfc,0x7d,0x04,0x7e, - 0x00,0x7d,0xfe,0x7e,0xfa,0x00,0xfe,0x02,0x04,0x85, - 0x02,0x00,0x06,0xf9,0x03,0x8f,0x00,0x73,0x01,0x7e, - 0x07,0x00,0x02,0x02,0x00,0x0d,0x00,0xf3,0x01,0x7e, - 0x03,0x80,0x03,0x8f,0x00,0x73,0x01,0x7e,0x07,0x00, - 0x02,0x02,0x00,0x0d,0x00,0xf3,0x01,0x7e,0xf8,0x90, - 0x03,0x00,0x08,0xf0,0x03,0x80,0x00,0x15,0x00,0xf3, - 0x02,0x00,0x06,0x07,0xfa,0xf9,0x07,0x78,0x03,0x80, - 0x03,0x80,0x04,0x0c,0x02,0x03,0x04,0x00,0x00,0x71, - 0x02,0x80,0x03,0x80,0x00,0x0f,0x06,0x77,0x06,0x09, - 0x00,0x71,0x02,0x80,0x03,0x80,0x00,0x0f,0x0a,0xf1, - 0x00,0x0f,0xf6,0xf8,0x0a,0x00,0x02,0xf9,0x05,0x80, - 0xff,0x01,0xff,0x04,0x00,0x05,0x01,0x03,0x01,0x02, - 0x06,0x00,0x02,0x7e,0x00,0x7d,0x00,0x7b,0x00,0x7c, - 0xfe,0x7f,0xfa,0x00,0x0b,0x80,0x03,0x80,0x00,0x0f, - 0x00,0xfb,0x01,0x03,0x01,0x02,0x05,0x00,0x02,0x7e, - 0x01,0x7d,0x00,0x76,0x03,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0x10,0x80, - 0x10,0x80,0x0a,0x8f,0x02,0x7f,0x01,0x7e,0x00,0x76, - 0xff,0x7f,0xfe,0x7f,0xfb,0x00,0xff,0x01,0xff,0x01, - 0x00,0x0a,0x01,0x02,0x01,0x01,0x05,0x00,0xf9,0x80, - 0x00,0x6b,0x0c,0x86,0x0d,0x8a,0xff,0x03,0xfe,0x02, - 0xfb,0x00,0xff,0x7e,0xff,0x7d,0x00,0x7b,0x01,0x7c, - 0x01,0x7f,0x05,0x00,0x02,0x01,0x01,0x03,0x03,0xfc, - 0x03,0x80,0x00,0x0f,0x00,0xfb,0x01,0x03,0x01,0x02, - 0x04,0x00,0x01,0x7e,0x01,0x7d,0x00,0x76,0x00,0x8a, - 0x01,0x03,0x02,0x02,0x03,0x00,0x02,0x7e,0x01,0x7d, - 0x00,0x76,0x03,0x80,0x03,0x8f,0x00,0x74,0x01,0x7e, - 0x02,0x7f,0x04,0x00,0x02,0x01,0x01,0x01,0x00,0x8d, - 0x00,0x6e,0xff,0x7e,0xfe,0x7f,0xfb,0x00,0xfe,0x01, - 0x0c,0x85,0x03,0x8d,0x01,0x02,0x03,0x00,0x02,0x7e, - 0x01,0x02,0x03,0x00,0x02,0x7e,0x00,0x74,0xfe,0x7f, - 0xfd,0x00,0xff,0x01,0xfe,0x7f,0xfd,0x00,0xff,0x01, - 0x00,0x0c,0x06,0x82,0x00,0x6b,0x08,0x86,0x03,0x80, - 0x0a,0x0f,0xf6,0x80,0x0a,0x71,0x03,0x80,0x03,0x8f, - 0x00,0x73,0x01,0x7e,0x07,0x00,0x02,0x02,0x00,0x0d, - 0x00,0xf3,0x01,0x7e,0x00,0x7e,0x03,0x82,0x03,0x8f, - 0x00,0x79,0x02,0x7e,0x08,0x00,0x00,0x89,0x00,0x71, - 0x02,0x80,0x03,0x8f,0x00,0x73,0x01,0x7e,0x03,0x00, - 0x02,0x02,0x00,0x0d,0x00,0xf3,0x01,0x7e,0x03,0x00, - 0x02,0x02,0x00,0x0d,0x00,0xf3,0x01,0x7e,0x03,0x80, - 0x03,0x8f,0x00,0x73,0x01,0x7e,0x03,0x00,0x02,0x02, - 0x00,0x0d,0x00,0xf3,0x01,0x7e,0x03,0x00,0x02,0x02, - 0x00,0x0d,0x00,0xf3,0x01,0x7e,0x00,0x7e,0x03,0x82, - 0x03,0x8d,0x00,0x02,0x02,0x00,0x00,0x71,0x08,0x00, - 0x02,0x02,0x00,0x06,0xfe,0x02,0xf8,0x00,0x0c,0xf6, - 0x03,0x8f,0x00,0x71,0x07,0x00,0x02,0x02,0x00,0x06, - 0xfe,0x02,0xf9,0x00,0x0c,0x85,0x00,0x71,0x02,0x80, - 0x03,0x8f,0x00,0x71,0x07,0x00,0x03,0x02,0x00,0x06, - 0xfd,0x02,0xf9,0x00,0x0c,0xf6,0x03,0x8d,0x02,0x02, - 0x06,0x00,0x02,0x7e,0x00,0x75,0xfe,0x7e,0xfa,0x00, - 0xfe,0x02,0x04,0x85,0x06,0x00,0x02,0xf9,0x03,0x80, - 0x00,0x0f,0x00,0xf8,0x04,0x00,0x00,0x06,0x02,0x02, - 0x04,0x00,0x02,0x7e,0x00,0x75,0xfe,0x7e,0xfc,0x00, - 0xfe,0x02,0x00,0x05,0x0a,0xf9,0x0d,0x80,0x00,0x0f, - 0xf7,0x00,0xff,0x7e,0x00,0x7b,0x01,0x7e,0x09,0x00, - 0xf6,0xfa,0x04,0x06,0x08,0xfa - }; - - //------------------------------------------------------------------------- - gsv_text::gsv_text() : - m_x(0.0), - m_y(0.0), - m_start_x(0.0), - m_width(10.0), - m_height(0.0), - m_space(0.0), - m_line_space(0.0), - m_text(m_chr), - m_text_buf(), - m_cur_chr(m_chr), - m_font(gsv_default_font), - m_loaded_font(), - m_status(initial), - m_big_endian(false), - m_flip(false) - { - m_chr[0] = m_chr[1] = 0; - - int t = 1; - if(*(char*)&t == 0) m_big_endian = true; - } - - //------------------------------------------------------------------------- - void gsv_text::font(const void* font) - { - m_font = font; - if(m_font == 0) m_font = &m_loaded_font[0]; - } - - //------------------------------------------------------------------------- - void gsv_text::size(double height, double width) - { - m_height = height; - m_width = width; - } - - //------------------------------------------------------------------------- - void gsv_text::space(double space) - { - m_space = space; - } - - //------------------------------------------------------------------------- - void gsv_text::line_space(double line_space) - { - m_line_space = line_space; - } - - //------------------------------------------------------------------------- - void gsv_text::start_point(double x, double y) - { - m_x = m_start_x = x; - m_y = y; - //if(m_flip) m_y += m_height; - } - - //------------------------------------------------------------------------- - void gsv_text::load_font(const char* file) - { - m_loaded_font.resize(0); - FILE* fd = fopen(file, "rb"); - if(fd) - { - unsigned len; - - fseek(fd, 0l, SEEK_END); - len = ftell(fd); - fseek(fd, 0l, SEEK_SET); - if(len > 0) - { - m_loaded_font.resize(len); - fread(&m_loaded_font[0], 1, len, fd); - m_font = &m_loaded_font[0]; - } - fclose(fd); - } - } - - //------------------------------------------------------------------------- - void gsv_text::text(const char* text) - { - if(text == 0) - { - m_chr[0] = 0; - m_text = m_chr; - return; - } - unsigned new_size = strlen(text) + 1; - if(new_size > m_text_buf.size()) - { - m_text_buf.resize(new_size); - } - memcpy(&m_text_buf[0], text, new_size); - m_text = &m_text_buf[0]; - } - - //------------------------------------------------------------------------- - void gsv_text::rewind(unsigned) - { - m_status = initial; - if(m_font == 0) return; - - m_indices = (int8u*)m_font; - double base_height = value(m_indices + 4); - m_indices += value(m_indices); - m_glyphs = (int8*)(m_indices + 257*2); - m_h = m_height / base_height; - m_w = (m_width == 0.0) ? m_h : m_width / base_height; - if(m_flip) m_h = -m_h; - m_cur_chr = m_text; - } - - //------------------------------------------------------------------------- - unsigned gsv_text::vertex(double* x, double* y) - { - unsigned idx; - int8 yc, yf; - int dx, dy; - bool quit = false; - - while(!quit) - { - switch(m_status) - { - case initial: - if(m_font == 0) - { - quit = true; - break; - } - m_status = next_char; - - case next_char: - if(*m_cur_chr == 0) - { - quit = true; - break; - } - idx = (*m_cur_chr++) & 0xFF; - if(idx == '\n') - { - m_x = m_start_x; - m_y -= m_flip ? -m_height - m_line_space : m_height + m_line_space; - break; - } - idx <<= 1; - m_bglyph = m_glyphs + value(m_indices + idx); - m_eglyph = m_glyphs + value(m_indices + idx + 2); - m_status = start_glyph; - - case start_glyph: - *x = m_x; - *y = m_y; - m_status = glyph; - return path_cmd_move_to; - - case glyph: - if(m_bglyph >= m_eglyph) - { - m_status = next_char; - m_x += m_space; - break; - } - dx = int(*m_bglyph++); - yf = (yc = *m_bglyph++) & 0x80; - yc <<= 1; - yc >>= 1; - dy = int(yc); - m_x += double(dx) * m_w; - m_y += double(dy) * m_h; - *x = m_x; - *y = m_y; - return yf ? path_cmd_move_to : path_cmd_line_to; - } - - } - return path_cmd_stop; - } - - //------------------------------------------------------------------------- - double gsv_text::text_width() - { - double x1, y1, x2, y2; - bounding_rect_single(*this, 0, &x1, &y1, &x2, &y2); - return x2 - x1; - } - - -} diff -Nru corsix-th-0.30/agg/src/agg_image_filters.cpp corsix-th-0.62/agg/src/agg_image_filters.cpp --- corsix-th-0.30/agg/src/agg_image_filters.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_image_filters.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Filtering class image_filter_lut implemantation -// -//---------------------------------------------------------------------------- - - -#include "agg_image_filters.h" - - -namespace agg -{ - //-------------------------------------------------------------------- - void image_filter_lut::realloc_lut(double radius) - { - m_radius = radius; - m_diameter = uceil(radius) * 2; - m_start = -int(m_diameter / 2 - 1); - unsigned size = m_diameter << image_subpixel_shift; - if(size > m_weight_array.size()) - { - m_weight_array.resize(size); - } - } - - - - //-------------------------------------------------------------------- - // This function normalizes integer values and corrects the rounding - // errors. It doesn't do anything with the source floating point values - // (m_weight_array_dbl), it corrects only integers according to the rule - // of 1.0 which means that any sum of pixel weights must be equal to 1.0. - // So, the filter function must produce a graph of the proper shape. - //-------------------------------------------------------------------- - void image_filter_lut::normalize() - { - unsigned i; - int flip = 1; - - for(i = 0; i < image_subpixel_scale; i++) - { - for(;;) - { - int sum = 0; - unsigned j; - for(j = 0; j < m_diameter; j++) - { - sum += m_weight_array[j * image_subpixel_scale + i]; - } - - if(sum == image_filter_scale) break; - - double k = double(image_filter_scale) / double(sum); - sum = 0; - for(j = 0; j < m_diameter; j++) - { - sum += m_weight_array[j * image_subpixel_scale + i] = - iround(m_weight_array[j * image_subpixel_scale + i] * k); - } - - sum -= image_filter_scale; - int inc = (sum > 0) ? -1 : 1; - - for(j = 0; j < m_diameter && sum; j++) - { - flip ^= 1; - unsigned idx = flip ? m_diameter/2 + j/2 : m_diameter/2 - j/2; - int v = m_weight_array[idx * image_subpixel_scale + i]; - if(v < image_filter_scale) - { - m_weight_array[idx * image_subpixel_scale + i] += inc; - sum += inc; - } - } - } - } - - unsigned pivot = m_diameter << (image_subpixel_shift - 1); - - for(i = 0; i < pivot; i++) - { - m_weight_array[pivot + i] = m_weight_array[pivot - i]; - } - unsigned end = (diameter() << image_subpixel_shift) - 1; - m_weight_array[0] = m_weight_array[end]; - } - - -} - diff -Nru corsix-th-0.30/agg/src/agg_line_aa_basics.cpp corsix-th-0.62/agg/src/agg_line_aa_basics.cpp --- corsix-th-0.30/agg/src/agg_line_aa_basics.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_line_aa_basics.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include -#include "agg_line_aa_basics.h" - -namespace agg -{ - //------------------------------------------------------------------------- - // The number of the octant is determined as a 3-bit value as follows: - // bit 0 = vertical flag - // bit 1 = sx < 0 - // bit 2 = sy < 0 - // - // [N] shows the number of the orthogonal quadrant - // shows the number of the diagonal quadrant - // <1> - // [1] | [0] - // . (3)011 | 001(1) . - // . | . - // . | . - // . | . - // (2)010 .|. 000(0) - // <2> ----------.+.----------- <0> - // (6)110 . | . 100(4) - // . | . - // . | . - // . | . - // (7)111 | 101(5) - // [2] | [3] - // <3> - // 0,1,2,3,4,5,6,7 - const int8u line_parameters::s_orthogonal_quadrant[8] = { 0,0,1,1,3,3,2,2 }; - const int8u line_parameters::s_diagonal_quadrant[8] = { 0,1,2,1,0,3,2,3 }; - - - - //------------------------------------------------------------------------- - void bisectrix(const line_parameters& l1, - const line_parameters& l2, - int* x, int* y) - { - double k = double(l2.len) / double(l1.len); - double tx = l2.x2 - (l2.x1 - l1.x1) * k; - double ty = l2.y2 - (l2.y1 - l1.y1) * k; - - //All bisectrices must be on the right of the line - //If the next point is on the left (l1 => l2.2) - //then the bisectix should be rotated by 180 degrees. - if(double(l2.x2 - l2.x1) * double(l2.y1 - l1.y1) < - double(l2.y2 - l2.y1) * double(l2.x1 - l1.x1) + 100.0) - { - tx -= (tx - l2.x1) * 2.0; - ty -= (ty - l2.y1) * 2.0; - } - - // Check if the bisectrix is too short - double dx = tx - l2.x1; - double dy = ty - l2.y1; - if((int)sqrt(dx * dx + dy * dy) < line_subpixel_scale) - { - *x = (l2.x1 + l2.x1 + (l2.y1 - l1.y1) + (l2.y2 - l2.y1)) >> 1; - *y = (l2.y1 + l2.y1 - (l2.x1 - l1.x1) - (l2.x2 - l2.x1)) >> 1; - return; - } - *x = iround(tx); - *y = iround(ty); - } - -} diff -Nru corsix-th-0.30/agg/src/agg_line_profile_aa.cpp corsix-th-0.62/agg/src/agg_line_profile_aa.cpp --- corsix-th-0.30/agg/src/agg_line_profile_aa.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_line_profile_aa.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include "agg_renderer_outline_aa.h" - -namespace agg -{ - - //--------------------------------------------------------------------- - void line_profile_aa::width(double w) - { - if(w < 0.0) w = 0.0; - - if(w < m_smoother_width) w += w; - else w += m_smoother_width; - - w *= 0.5; - - w -= m_smoother_width; - double s = m_smoother_width; - if(w < 0.0) - { - s += w; - w = 0.0; - } - set(w, s); - } - - - //--------------------------------------------------------------------- - line_profile_aa::value_type* line_profile_aa::profile(double w) - { - m_subpixel_width = uround(w * subpixel_scale); - unsigned size = m_subpixel_width + subpixel_scale * 6; - if(size > m_profile.size()) - { - m_profile.resize(size); - } - return &m_profile[0]; - } - - - //--------------------------------------------------------------------- - void line_profile_aa::set(double center_width, double smoother_width) - { - double base_val = 1.0; - if(center_width == 0.0) center_width = 1.0 / subpixel_scale; - if(smoother_width == 0.0) smoother_width = 1.0 / subpixel_scale; - - double width = center_width + smoother_width; - if(width < m_min_width) - { - double k = width / m_min_width; - base_val *= k; - center_width /= k; - smoother_width /= k; - } - - value_type* ch = profile(center_width + smoother_width); - - unsigned subpixel_center_width = unsigned(center_width * subpixel_scale); - unsigned subpixel_smoother_width = unsigned(smoother_width * subpixel_scale); - - value_type* ch_center = ch + subpixel_scale*2; - value_type* ch_smoother = ch_center + subpixel_center_width; - - unsigned i; - - unsigned val = m_gamma[unsigned(base_val * aa_mask)]; - ch = ch_center; - for(i = 0; i < subpixel_center_width; i++) - { - *ch++ = (value_type)val; - } - - for(i = 0; i < subpixel_smoother_width; i++) - { - *ch_smoother++ = - m_gamma[unsigned((base_val - - base_val * - (double(i) / subpixel_smoother_width)) * aa_mask)]; - } - - unsigned n_smoother = profile_size() - - subpixel_smoother_width - - subpixel_center_width - - subpixel_scale*2; - - val = m_gamma[0]; - for(i = 0; i < n_smoother; i++) - { - *ch_smoother++ = (value_type)val; - } - - ch = ch_center; - for(i = 0; i < subpixel_scale*2; i++) - { - *--ch = *ch_center++; - } - } - - -} - diff -Nru corsix-th-0.30/agg/src/agg_rounded_rect.cpp corsix-th-0.62/agg/src/agg_rounded_rect.cpp --- corsix-th-0.30/agg/src/agg_rounded_rect.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_rounded_rect.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Rounded rectangle vertex generator -// -//---------------------------------------------------------------------------- - -#include -#include "agg_rounded_rect.h" - - -namespace agg -{ - //------------------------------------------------------------------------ - rounded_rect::rounded_rect(double x1, double y1, double x2, double y2, double r) : - m_x1(x1), m_y1(y1), m_x2(x2), m_y2(y2), - m_rx1(r), m_ry1(r), m_rx2(r), m_ry2(r), - m_rx3(r), m_ry3(r), m_rx4(r), m_ry4(r) - { - if(x1 > x2) { m_x1 = x2; m_x2 = x1; } - if(y1 > y2) { m_y1 = y2; m_y2 = y1; } - } - - //-------------------------------------------------------------------- - void rounded_rect::rect(double x1, double y1, double x2, double y2) - { - m_x1 = x1; - m_y1 = y1; - m_x2 = x2; - m_y2 = y2; - if(x1 > x2) { m_x1 = x2; m_x2 = x1; } - if(y1 > y2) { m_y1 = y2; m_y2 = y1; } - } - - //-------------------------------------------------------------------- - void rounded_rect::radius(double r) - { - m_rx1 = m_ry1 = m_rx2 = m_ry2 = m_rx3 = m_ry3 = m_rx4 = m_ry4 = r; - } - - //-------------------------------------------------------------------- - void rounded_rect::radius(double rx, double ry) - { - m_rx1 = m_rx2 = m_rx3 = m_rx4 = rx; - m_ry1 = m_ry2 = m_ry3 = m_ry4 = ry; - } - - //-------------------------------------------------------------------- - void rounded_rect::radius(double rx_bottom, double ry_bottom, - double rx_top, double ry_top) - { - m_rx1 = m_rx2 = rx_bottom; - m_rx3 = m_rx4 = rx_top; - m_ry1 = m_ry2 = ry_bottom; - m_ry3 = m_ry4 = ry_top; - } - - //-------------------------------------------------------------------- - void rounded_rect::radius(double rx1, double ry1, double rx2, double ry2, - double rx3, double ry3, double rx4, double ry4) - { - m_rx1 = rx1; m_ry1 = ry1; m_rx2 = rx2; m_ry2 = ry2; - m_rx3 = rx3; m_ry3 = ry3; m_rx4 = rx4; m_ry4 = ry4; - } - - //-------------------------------------------------------------------- - void rounded_rect::normalize_radius() - { - double dx = fabs(m_y2 - m_y1); - double dy = fabs(m_x2 - m_x1); - - double k = 1.0; - double t; - t = dx / (m_rx1 + m_rx2); if(t < k) k = t; - t = dx / (m_rx3 + m_rx4); if(t < k) k = t; - t = dy / (m_ry1 + m_ry2); if(t < k) k = t; - t = dy / (m_ry3 + m_ry4); if(t < k) k = t; - - if(k < 1.0) - { - m_rx1 *= k; m_ry1 *= k; m_rx2 *= k; m_ry2 *= k; - m_rx3 *= k; m_ry3 *= k; m_rx4 *= k; m_ry4 *= k; - } - } - - //-------------------------------------------------------------------- - void rounded_rect::rewind(unsigned) - { - m_status = 0; - } - - //-------------------------------------------------------------------- - unsigned rounded_rect::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_stop; - switch(m_status) - { - case 0: - m_arc.init(m_x1 + m_rx1, m_y1 + m_ry1, m_rx1, m_ry1, - pi, pi+pi*0.5); - m_arc.rewind(0); - m_status++; - - case 1: - cmd = m_arc.vertex(x, y); - if(is_stop(cmd)) m_status++; - else return cmd; - - case 2: - m_arc.init(m_x2 - m_rx2, m_y1 + m_ry2, m_rx2, m_ry2, - pi+pi*0.5, 0.0); - m_arc.rewind(0); - m_status++; - - case 3: - cmd = m_arc.vertex(x, y); - if(is_stop(cmd)) m_status++; - else return path_cmd_line_to; - - case 4: - m_arc.init(m_x2 - m_rx3, m_y2 - m_ry3, m_rx3, m_ry3, - 0.0, pi*0.5); - m_arc.rewind(0); - m_status++; - - case 5: - cmd = m_arc.vertex(x, y); - if(is_stop(cmd)) m_status++; - else return path_cmd_line_to; - - case 6: - m_arc.init(m_x1 + m_rx4, m_y2 - m_ry4, m_rx4, m_ry4, - pi*0.5, pi); - m_arc.rewind(0); - m_status++; - - case 7: - cmd = m_arc.vertex(x, y); - if(is_stop(cmd)) m_status++; - else return path_cmd_line_to; - - case 8: - cmd = path_cmd_end_poly | path_flags_close | path_flags_ccw; - m_status++; - break; - } - return cmd; - } - - -} - diff -Nru corsix-th-0.30/agg/src/agg_sqrt_tables.cpp corsix-th-0.62/agg/src/agg_sqrt_tables.cpp --- corsix-th-0.30/agg/src/agg_sqrt_tables.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_sqrt_tables.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// static tables for fast integer sqrt -// -//---------------------------------------------------------------------------- - -#include "agg_basics.h" - -namespace agg -{ - int16u g_sqrt_table[1024] = //----------g_sqrt_table - { - 0, - 2048,2896,3547,4096,4579,5017,5418,5793,6144,6476,6792,7094,7384,7663,7932,8192,8444, - 8689,8927,9159,9385,9606,9822,10033,10240,10443,10642,10837,11029,11217,11403,11585, - 11765,11942,12116,12288,12457,12625,12790,12953,13114,13273,13430,13585,13738,13890, - 14040,14189,14336,14482,14626,14768,14910,15050,15188,15326,15462,15597,15731,15864, - 15995,16126,16255,16384,16512,16638,16764,16888,17012,17135,17257,17378,17498,17618, - 17736,17854,17971,18087,18203,18318,18432,18545,18658,18770,18882,18992,19102,19212, - 19321,19429,19537,19644,19750,19856,19961,20066,20170,20274,20377,20480,20582,20684, - 20785,20886,20986,21085,21185,21283,21382,21480,21577,21674,21771,21867,21962,22058, - 22153,22247,22341,22435,22528,22621,22713,22806,22897,22989,23080,23170,23261,23351, - 23440,23530,23619,23707,23796,23884,23971,24059,24146,24232,24319,24405,24491,24576, - 24661,24746,24831,24915,24999,25083,25166,25249,25332,25415,25497,25580,25661,25743, - 25824,25905,25986,26067,26147,26227,26307,26387,26466,26545,26624,26703,26781,26859, - 26937,27015,27092,27170,27247,27324,27400,27477,27553,27629,27705,27780,27856,27931, - 28006,28081,28155,28230,28304,28378,28452,28525,28599,28672,28745,28818,28891,28963, - 29035,29108,29180,29251,29323,29394,29466,29537,29608,29678,29749,29819,29890,29960, - 30030,30099,30169,30238,30308,30377,30446,30515,30583,30652,30720,30788,30856,30924, - 30992,31059,31127,31194,31261,31328,31395,31462,31529,31595,31661,31727,31794,31859, - 31925,31991,32056,32122,32187,32252,32317,32382,32446,32511,32575,32640,32704,32768, - 32832,32896,32959,33023,33086,33150,33213,33276,33339,33402,33465,33527,33590,33652, - 33714,33776,33839,33900,33962,34024,34086,34147,34208,34270,34331,34392,34453,34514, - 34574,34635,34695,34756,34816,34876,34936,34996,35056,35116,35176,35235,35295,35354, - 35413,35472,35531,35590,35649,35708,35767,35825,35884,35942,36001,36059,36117,36175, - 36233,36291,36348,36406,36464,36521,36578,36636,36693,36750,36807,36864,36921,36978, - 37034,37091,37147,37204,37260,37316,37372,37429,37485,37540,37596,37652,37708,37763, - 37819,37874,37929,37985,38040,38095,38150,38205,38260,38315,38369,38424,38478,38533, - 38587,38642,38696,38750,38804,38858,38912,38966,39020,39073,39127,39181,39234,39287, - 39341,39394,39447,39500,39553,39606,39659,39712,39765,39818,39870,39923,39975,40028, - 40080,40132,40185,40237,40289,40341,40393,40445,40497,40548,40600,40652,40703,40755, - 40806,40857,40909,40960,41011,41062,41113,41164,41215,41266,41317,41368,41418,41469, - 41519,41570,41620,41671,41721,41771,41821,41871,41922,41972,42021,42071,42121,42171, - 42221,42270,42320,42369,42419,42468,42518,42567,42616,42665,42714,42763,42813,42861, - 42910,42959,43008,43057,43105,43154,43203,43251,43300,43348,43396,43445,43493,43541, - 43589,43637,43685,43733,43781,43829,43877,43925,43972,44020,44068,44115,44163,44210, - 44258,44305,44352,44400,44447,44494,44541,44588,44635,44682,44729,44776,44823,44869, - 44916,44963,45009,45056,45103,45149,45195,45242,45288,45334,45381,45427,45473,45519, - 45565,45611,45657,45703,45749,45795,45840,45886,45932,45977,46023,46069,46114,46160, - 46205,46250,46296,46341,46386,46431,46477,46522,46567,46612,46657,46702,46746,46791, - 46836,46881,46926,46970,47015,47059,47104,47149,47193,47237,47282,47326,47370,47415, - 47459,47503,47547,47591,47635,47679,47723,47767,47811,47855,47899,47942,47986,48030, - 48074,48117,48161,48204,48248,48291,48335,48378,48421,48465,48508,48551,48594,48637, - 48680,48723,48766,48809,48852,48895,48938,48981,49024,49067,49109,49152,49195,49237, - 49280,49322,49365,49407,49450,49492,49535,49577,49619,49661,49704,49746,49788,49830, - 49872,49914,49956,49998,50040,50082,50124,50166,50207,50249,50291,50332,50374,50416, - 50457,50499,50540,50582,50623,50665,50706,50747,50789,50830,50871,50912,50954,50995, - 51036,51077,51118,51159,51200,51241,51282,51323,51364,51404,51445,51486,51527,51567, - 51608,51649,51689,51730,51770,51811,51851,51892,51932,51972,52013,52053,52093,52134, - 52174,52214,52254,52294,52334,52374,52414,52454,52494,52534,52574,52614,52654,52694, - 52734,52773,52813,52853,52892,52932,52972,53011,53051,53090,53130,53169,53209,53248, - 53287,53327,53366,53405,53445,53484,53523,53562,53601,53640,53679,53719,53758,53797, - 53836,53874,53913,53952,53991,54030,54069,54108,54146,54185,54224,54262,54301,54340, - 54378,54417,54455,54494,54532,54571,54609,54647,54686,54724,54762,54801,54839,54877, - 54915,54954,54992,55030,55068,55106,55144,55182,55220,55258,55296,55334,55372,55410, - 55447,55485,55523,55561,55599,55636,55674,55712,55749,55787,55824,55862,55900,55937, - 55975,56012,56049,56087,56124,56162,56199,56236,56273,56311,56348,56385,56422,56459, - 56497,56534,56571,56608,56645,56682,56719,56756,56793,56830,56867,56903,56940,56977, - 57014,57051,57087,57124,57161,57198,57234,57271,57307,57344,57381,57417,57454,57490, - 57527,57563,57599,57636,57672,57709,57745,57781,57817,57854,57890,57926,57962,57999, - 58035,58071,58107,58143,58179,58215,58251,58287,58323,58359,58395,58431,58467,58503, - 58538,58574,58610,58646,58682,58717,58753,58789,58824,58860,58896,58931,58967,59002, - 59038,59073,59109,59144,59180,59215,59251,59286,59321,59357,59392,59427,59463,59498, - 59533,59568,59603,59639,59674,59709,59744,59779,59814,59849,59884,59919,59954,59989, - 60024,60059,60094,60129,60164,60199,60233,60268,60303,60338,60373,60407,60442,60477, - 60511,60546,60581,60615,60650,60684,60719,60753,60788,60822,60857,60891,60926,60960, - 60995,61029,61063,61098,61132,61166,61201,61235,61269,61303,61338,61372,61406,61440, - 61474,61508,61542,61576,61610,61644,61678,61712,61746,61780,61814,61848,61882,61916, - 61950,61984,62018,62051,62085,62119,62153,62186,62220,62254,62287,62321,62355,62388, - 62422,62456,62489,62523,62556,62590,62623,62657,62690,62724,62757,62790,62824,62857, - 62891,62924,62957,62991,63024,63057,63090,63124,63157,63190,63223,63256,63289,63323, - 63356,63389,63422,63455,63488,63521,63554,63587,63620,63653,63686,63719,63752,63785, - 63817,63850,63883,63916,63949,63982,64014,64047,64080,64113,64145,64178,64211,64243, - 64276,64309,64341,64374,64406,64439,64471,64504,64536,64569,64601,64634,64666,64699, - 64731,64763,64796,64828,64861,64893,64925,64957,64990,65022,65054,65086,65119,65151, - 65183,65215,65247,65279,65312,65344,65376,65408,65440,65472,65504 - }; - - - int8 g_elder_bit_table[256] = //---------g_elder_bit_table - { - 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 - }; - -} diff -Nru corsix-th-0.30/agg/src/agg_trans_affine.cpp corsix-th-0.62/agg/src/agg_trans_affine.cpp --- corsix-th-0.30/agg/src/agg_trans_affine.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_trans_affine.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,194 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Affine transformations -// -//---------------------------------------------------------------------------- -#include "agg_trans_affine.h" - - - -namespace agg -{ - - //------------------------------------------------------------------------ - const trans_affine& trans_affine::parl_to_parl(const double* src, - const double* dst) - { - sx = src[2] - src[0]; - shy = src[3] - src[1]; - shx = src[4] - src[0]; - sy = src[5] - src[1]; - tx = src[0]; - ty = src[1]; - invert(); - multiply(trans_affine(dst[2] - dst[0], dst[3] - dst[1], - dst[4] - dst[0], dst[5] - dst[1], - dst[0], dst[1])); - return *this; - } - - //------------------------------------------------------------------------ - const trans_affine& trans_affine::rect_to_parl(double x1, double y1, - double x2, double y2, - const double* parl) - { - double src[6]; - src[0] = x1; src[1] = y1; - src[2] = x2; src[3] = y1; - src[4] = x2; src[5] = y2; - parl_to_parl(src, parl); - return *this; - } - - //------------------------------------------------------------------------ - const trans_affine& trans_affine::parl_to_rect(const double* parl, - double x1, double y1, - double x2, double y2) - { - double dst[6]; - dst[0] = x1; dst[1] = y1; - dst[2] = x2; dst[3] = y1; - dst[4] = x2; dst[5] = y2; - parl_to_parl(parl, dst); - return *this; - } - - //------------------------------------------------------------------------ - const trans_affine& trans_affine::multiply(const trans_affine& m) - { - double t0 = sx * m.sx + shy * m.shx; - double t2 = shx * m.sx + sy * m.shx; - double t4 = tx * m.sx + ty * m.shx + m.tx; - shy = sx * m.shy + shy * m.sy; - sy = shx * m.shy + sy * m.sy; - ty = tx * m.shy + ty * m.sy + m.ty; - sx = t0; - shx = t2; - tx = t4; - return *this; - } - - - //------------------------------------------------------------------------ - const trans_affine& trans_affine::invert() - { - double d = determinant_reciprocal(); - - double t0 = sy * d; - sy = sx * d; - shy = -shy * d; - shx = -shx * d; - - double t4 = -tx * t0 - ty * shx; - ty = -tx * shy - ty * sy; - - sx = t0; - tx = t4; - return *this; - } - - - //------------------------------------------------------------------------ - const trans_affine& trans_affine::flip_x() - { - sx = -sx; - shy = -shy; - tx = -tx; - return *this; - } - - //------------------------------------------------------------------------ - const trans_affine& trans_affine::flip_y() - { - shx = -shx; - sy = -sy; - ty = -ty; - return *this; - } - - //------------------------------------------------------------------------ - const trans_affine& trans_affine::reset() - { - sx = sy = 1.0; - shy = shx = tx = ty = 0.0; - return *this; - } - - //------------------------------------------------------------------------ - bool trans_affine::is_identity(double epsilon) const - { - return is_equal_eps(sx, 1.0, epsilon) && - is_equal_eps(shy, 0.0, epsilon) && - is_equal_eps(shx, 0.0, epsilon) && - is_equal_eps(sy, 1.0, epsilon) && - is_equal_eps(tx, 0.0, epsilon) && - is_equal_eps(ty, 0.0, epsilon); - } - - //------------------------------------------------------------------------ - bool trans_affine::is_valid(double epsilon) const - { - return fabs(sx) > epsilon && fabs(sy) > epsilon; - } - - //------------------------------------------------------------------------ - bool trans_affine::is_equal(const trans_affine& m, double epsilon) const - { - return is_equal_eps(sx, m.sx, epsilon) && - is_equal_eps(shy, m.shy, epsilon) && - is_equal_eps(shx, m.shx, epsilon) && - is_equal_eps(sy, m.sy, epsilon) && - is_equal_eps(tx, m.tx, epsilon) && - is_equal_eps(ty, m.ty, epsilon); - } - - //------------------------------------------------------------------------ - double trans_affine::rotation() const - { - double x1 = 0.0; - double y1 = 0.0; - double x2 = 1.0; - double y2 = 0.0; - transform(&x1, &y1); - transform(&x2, &y2); - return atan2(y2-y1, x2-x1); - } - - //------------------------------------------------------------------------ - void trans_affine::translation(double* dx, double* dy) const - { - *dx = tx; - *dy = ty; - } - - //------------------------------------------------------------------------ - void trans_affine::scaling(double* x, double* y) const - { - double x1 = 0.0; - double y1 = 0.0; - double x2 = 1.0; - double y2 = 1.0; - trans_affine t(*this); - t *= trans_affine_rotation(-rotation()); - t.transform(&x1, &y1); - t.transform(&x2, &y2); - *x = x2 - x1; - *y = y2 - y1; - } - - -} - diff -Nru corsix-th-0.30/agg/src/agg_trans_double_path.cpp corsix-th-0.62/agg/src/agg_trans_double_path.cpp --- corsix-th-0.30/agg/src/agg_trans_double_path.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_trans_double_path.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,273 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include "agg_math.h" -#include "agg_trans_double_path.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - trans_double_path::trans_double_path() : - m_kindex1(0.0), - m_kindex2(0.0), - m_base_length(0.0), - m_base_height(1.0), - m_status1(initial), - m_status2(initial), - m_preserve_x_scale(true) - { - } - - - //------------------------------------------------------------------------ - void trans_double_path::reset() - { - m_src_vertices1.remove_all(); - m_src_vertices2.remove_all(); - m_kindex1 = 0.0; - m_kindex1 = 0.0; - m_status1 = initial; - m_status2 = initial; - } - - - //------------------------------------------------------------------------ - void trans_double_path::move_to1(double x, double y) - { - if(m_status1 == initial) - { - m_src_vertices1.modify_last(vertex_dist(x, y)); - m_status1 = making_path; - } - else - { - line_to1(x, y); - } - } - - - //------------------------------------------------------------------------ - void trans_double_path::line_to1(double x, double y) - { - if(m_status1 == making_path) - { - m_src_vertices1.add(vertex_dist(x, y)); - } - } - - - //------------------------------------------------------------------------ - void trans_double_path::move_to2(double x, double y) - { - if(m_status2 == initial) - { - m_src_vertices2.modify_last(vertex_dist(x, y)); - m_status2 = making_path; - } - else - { - line_to2(x, y); - } - } - - - //------------------------------------------------------------------------ - void trans_double_path::line_to2(double x, double y) - { - if(m_status2 == making_path) - { - m_src_vertices2.add(vertex_dist(x, y)); - } - } - - - //------------------------------------------------------------------------ - double trans_double_path::finalize_path(vertex_storage& vertices) - { - unsigned i; - double dist; - double d; - - vertices.close(false); - if(vertices.size() > 2) - { - if(vertices[vertices.size() - 2].dist * 10.0 < - vertices[vertices.size() - 3].dist) - { - d = vertices[vertices.size() - 3].dist + - vertices[vertices.size() - 2].dist; - - vertices[vertices.size() - 2] = - vertices[vertices.size() - 1]; - - vertices.remove_last(); - vertices[vertices.size() - 2].dist = d; - } - } - - dist = 0; - for(i = 0; i < vertices.size(); i++) - { - vertex_dist& v = vertices[i]; - d = v.dist; - v.dist = dist; - dist += d; - } - - return (vertices.size() - 1) / dist; - } - - - //------------------------------------------------------------------------ - void trans_double_path::finalize_paths() - { - if(m_status1 == making_path && m_src_vertices1.size() > 1 && - m_status2 == making_path && m_src_vertices2.size() > 1) - { - m_kindex1 = finalize_path(m_src_vertices1); - m_kindex2 = finalize_path(m_src_vertices2); - m_status1 = ready; - m_status2 = ready; - } - } - - - //------------------------------------------------------------------------ - double trans_double_path::total_length1() const - { - if(m_base_length >= 1e-10) return m_base_length; - return (m_status1 == ready) ? - m_src_vertices1[m_src_vertices1.size() - 1].dist : - 0.0; - } - - - //------------------------------------------------------------------------ - double trans_double_path::total_length2() const - { - if(m_base_length >= 1e-10) return m_base_length; - return (m_status2 == ready) ? - m_src_vertices2[m_src_vertices2.size() - 1].dist : - 0.0; - } - - - //------------------------------------------------------------------------ - void trans_double_path::transform1(const vertex_storage& vertices, - double kindex, double kx, - double *x, double* y) const - { - double x1 = 0.0; - double y1 = 0.0; - double dx = 1.0; - double dy = 1.0; - double d = 0.0; - double dd = 1.0; - *x *= kx; - if(*x < 0.0) - { - // Extrapolation on the left - //-------------------------- - x1 = vertices[0].x; - y1 = vertices[0].y; - dx = vertices[1].x - x1; - dy = vertices[1].y - y1; - dd = vertices[1].dist - vertices[0].dist; - d = *x; - } - else - if(*x > vertices[vertices.size() - 1].dist) - { - // Extrapolation on the right - //-------------------------- - unsigned i = vertices.size() - 2; - unsigned j = vertices.size() - 1; - x1 = vertices[j].x; - y1 = vertices[j].y; - dx = x1 - vertices[i].x; - dy = y1 - vertices[i].y; - dd = vertices[j].dist - vertices[i].dist; - d = *x - vertices[j].dist; - } - else - { - // Interpolation - //-------------------------- - unsigned i = 0; - unsigned j = vertices.size() - 1; - if(m_preserve_x_scale) - { - unsigned k; - for(i = 0; (j - i) > 1; ) - { - if(*x < vertices[k = (i + j) >> 1].dist) - { - j = k; - } - else - { - i = k; - } - } - d = vertices[i].dist; - dd = vertices[j].dist - d; - d = *x - d; - } - else - { - i = unsigned(*x * kindex); - j = i + 1; - dd = vertices[j].dist - vertices[i].dist; - d = ((*x * kindex) - i) * dd; - } - x1 = vertices[i].x; - y1 = vertices[i].y; - dx = vertices[j].x - x1; - dy = vertices[j].y - y1; - } - *x = x1 + dx * d / dd; - *y = y1 + dy * d / dd; - } - - - //------------------------------------------------------------------------ - void trans_double_path::transform(double *x, double *y) const - { - if(m_status1 == ready && m_status2 == ready) - { - if(m_base_length > 1e-10) - { - *x *= m_src_vertices1[m_src_vertices1.size() - 1].dist / - m_base_length; - } - - double x1 = *x; - double y1 = *y; - double x2 = *x; - double y2 = *y; - double dd = m_src_vertices2[m_src_vertices2.size() - 1].dist / - m_src_vertices1[m_src_vertices1.size() - 1].dist; - - transform1(m_src_vertices1, m_kindex1, 1.0, &x1, &y1); - transform1(m_src_vertices2, m_kindex2, dd, &x2, &y2); - - *x = x1 + *y * (x2 - x1) / m_base_height; - *y = y1 + *y * (y2 - y1) / m_base_height; - } - } - -} - diff -Nru corsix-th-0.30/agg/src/agg_trans_single_path.cpp corsix-th-0.62/agg/src/agg_trans_single_path.cpp --- corsix-th-0.30/agg/src/agg_trans_single_path.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_trans_single_path.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,202 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include "agg_math.h" -#include "agg_vertex_sequence.h" -#include "agg_trans_single_path.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - trans_single_path::trans_single_path() : - m_base_length(0.0), - m_kindex(0.0), - m_status(initial), - m_preserve_x_scale(true) - { - } - - //------------------------------------------------------------------------ - void trans_single_path::reset() - { - m_src_vertices.remove_all(); - m_kindex = 0.0; - m_status = initial; - } - - //------------------------------------------------------------------------ - void trans_single_path::move_to(double x, double y) - { - if(m_status == initial) - { - m_src_vertices.modify_last(vertex_dist(x, y)); - m_status = making_path; - } - else - { - line_to(x, y); - } - } - - //------------------------------------------------------------------------ - void trans_single_path::line_to(double x, double y) - { - if(m_status == making_path) - { - m_src_vertices.add(vertex_dist(x, y)); - } - } - - - //------------------------------------------------------------------------ - void trans_single_path::finalize_path() - { - if(m_status == making_path && m_src_vertices.size() > 1) - { - unsigned i; - double dist; - double d; - - m_src_vertices.close(false); - if(m_src_vertices.size() > 2) - { - if(m_src_vertices[m_src_vertices.size() - 2].dist * 10.0 < - m_src_vertices[m_src_vertices.size() - 3].dist) - { - d = m_src_vertices[m_src_vertices.size() - 3].dist + - m_src_vertices[m_src_vertices.size() - 2].dist; - - m_src_vertices[m_src_vertices.size() - 2] = - m_src_vertices[m_src_vertices.size() - 1]; - - m_src_vertices.remove_last(); - m_src_vertices[m_src_vertices.size() - 2].dist = d; - } - } - - dist = 0.0; - for(i = 0; i < m_src_vertices.size(); i++) - { - vertex_dist& v = m_src_vertices[i]; - double d = v.dist; - v.dist = dist; - dist += d; - } - m_kindex = (m_src_vertices.size() - 1) / dist; - m_status = ready; - } - } - - - - //------------------------------------------------------------------------ - double trans_single_path::total_length() const - { - if(m_base_length >= 1e-10) return m_base_length; - return (m_status == ready) ? - m_src_vertices[m_src_vertices.size() - 1].dist : - 0.0; - } - - - //------------------------------------------------------------------------ - void trans_single_path::transform(double *x, double *y) const - { - if(m_status == ready) - { - if(m_base_length > 1e-10) - { - *x *= m_src_vertices[m_src_vertices.size() - 1].dist / - m_base_length; - } - - double x1 = 0.0; - double y1 = 0.0; - double dx = 1.0; - double dy = 1.0; - double d = 0.0; - double dd = 1.0; - if(*x < 0.0) - { - // Extrapolation on the left - //-------------------------- - x1 = m_src_vertices[0].x; - y1 = m_src_vertices[0].y; - dx = m_src_vertices[1].x - x1; - dy = m_src_vertices[1].y - y1; - dd = m_src_vertices[1].dist - m_src_vertices[0].dist; - d = *x; - } - else - if(*x > m_src_vertices[m_src_vertices.size() - 1].dist) - { - // Extrapolation on the right - //-------------------------- - unsigned i = m_src_vertices.size() - 2; - unsigned j = m_src_vertices.size() - 1; - x1 = m_src_vertices[j].x; - y1 = m_src_vertices[j].y; - dx = x1 - m_src_vertices[i].x; - dy = y1 - m_src_vertices[i].y; - dd = m_src_vertices[j].dist - m_src_vertices[i].dist; - d = *x - m_src_vertices[j].dist; - } - else - { - // Interpolation - //-------------------------- - unsigned i = 0; - unsigned j = m_src_vertices.size() - 1; - if(m_preserve_x_scale) - { - unsigned k; - for(i = 0; (j - i) > 1; ) - { - if(*x < m_src_vertices[k = (i + j) >> 1].dist) - { - j = k; - } - else - { - i = k; - } - } - d = m_src_vertices[i].dist; - dd = m_src_vertices[j].dist - d; - d = *x - d; - } - else - { - i = unsigned(*x * m_kindex); - j = i + 1; - dd = m_src_vertices[j].dist - m_src_vertices[i].dist; - d = ((*x * m_kindex) - i) * dd; - } - x1 = m_src_vertices[i].x; - y1 = m_src_vertices[i].y; - dx = m_src_vertices[j].x - x1; - dy = m_src_vertices[j].y - y1; - } - double x2 = x1 + dx * d / dd; - double y2 = y1 + dy * d / dd; - *x = x2 - *y * dy / dd; - *y = y2 + *y * dx / dd; - } - } - - -} - diff -Nru corsix-th-0.30/agg/src/agg_trans_warp_magnifier.cpp corsix-th-0.62/agg/src/agg_trans_warp_magnifier.cpp --- corsix-th-0.30/agg/src/agg_trans_warp_magnifier.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_trans_warp_magnifier.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include -#include "agg_trans_warp_magnifier.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - void trans_warp_magnifier::transform(double* x, double* y) const - { - double dx = *x - m_xc; - double dy = *y - m_yc; - double r = sqrt(dx * dx + dy * dy); - if(r < m_radius) - { - *x = m_xc + dx * m_magn; - *y = m_yc + dy * m_magn; - return; - } - - double m = (r + m_radius * (m_magn - 1.0)) / r; - *x = m_xc + dx * m; - *y = m_yc + dy * m; - } - - //------------------------------------------------------------------------ - void trans_warp_magnifier::inverse_transform(double* x, double* y) const - { - // New version by Andrew Skalkin - //----------------- - double dx = *x - m_xc; - double dy = *y - m_yc; - double r = sqrt(dx * dx + dy * dy); - - if(r < m_radius * m_magn) - { - *x = m_xc + dx / m_magn; - *y = m_yc + dy / m_magn; - } - else - { - double rnew = r - m_radius * (m_magn - 1.0); - *x = m_xc + rnew * dx / r; - *y = m_yc + rnew * dy / r; - } - - // Old version - //----------------- - //trans_warp_magnifier t(*this); - //t.magnification(1.0 / m_magn); - //t.radius(m_radius * m_magn); - //t.transform(x, y); - } - - -} diff -Nru corsix-th-0.30/agg/src/agg_vcgen_bspline.cpp corsix-th-0.62/agg/src/agg_vcgen_bspline.cpp --- corsix-th-0.30/agg/src/agg_vcgen_bspline.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vcgen_bspline.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,194 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include "agg_vcgen_bspline.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - vcgen_bspline::vcgen_bspline() : - m_src_vertices(), - m_spline_x(), - m_spline_y(), - m_interpolation_step(1.0/50.0), - m_closed(0), - m_status(initial), - m_src_vertex(0) - { - } - - - //------------------------------------------------------------------------ - void vcgen_bspline::remove_all() - { - m_src_vertices.remove_all(); - m_closed = 0; - m_status = initial; - m_src_vertex = 0; - } - - - //------------------------------------------------------------------------ - void vcgen_bspline::add_vertex(double x, double y, unsigned cmd) - { - m_status = initial; - if(is_move_to(cmd)) - { - m_src_vertices.modify_last(point_d(x, y)); - } - else - { - if(is_vertex(cmd)) - { - m_src_vertices.add(point_d(x, y)); - } - else - { - m_closed = get_close_flag(cmd); - } - } - } - - - //------------------------------------------------------------------------ - void vcgen_bspline::rewind(unsigned) - { - m_cur_abscissa = 0.0; - m_max_abscissa = 0.0; - m_src_vertex = 0; - if(m_status == initial && m_src_vertices.size() > 2) - { - if(m_closed) - { - m_spline_x.init(m_src_vertices.size() + 8); - m_spline_y.init(m_src_vertices.size() + 8); - m_spline_x.add_point(0.0, m_src_vertices.prev(m_src_vertices.size() - 3).x); - m_spline_y.add_point(0.0, m_src_vertices.prev(m_src_vertices.size() - 3).y); - m_spline_x.add_point(1.0, m_src_vertices[m_src_vertices.size() - 3].x); - m_spline_y.add_point(1.0, m_src_vertices[m_src_vertices.size() - 3].y); - m_spline_x.add_point(2.0, m_src_vertices[m_src_vertices.size() - 2].x); - m_spline_y.add_point(2.0, m_src_vertices[m_src_vertices.size() - 2].y); - m_spline_x.add_point(3.0, m_src_vertices[m_src_vertices.size() - 1].x); - m_spline_y.add_point(3.0, m_src_vertices[m_src_vertices.size() - 1].y); - } - else - { - m_spline_x.init(m_src_vertices.size()); - m_spline_y.init(m_src_vertices.size()); - } - unsigned i; - for(i = 0; i < m_src_vertices.size(); i++) - { - double x = m_closed ? i + 4 : i; - m_spline_x.add_point(x, m_src_vertices[i].x); - m_spline_y.add_point(x, m_src_vertices[i].y); - } - m_cur_abscissa = 0.0; - m_max_abscissa = m_src_vertices.size() - 1; - if(m_closed) - { - m_cur_abscissa = 4.0; - m_max_abscissa += 5.0; - m_spline_x.add_point(m_src_vertices.size() + 4, m_src_vertices[0].x); - m_spline_y.add_point(m_src_vertices.size() + 4, m_src_vertices[0].y); - m_spline_x.add_point(m_src_vertices.size() + 5, m_src_vertices[1].x); - m_spline_y.add_point(m_src_vertices.size() + 5, m_src_vertices[1].y); - m_spline_x.add_point(m_src_vertices.size() + 6, m_src_vertices[2].x); - m_spline_y.add_point(m_src_vertices.size() + 6, m_src_vertices[2].y); - m_spline_x.add_point(m_src_vertices.size() + 7, m_src_vertices.next(2).x); - m_spline_y.add_point(m_src_vertices.size() + 7, m_src_vertices.next(2).y); - } - m_spline_x.prepare(); - m_spline_y.prepare(); - } - m_status = ready; - } - - - - - - - //------------------------------------------------------------------------ - unsigned vcgen_bspline::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_line_to; - while(!is_stop(cmd)) - { - switch(m_status) - { - case initial: - rewind(0); - - case ready: - if(m_src_vertices.size() < 2) - { - cmd = path_cmd_stop; - break; - } - - if(m_src_vertices.size() == 2) - { - *x = m_src_vertices[m_src_vertex].x; - *y = m_src_vertices[m_src_vertex].y; - m_src_vertex++; - if(m_src_vertex == 1) return path_cmd_move_to; - if(m_src_vertex == 2) return path_cmd_line_to; - cmd = path_cmd_stop; - break; - } - - cmd = path_cmd_move_to; - m_status = polygon; - m_src_vertex = 0; - - case polygon: - if(m_cur_abscissa >= m_max_abscissa) - { - if(m_closed) - { - m_status = end_poly; - break; - } - else - { - *x = m_src_vertices[m_src_vertices.size() - 1].x; - *y = m_src_vertices[m_src_vertices.size() - 1].y; - m_status = end_poly; - return path_cmd_line_to; - } - } - - *x = m_spline_x.get_stateful(m_cur_abscissa); - *y = m_spline_y.get_stateful(m_cur_abscissa); - m_src_vertex++; - m_cur_abscissa += m_interpolation_step; - return (m_src_vertex == 1) ? path_cmd_move_to : path_cmd_line_to; - - case end_poly: - m_status = stop; - return path_cmd_end_poly | m_closed; - - case stop: - return path_cmd_stop; - } - } - return cmd; - } - - -} - diff -Nru corsix-th-0.30/agg/src/agg_vcgen_contour.cpp corsix-th-0.62/agg/src/agg_vcgen_contour.cpp --- corsix-th-0.30/agg/src/agg_vcgen_contour.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vcgen_contour.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Contour generator -// -//---------------------------------------------------------------------------- - -#include -#include "agg_vcgen_contour.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - vcgen_contour::vcgen_contour() : - m_stroker(), - m_width(1), - m_src_vertices(), - m_out_vertices(), - m_status(initial), - m_src_vertex(0), - m_closed(0), - m_orientation(0), - m_auto_detect(false) - { - } - - //------------------------------------------------------------------------ - void vcgen_contour::remove_all() - { - m_src_vertices.remove_all(); - m_closed = 0; - m_orientation = 0; - m_status = initial; - } - - //------------------------------------------------------------------------ - void vcgen_contour::add_vertex(double x, double y, unsigned cmd) - { - m_status = initial; - if(is_move_to(cmd)) - { - m_src_vertices.modify_last(vertex_dist(x, y)); - } - else - { - if(is_vertex(cmd)) - { - m_src_vertices.add(vertex_dist(x, y)); - } - else - { - if(is_end_poly(cmd)) - { - m_closed = get_close_flag(cmd); - if(m_orientation == path_flags_none) - { - m_orientation = get_orientation(cmd); - } - } - } - } - } - - //------------------------------------------------------------------------ - void vcgen_contour::rewind(unsigned) - { - if(m_status == initial) - { - m_src_vertices.close(true); - if(m_auto_detect) - { - if(!is_oriented(m_orientation)) - { - m_orientation = (calc_polygon_area(m_src_vertices) > 0.0) ? - path_flags_ccw : - path_flags_cw; - } - } - if(is_oriented(m_orientation)) - { - m_stroker.width(is_ccw(m_orientation) ? m_width : -m_width); - } - } - m_status = ready; - m_src_vertex = 0; - } - - //------------------------------------------------------------------------ - unsigned vcgen_contour::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_line_to; - while(!is_stop(cmd)) - { - switch(m_status) - { - case initial: - rewind(0); - - case ready: - if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) - { - cmd = path_cmd_stop; - break; - } - m_status = outline; - cmd = path_cmd_move_to; - m_src_vertex = 0; - m_out_vertex = 0; - - case outline: - if(m_src_vertex >= m_src_vertices.size()) - { - m_status = end_poly; - break; - } - m_stroker.calc_join(m_out_vertices, - m_src_vertices.prev(m_src_vertex), - m_src_vertices.curr(m_src_vertex), - m_src_vertices.next(m_src_vertex), - m_src_vertices.prev(m_src_vertex).dist, - m_src_vertices.curr(m_src_vertex).dist); - ++m_src_vertex; - m_status = out_vertices; - m_out_vertex = 0; - - case out_vertices: - if(m_out_vertex >= m_out_vertices.size()) - { - m_status = outline; - } - else - { - const point_d& c = m_out_vertices[m_out_vertex++]; - *x = c.x; - *y = c.y; - return cmd; - } - break; - - case end_poly: - if(!m_closed) return path_cmd_stop; - m_status = stop; - return path_cmd_end_poly | path_flags_close | path_flags_ccw; - - case stop: - return path_cmd_stop; - } - } - return cmd; - } - -} diff -Nru corsix-th-0.30/agg/src/agg_vcgen_dash.cpp corsix-th-0.62/agg/src/agg_vcgen_dash.cpp --- corsix-th-0.30/agg/src/agg_vcgen_dash.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vcgen_dash.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,235 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Line dash generator -// -//---------------------------------------------------------------------------- - -#include -#include "agg_vcgen_dash.h" -#include "agg_shorten_path.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - vcgen_dash::vcgen_dash() : - m_total_dash_len(0.0), - m_num_dashes(0), - m_dash_start(0.0), - m_shorten(0.0), - m_curr_dash_start(0.0), - m_curr_dash(0), - m_src_vertices(), - m_closed(0), - m_status(initial), - m_src_vertex(0) - { - } - - - - //------------------------------------------------------------------------ - void vcgen_dash::remove_all_dashes() - { - m_total_dash_len = 0.0; - m_num_dashes = 0; - m_curr_dash_start = 0.0; - m_curr_dash = 0; - } - - - //------------------------------------------------------------------------ - void vcgen_dash::add_dash(double dash_len, double gap_len) - { - if(m_num_dashes < max_dashes) - { - m_total_dash_len += dash_len + gap_len; - m_dashes[m_num_dashes++] = dash_len; - m_dashes[m_num_dashes++] = gap_len; - } - } - - - //------------------------------------------------------------------------ - void vcgen_dash::dash_start(double ds) - { - m_dash_start = ds; - calc_dash_start(fabs(ds)); - } - - - //------------------------------------------------------------------------ - void vcgen_dash::calc_dash_start(double ds) - { - m_curr_dash = 0; - m_curr_dash_start = 0.0; - while(ds > 0.0) - { - if(ds > m_dashes[m_curr_dash]) - { - ds -= m_dashes[m_curr_dash]; - ++m_curr_dash; - m_curr_dash_start = 0.0; - if(m_curr_dash >= m_num_dashes) m_curr_dash = 0; - } - else - { - m_curr_dash_start = ds; - ds = 0.0; - } - } - } - - - //------------------------------------------------------------------------ - void vcgen_dash::remove_all() - { - m_status = initial; - m_src_vertices.remove_all(); - m_closed = 0; - } - - - //------------------------------------------------------------------------ - void vcgen_dash::add_vertex(double x, double y, unsigned cmd) - { - m_status = initial; - if(is_move_to(cmd)) - { - m_src_vertices.modify_last(vertex_dist(x, y)); - } - else - { - if(is_vertex(cmd)) - { - m_src_vertices.add(vertex_dist(x, y)); - } - else - { - m_closed = get_close_flag(cmd); - } - } - } - - - //------------------------------------------------------------------------ - void vcgen_dash::rewind(unsigned) - { - if(m_status == initial) - { - m_src_vertices.close(m_closed != 0); - shorten_path(m_src_vertices, m_shorten, m_closed); - } - m_status = ready; - m_src_vertex = 0; - } - - - //------------------------------------------------------------------------ - unsigned vcgen_dash::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_move_to; - while(!is_stop(cmd)) - { - switch(m_status) - { - case initial: - rewind(0); - - case ready: - if(m_num_dashes < 2 || m_src_vertices.size() < 2) - { - cmd = path_cmd_stop; - break; - } - m_status = polyline; - m_src_vertex = 1; - m_v1 = &m_src_vertices[0]; - m_v2 = &m_src_vertices[1]; - m_curr_rest = m_v1->dist; - *x = m_v1->x; - *y = m_v1->y; - if(m_dash_start >= 0.0) calc_dash_start(m_dash_start); - return path_cmd_move_to; - - case polyline: - { - double dash_rest = m_dashes[m_curr_dash] - m_curr_dash_start; - - unsigned cmd = (m_curr_dash & 1) ? - path_cmd_move_to : - path_cmd_line_to; - - if(m_curr_rest > dash_rest) - { - m_curr_rest -= dash_rest; - ++m_curr_dash; - if(m_curr_dash >= m_num_dashes) m_curr_dash = 0; - m_curr_dash_start = 0.0; - *x = m_v2->x - (m_v2->x - m_v1->x) * m_curr_rest / m_v1->dist; - *y = m_v2->y - (m_v2->y - m_v1->y) * m_curr_rest / m_v1->dist; - } - else - { - m_curr_dash_start += m_curr_rest; - *x = m_v2->x; - *y = m_v2->y; - ++m_src_vertex; - m_v1 = m_v2; - m_curr_rest = m_v1->dist; - if(m_closed) - { - if(m_src_vertex > m_src_vertices.size()) - { - m_status = stop; - } - else - { - m_v2 = &m_src_vertices - [ - (m_src_vertex >= m_src_vertices.size()) ? 0 : - m_src_vertex - ]; - } - } - else - { - if(m_src_vertex >= m_src_vertices.size()) - { - m_status = stop; - } - else - { - m_v2 = &m_src_vertices[m_src_vertex]; - } - } - } - return cmd; - } - break; - - case stop: - cmd = path_cmd_stop; - break; - } - - } - return path_cmd_stop; - } - - -} - diff -Nru corsix-th-0.30/agg/src/agg_vcgen_markers_term.cpp corsix-th-0.62/agg/src/agg_vcgen_markers_term.cpp --- corsix-th-0.30/agg/src/agg_vcgen_markers_term.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vcgen_markers_term.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Terminal markers generator (arrowhead/arrowtail) -// -//---------------------------------------------------------------------------- - -#include "agg_vcgen_markers_term.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - void vcgen_markers_term::remove_all() - { - m_markers.remove_all(); - } - - - //------------------------------------------------------------------------ - void vcgen_markers_term::add_vertex(double x, double y, unsigned cmd) - { - if(is_move_to(cmd)) - { - if(m_markers.size() & 1) - { - // Initial state, the first coordinate was added. - // If two of more calls of start_vertex() occures - // we just modify the last one. - m_markers.modify_last(coord_type(x, y)); - } - else - { - m_markers.add(coord_type(x, y)); - } - } - else - { - if(is_vertex(cmd)) - { - if(m_markers.size() & 1) - { - // Initial state, the first coordinate was added. - // Add three more points, 0,1,1,0 - m_markers.add(coord_type(x, y)); - m_markers.add(m_markers[m_markers.size() - 1]); - m_markers.add(m_markers[m_markers.size() - 3]); - } - else - { - if(m_markers.size()) - { - // Replace two last points: 0,1,1,0 -> 0,1,2,1 - m_markers[m_markers.size() - 1] = m_markers[m_markers.size() - 2]; - m_markers[m_markers.size() - 2] = coord_type(x, y); - } - } - } - } - } - - - //------------------------------------------------------------------------ - void vcgen_markers_term::rewind(unsigned path_id) - { - m_curr_id = path_id * 2; - m_curr_idx = m_curr_id; - } - - - //------------------------------------------------------------------------ - unsigned vcgen_markers_term::vertex(double* x, double* y) - { - if(m_curr_id > 2 || m_curr_idx >= m_markers.size()) - { - return path_cmd_stop; - } - const coord_type& c = m_markers[m_curr_idx]; - *x = c.x; - *y = c.y; - if(m_curr_idx & 1) - { - m_curr_idx += 3; - return path_cmd_line_to; - } - ++m_curr_idx; - return path_cmd_move_to; - } - - -} diff -Nru corsix-th-0.30/agg/src/agg_vcgen_smooth_poly1.cpp corsix-th-0.62/agg/src/agg_vcgen_smooth_poly1.cpp --- corsix-th-0.30/agg/src/agg_vcgen_smooth_poly1.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vcgen_smooth_poly1.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Smooth polygon generator -// -//---------------------------------------------------------------------------- - -#include "agg_vcgen_smooth_poly1.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - vcgen_smooth_poly1::vcgen_smooth_poly1() : - m_src_vertices(), - m_smooth_value(0.5), - m_closed(0), - m_status(initial), - m_src_vertex(0) - { - } - - - //------------------------------------------------------------------------ - void vcgen_smooth_poly1::remove_all() - { - m_src_vertices.remove_all(); - m_closed = 0; - m_status = initial; - } - - - //------------------------------------------------------------------------ - void vcgen_smooth_poly1::add_vertex(double x, double y, unsigned cmd) - { - m_status = initial; - if(is_move_to(cmd)) - { - m_src_vertices.modify_last(vertex_dist(x, y)); - } - else - { - if(is_vertex(cmd)) - { - m_src_vertices.add(vertex_dist(x, y)); - } - else - { - m_closed = get_close_flag(cmd); - } - } - } - - - //------------------------------------------------------------------------ - void vcgen_smooth_poly1::rewind(unsigned) - { - if(m_status == initial) - { - m_src_vertices.close(m_closed != 0); - } - m_status = ready; - m_src_vertex = 0; - } - - - //------------------------------------------------------------------------ - void vcgen_smooth_poly1::calculate(const vertex_dist& v0, - const vertex_dist& v1, - const vertex_dist& v2, - const vertex_dist& v3) - { - - double k1 = v0.dist / (v0.dist + v1.dist); - double k2 = v1.dist / (v1.dist + v2.dist); - - double xm1 = v0.x + (v2.x - v0.x) * k1; - double ym1 = v0.y + (v2.y - v0.y) * k1; - double xm2 = v1.x + (v3.x - v1.x) * k2; - double ym2 = v1.y + (v3.y - v1.y) * k2; - - m_ctrl1_x = v1.x + m_smooth_value * (v2.x - xm1); - m_ctrl1_y = v1.y + m_smooth_value * (v2.y - ym1); - m_ctrl2_x = v2.x + m_smooth_value * (v1.x - xm2); - m_ctrl2_y = v2.y + m_smooth_value * (v1.y - ym2); - } - - - //------------------------------------------------------------------------ - unsigned vcgen_smooth_poly1::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_line_to; - while(!is_stop(cmd)) - { - switch(m_status) - { - case initial: - rewind(0); - - case ready: - if(m_src_vertices.size() < 2) - { - cmd = path_cmd_stop; - break; - } - - if(m_src_vertices.size() == 2) - { - *x = m_src_vertices[m_src_vertex].x; - *y = m_src_vertices[m_src_vertex].y; - m_src_vertex++; - if(m_src_vertex == 1) return path_cmd_move_to; - if(m_src_vertex == 2) return path_cmd_line_to; - cmd = path_cmd_stop; - break; - } - - cmd = path_cmd_move_to; - m_status = polygon; - m_src_vertex = 0; - - case polygon: - if(m_closed) - { - if(m_src_vertex >= m_src_vertices.size()) - { - *x = m_src_vertices[0].x; - *y = m_src_vertices[0].y; - m_status = end_poly; - return path_cmd_curve4; - } - } - else - { - if(m_src_vertex >= m_src_vertices.size() - 1) - { - *x = m_src_vertices[m_src_vertices.size() - 1].x; - *y = m_src_vertices[m_src_vertices.size() - 1].y; - m_status = end_poly; - return path_cmd_curve3; - } - } - - calculate(m_src_vertices.prev(m_src_vertex), - m_src_vertices.curr(m_src_vertex), - m_src_vertices.next(m_src_vertex), - m_src_vertices.next(m_src_vertex + 1)); - - *x = m_src_vertices[m_src_vertex].x; - *y = m_src_vertices[m_src_vertex].y; - m_src_vertex++; - - if(m_closed) - { - m_status = ctrl1; - return ((m_src_vertex == 1) ? - path_cmd_move_to : - path_cmd_curve4); - } - else - { - if(m_src_vertex == 1) - { - m_status = ctrl_b; - return path_cmd_move_to; - } - if(m_src_vertex >= m_src_vertices.size() - 1) - { - m_status = ctrl_e; - return path_cmd_curve3; - } - m_status = ctrl1; - return path_cmd_curve4; - } - break; - - case ctrl_b: - *x = m_ctrl2_x; - *y = m_ctrl2_y; - m_status = polygon; - return path_cmd_curve3; - - case ctrl_e: - *x = m_ctrl1_x; - *y = m_ctrl1_y; - m_status = polygon; - return path_cmd_curve3; - - case ctrl1: - *x = m_ctrl1_x; - *y = m_ctrl1_y; - m_status = ctrl2; - return path_cmd_curve4; - - case ctrl2: - *x = m_ctrl2_x; - *y = m_ctrl2_y; - m_status = polygon; - return path_cmd_curve4; - - case end_poly: - m_status = stop; - return path_cmd_end_poly | m_closed; - - case stop: - return path_cmd_stop; - } - } - return cmd; - } - -} - diff -Nru corsix-th-0.30/agg/src/agg_vcgen_stroke.cpp corsix-th-0.62/agg/src/agg_vcgen_stroke.cpp --- corsix-th-0.30/agg/src/agg_vcgen_stroke.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vcgen_stroke.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,213 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Stroke generator -// -//---------------------------------------------------------------------------- -#include -#include "agg_vcgen_stroke.h" -#include "agg_shorten_path.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - vcgen_stroke::vcgen_stroke() : - m_stroker(), - m_src_vertices(), - m_out_vertices(), - m_shorten(0.0), - m_closed(0), - m_status(initial), - m_src_vertex(0), - m_out_vertex(0) - { - } - - //------------------------------------------------------------------------ - void vcgen_stroke::remove_all() - { - m_src_vertices.remove_all(); - m_closed = 0; - m_status = initial; - } - - - //------------------------------------------------------------------------ - void vcgen_stroke::add_vertex(double x, double y, unsigned cmd) - { - m_status = initial; - if(is_move_to(cmd)) - { - m_src_vertices.modify_last(vertex_dist(x, y)); - } - else - { - if(is_vertex(cmd)) - { - m_src_vertices.add(vertex_dist(x, y)); - } - else - { - m_closed = get_close_flag(cmd); - } - } - } - - //------------------------------------------------------------------------ - void vcgen_stroke::rewind(unsigned) - { - if(m_status == initial) - { - m_src_vertices.close(m_closed != 0); - shorten_path(m_src_vertices, m_shorten, m_closed); - if(m_src_vertices.size() < 3) m_closed = 0; - } - m_status = ready; - m_src_vertex = 0; - m_out_vertex = 0; - } - - - //------------------------------------------------------------------------ - unsigned vcgen_stroke::vertex(double* x, double* y) - { - unsigned cmd = path_cmd_line_to; - while(!is_stop(cmd)) - { - switch(m_status) - { - case initial: - rewind(0); - - case ready: - if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) - { - cmd = path_cmd_stop; - break; - } - m_status = m_closed ? outline1 : cap1; - cmd = path_cmd_move_to; - m_src_vertex = 0; - m_out_vertex = 0; - break; - - case cap1: - m_stroker.calc_cap(m_out_vertices, - m_src_vertices[0], - m_src_vertices[1], - m_src_vertices[0].dist); - m_src_vertex = 1; - m_prev_status = outline1; - m_status = out_vertices; - m_out_vertex = 0; - break; - - case cap2: - m_stroker.calc_cap(m_out_vertices, - m_src_vertices[m_src_vertices.size() - 1], - m_src_vertices[m_src_vertices.size() - 2], - m_src_vertices[m_src_vertices.size() - 2].dist); - m_prev_status = outline2; - m_status = out_vertices; - m_out_vertex = 0; - break; - - case outline1: - if(m_closed) - { - if(m_src_vertex >= m_src_vertices.size()) - { - m_prev_status = close_first; - m_status = end_poly1; - break; - } - } - else - { - if(m_src_vertex >= m_src_vertices.size() - 1) - { - m_status = cap2; - break; - } - } - m_stroker.calc_join(m_out_vertices, - m_src_vertices.prev(m_src_vertex), - m_src_vertices.curr(m_src_vertex), - m_src_vertices.next(m_src_vertex), - m_src_vertices.prev(m_src_vertex).dist, - m_src_vertices.curr(m_src_vertex).dist); - ++m_src_vertex; - m_prev_status = m_status; - m_status = out_vertices; - m_out_vertex = 0; - break; - - case close_first: - m_status = outline2; - cmd = path_cmd_move_to; - - case outline2: - if(m_src_vertex <= unsigned(m_closed == 0)) - { - m_status = end_poly2; - m_prev_status = stop; - break; - } - - --m_src_vertex; - m_stroker.calc_join(m_out_vertices, - m_src_vertices.next(m_src_vertex), - m_src_vertices.curr(m_src_vertex), - m_src_vertices.prev(m_src_vertex), - m_src_vertices.curr(m_src_vertex).dist, - m_src_vertices.prev(m_src_vertex).dist); - - m_prev_status = m_status; - m_status = out_vertices; - m_out_vertex = 0; - break; - - case out_vertices: - if(m_out_vertex >= m_out_vertices.size()) - { - m_status = m_prev_status; - } - else - { - const point_d& c = m_out_vertices[m_out_vertex++]; - *x = c.x; - *y = c.y; - return cmd; - } - break; - - case end_poly1: - m_status = m_prev_status; - return path_cmd_end_poly | path_flags_close | path_flags_ccw; - - case end_poly2: - m_status = m_prev_status; - return path_cmd_end_poly | path_flags_close | path_flags_cw; - - case stop: - cmd = path_cmd_stop; - break; - } - } - return cmd; - } - -} diff -Nru corsix-th-0.30/agg/src/agg_vpgen_clip_polygon.cpp corsix-th-0.62/agg/src/agg_vpgen_clip_polygon.cpp --- corsix-th-0.30/agg/src/agg_vpgen_clip_polygon.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vpgen_clip_polygon.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include "agg_vpgen_clip_polygon.h" -#include "agg_clip_liang_barsky.h" - -namespace agg -{ - - //------------------------------------------------------------------------ - // Determine the clipping code of the vertex according to the - // Cyrus-Beck line clipping algorithm - // - // | | - // 0110 | 0010 | 0011 - // | | - // -------+--------+-------- clip_box.y2 - // | | - // 0100 | 0000 | 0001 - // | | - // -------+--------+-------- clip_box.y1 - // | | - // 1100 | 1000 | 1001 - // | | - // clip_box.x1 clip_box.x2 - // - // - unsigned vpgen_clip_polygon::clipping_flags(double x, double y) - { - if(x < m_clip_box.x1) - { - if(y > m_clip_box.y2) return 6; - if(y < m_clip_box.y1) return 12; - return 4; - } - - if(x > m_clip_box.x2) - { - if(y > m_clip_box.y2) return 3; - if(y < m_clip_box.y1) return 9; - return 1; - } - - if(y > m_clip_box.y2) return 2; - if(y < m_clip_box.y1) return 8; - - return 0; - } - - //---------------------------------------------------------------------------- - void vpgen_clip_polygon::reset() - { - m_vertex = 0; - m_num_vertices = 0; - } - - //---------------------------------------------------------------------------- - void vpgen_clip_polygon::move_to(double x, double y) - { - m_vertex = 0; - m_num_vertices = 0; - m_clip_flags = clipping_flags(x, y); - if(m_clip_flags == 0) - { - m_x[0] = x; - m_y[0] = y; - m_num_vertices = 1; - } - m_x1 = x; - m_y1 = y; - m_cmd = path_cmd_move_to; - } - - - //---------------------------------------------------------------------------- - void vpgen_clip_polygon::line_to(double x, double y) - { - m_vertex = 0; - m_num_vertices = 0; - unsigned flags = clipping_flags(x, y); - - if(m_clip_flags == flags) - { - if(flags == 0) - { - m_x[0] = x; - m_y[0] = y; - m_num_vertices = 1; - } - } - else - { - m_num_vertices = clip_liang_barsky(m_x1, m_y1, - x, y, - m_clip_box, - m_x, m_y); - } - - m_clip_flags = flags; - m_x1 = x; - m_y1 = y; - } - - - //---------------------------------------------------------------------------- - unsigned vpgen_clip_polygon::vertex(double* x, double* y) - { - if(m_vertex < m_num_vertices) - { - *x = m_x[m_vertex]; - *y = m_y[m_vertex]; - ++m_vertex; - unsigned cmd = m_cmd; - m_cmd = path_cmd_line_to; - return cmd; - } - return path_cmd_stop; - } - - -} diff -Nru corsix-th-0.30/agg/src/agg_vpgen_clip_polyline.cpp corsix-th-0.62/agg/src/agg_vpgen_clip_polyline.cpp --- corsix-th-0.30/agg/src/agg_vpgen_clip_polyline.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vpgen_clip_polyline.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include "agg_vpgen_clip_polyline.h" -#include "agg_clip_liang_barsky.h" - -namespace agg -{ - //---------------------------------------------------------------------------- - void vpgen_clip_polyline::reset() - { - m_vertex = 0; - m_num_vertices = 0; - m_move_to = false; - } - - //---------------------------------------------------------------------------- - void vpgen_clip_polyline::move_to(double x, double y) - { - m_vertex = 0; - m_num_vertices = 0; - m_x1 = x; - m_y1 = y; - m_move_to = true; - } - - //---------------------------------------------------------------------------- - void vpgen_clip_polyline::line_to(double x, double y) - { - double x2 = x; - double y2 = y; - unsigned flags = clip_line_segment(&m_x1, &m_y1, &x2, &y2, m_clip_box); - - m_vertex = 0; - m_num_vertices = 0; - if((flags & 4) == 0) - { - if((flags & 1) != 0 || m_move_to) - { - m_x[0] = m_x1; - m_y[0] = m_y1; - m_cmd[0] = path_cmd_move_to; - m_num_vertices = 1; - } - m_x[m_num_vertices] = x2; - m_y[m_num_vertices] = y2; - m_cmd[m_num_vertices++] = path_cmd_line_to; - m_move_to = (flags & 2) != 0; - } - m_x1 = x; - m_y1 = y; - } - - //---------------------------------------------------------------------------- - unsigned vpgen_clip_polyline::vertex(double* x, double* y) - { - if(m_vertex < m_num_vertices) - { - *x = m_x[m_vertex]; - *y = m_y[m_vertex]; - return m_cmd[m_vertex++]; - } - return path_cmd_stop; - } -} diff -Nru corsix-th-0.30/agg/src/agg_vpgen_segmentator.cpp corsix-th-0.62/agg/src/agg_vpgen_segmentator.cpp --- corsix-th-0.30/agg/src/agg_vpgen_segmentator.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/agg_vpgen_segmentator.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#include -#include "agg_vpgen_segmentator.h" - -namespace agg -{ - - void vpgen_segmentator::move_to(double x, double y) - { - m_x1 = x; - m_y1 = y; - m_dx = 0.0; - m_dy = 0.0; - m_dl = 2.0; - m_ddl = 2.0; - m_cmd = path_cmd_move_to; - } - - void vpgen_segmentator::line_to(double x, double y) - { - m_x1 += m_dx; - m_y1 += m_dy; - m_dx = x - m_x1; - m_dy = y - m_y1; - double len = sqrt(m_dx * m_dx + m_dy * m_dy) * m_approximation_scale; - if(len < 1e-30) len = 1e-30; - m_ddl = 1.0 / len; - m_dl = (m_cmd == path_cmd_move_to) ? 0.0 : m_ddl; - if(m_cmd == path_cmd_stop) m_cmd = path_cmd_line_to; - } - - unsigned vpgen_segmentator::vertex(double* x, double* y) - { - if(m_cmd == path_cmd_stop) return path_cmd_stop; - - unsigned cmd = m_cmd; - m_cmd = path_cmd_line_to; - if(m_dl >= 1.0 - m_ddl) - { - m_dl = 1.0; - m_cmd = path_cmd_stop; - *x = m_x1 + m_dx; - *y = m_y1 + m_dy; - return cmd; - } - *x = m_x1 + m_dx * m_dl; - *y = m_y1 + m_dy * m_dl; - m_dl += m_ddl; - return cmd; - } - -} - diff -Nru corsix-th-0.30/agg/src/copying corsix-th-0.62/agg/src/copying --- corsix-th-0.30/agg/src/copying 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/copying 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -The Anti-Grain Geometry Project -A high quality rendering engine for C++ -http://antigrain.com - -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) - -Permission to copy, use, modify, sell and distribute this software -is granted provided this copyright notice appears in all copies. -This software is provided "as is" without express or implied -warranty, and with no claim as to its suitability for any purpose. diff -Nru corsix-th-0.30/agg/src/readme corsix-th-0.62/agg/src/readme --- corsix-th-0.30/agg/src/readme 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/agg/src/readme 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -Use automake to build the library. - -If automake is not available you still can use the old make. -There is a very simple Makefile that can be used. Note that -if you use automake it will overwrite Makefile. diff -Nru corsix-th-0.30/AnimView/CMakeLists.txt corsix-th-0.62/AnimView/CMakeLists.txt --- corsix-th-0.30/AnimView/CMakeLists.txt 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/CMakeLists.txt 2018-07-21 11:13:17.000000000 +0000 @@ -1,31 +1,25 @@ # Project Declaration -PROJECT(AnimView) +project(AnimView) # Generate source files list # Note: do not use generic includes (*.cpp and such) this will break things with cmake -SET(animview_source_files +set(animview_source_files app.cpp frmMain.cpp frmSprites.cpp - rnc.cpp + ${CMAKE_SOURCE_DIR}/common/rnc.h + ${CMAKE_SOURCE_DIR}/common/rnc.cpp th.cpp - tinystr.cpp - tinyxml.cpp - tinyxmlerror.cpp - tinyxmlparser.cpp app.h backdrop.h frmMain.h frmSprites.h th.h - tinystr.h - tinyxml.h AnimView.rc ) # Declaration of the executable -IF(APPLE) - +if(APPLE) set(corsixth_icon_file ${CMAKE_SOURCE_DIR}/AnimView/Icon.icns) set_source_files_properties( ${corsixth_icon_file} @@ -43,59 +37,45 @@ set_target_properties(AnimView PROPERTIES LINK_FLAGS_MINSIZEREL "-dead_strip") set_target_properties(AnimView PROPERTIES XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks") - -ELSE() +else() add_executable( AnimView WIN32 # This prevents the dos console showing up ${animview_source_files} ) -ENDIF() +endif() -# Finding libraries +## Finding libraries # Find WxWidgets -SET(wxWidgets_USE_LIBS core base) # optionally: more than wx std libs -FIND_PACKAGE(wxWidgets REQUIRED) -IF(wxWidgets_FOUND) - LINK_LIBRARIES(${wxWidgets_LIBRARIES}) - INCLUDE_DIRECTORIES(${wxWidgets_INCLUDE_DIRS}) - INCLUDE(${wxWidgets_USE_FILE}) - TARGET_LINK_LIBRARIES(AnimView ${wxWidgets_LIBRARIES}) +set(wxWidgets_USE_LIBS core base) # optionally: more than wx std libs +find_package(wxWidgets REQUIRED) +if(wxWidgets_FOUND) + link_libraries(${wxWidgets_LIBRARIES}) + include_directories(${wxWidgets_INCLUDE_DIRS}) + include(${wxWidgets_USE_FILE}) + target_link_libraries(AnimView ${wxWidgets_LIBRARIES}) message(" wxWidgets found") -ELSE(wxWidgets_FOUND) +else() message(FATAL_ERROR "error: wxWdigets library not found, it is required to build") message("Make sure the path is correctly defined or set the environment variable WXWIN to the correct location") -ENDIF(wxWidgets_FOUND) +endif() -# Basic platform dependant stuff -IF(UNIX) - IF(APPLE) - # fruit goes here - ELSE(APPLE) - # regular unix/linux - ENDIF(APPLE) -ELSE(UNIX) - IF(WIN32) - # Win32 specific - IF(MSVC) - # We want to bind against the very latest versions of the MSVC runtimes - add_definitions(/D "_BIND_TO_CURRENT_VCLIBS_VERSION=1") - ELSE(MSVC) - IF(MSYS) - # MSYS stuff - ELSE(MSYS) - # What's left? MINGW? CYGWIN? BORLAND? - ENDIF(MSYS) - ENDIF(MSVC) - ELSE(WIN32) - # other OS (not UNIX, not 32/64 bit Windows) - ENDIF(WIN32) -ENDIF(UNIX) +if(MSVC) + # We want to bind against the very latest versions of the MSVC runtimes + add_definitions(/D "_BIND_TO_CURRENT_VCLIBS_VERSION=1") +endif() -IF(APPLE) +if(APPLE) install(TARGETS AnimView BUNDLE DESTINATION .) -ELSE() + + # Fix the OS X bundle to include required libraries (create a redistributable app) + install(CODE " + INCLUDE(BundleUtilities) + SET(BU_CHMOD_BUNDLE_ITEMS ON) + FIXUP_BUNDLE(${CMAKE_INSTALL_PREFIX}/AnimView.app \"\" \"\") + ") +else() install(TARGETS AnimView RUNTIME DESTINATION AnimView) install(FILES LICENSE.txt DESTINATION AnimView ) -ENDIF() +endif() diff -Nru corsix-th-0.30/AnimView/frmMain.cpp corsix-th-0.62/AnimView/frmMain.cpp --- corsix-th-0.30/AnimView/frmMain.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/frmMain.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -36,12 +36,10 @@ #include #include #include "backdrop.h" -#include "tinyxml.h" BEGIN_EVENT_TABLE(frmMain, wxFrame) EVT_BUTTON(ID_LOAD , frmMain::_onLoad) EVT_BUTTON(ID_BROWSE , frmMain::_onBrowse) - EVT_BUTTON(ID_EXPORT , frmMain::_onExport) EVT_BUTTON(ID_FIRST_ANIM, frmMain::_onFirstAnim) EVT_BUTTON(ID_PREV_ANIM , frmMain::_onPrevAnim) EVT_BUTTON(ID_NEXT_ANIM , frmMain::_onNextAnim) @@ -77,7 +75,6 @@ pThemeHospital->Add(m_txtTHPath = new wxTextCtrl(this, wxID_ANY, L"", def, wxTE_CENTRE), 1, wxALIGN_CENTER_VERTICAL | wxALL, 1); pThemeHospital->Add(new wxButton(this, ID_BROWSE, L"Browse..."), 0, wxALIGN_CENTER_VERTICAL | wxALL, 1); pThemeHospital->Add(new wxButton(this, ID_LOAD, L"Load"), 0, wxALIGN_CENTER_VERTICAL | wxALL, 1); - pThemeHospital->Add(m_btnExport = new wxButton(this, ID_EXPORT, L"Export"), 0, wxALIGN_CENTER_VERTICAL | wxALL, 1); pSidebarSizer->Add(pThemeHospital, 0, wxEXPAND | wxALL, 0); wxStaticBoxSizer *pPalette = new wxStaticBoxSizer(wxVERTICAL, this, L"Palette"); @@ -190,9 +187,9 @@ wxStaticBoxSizer *pMoodOverlay = new wxStaticBoxSizer(wxVERTICAL, this, L"Overlays"); pMoodOverlay->Add(new wxCheckBox(this, ID_DRAW_MOOD, L"Draw mood overlay"), 0, wxEXPAND | wxALL, 1); wxBoxSizer *pMoodRow = new wxBoxSizer(wxHORIZONTAL); - pMoodRow->Add(new wxStaticText(this, wxID_ANY, L"Marker position (click to move it):"), 0, wxEXPAND | wxRIGHT | wxALIGN_CENTER_VERTICAL, 2); - pMoodRow->Add(m_txtMoodPosition[0] = new wxTextCtrl(this, wxID_ANY, L"{0, 0}"), 1, wxEXPAND | wxRIGHT | wxALIGN_CENTER_VERTICAL, 1); - pMoodRow->Add(m_txtMoodPosition[1] = new wxTextCtrl(this, wxID_ANY, L"{0, 0, \"px\"}"), 1, wxEXPAND | wxALIGN_CENTER_VERTICAL); + pMoodRow->Add(new wxStaticText(this, wxID_ANY, L"Marker position (click to move it):"), 0, wxEXPAND | wxRIGHT, 2); + pMoodRow->Add(m_txtMoodPosition[0] = new wxTextCtrl(this, wxID_ANY, L"{0, 0}"), 1, wxEXPAND | wxRIGHT, 1); + pMoodRow->Add(m_txtMoodPosition[1] = new wxTextCtrl(this, wxID_ANY, L"{0, 0, \"px\"}"), 1, wxEXPAND); pMoodOverlay->Add(pMoodRow, 1, wxEXPAND | wxALL, 2); pMoodOverlay->Add(new wxCheckBox(this, ID_DRAW_COORDINATES, L"Draw tile coodinates"), 0, wxEXPAND | wxALL, 0); pSidebarSizer->Add(pMoodOverlay, 0, wxEXPAND | wxALL, 0); @@ -285,13 +282,6 @@ load(); } -void frmMain::_onExport(wxCommandEvent& WXUNUSED(evt)) -{ - m_tmrAnimate.Stop(); - ::wxInitAllImageHandlers(); - export_png(); -} - void frmMain::load() { wxBusyCursor oBusy; @@ -313,20 +303,7 @@ aPath += wxFileName::GetPathSeparator(); m_oAnims.setSpritePath(aPath); - bool bXmlLoaded = false; - wxString xmlFile = _getCaseSensitivePath(L"VSPR-0.xml", sPath); - TiXmlDocument xmlDocument((const char*)xmlFile.mb_str()); - if(wxFileName::FileExists(xmlFile) && xmlDocument.LoadFile()) - { - m_oAnims.loadXMLFile(&xmlDocument); - m_oAnims.loadPaletteFile(_getCaseSensitivePath(L"MPALETTE.DAT", sPath)); - m_oAnims.loadGhostFile(_getCaseSensitivePath(L"../QDATA/GHOST1.DAT", sPath), 1); - m_oAnims.loadGhostFile(_getCaseSensitivePath(L"../QDATA/GHOST2.DAT", sPath), 2); - m_oAnims.loadGhostFile(_getCaseSensitivePath(L"../QDATA/GHOST66.DAT", sPath), 3); - bXmlLoaded = true; - m_btnExport->Disable(); - } - else if(!m_oAnims.loadAnimationFile(_getCaseSensitivePath(L"VSTART-1.ANI", sPath)) + if(!m_oAnims.loadAnimationFile(_getCaseSensitivePath(L"VSTART-1.ANI", sPath)) ||!m_oAnims.loadFrameFile(_getCaseSensitivePath(L"VFRA-1.ANI", sPath)) ||!m_oAnims.loadListFile(_getCaseSensitivePath(L"VLIST-1.ANI", sPath)) ||!m_oAnims.loadElementFile(_getCaseSensitivePath(L"VELE-1.ANI", sPath)) @@ -339,7 +316,7 @@ { ::wxMessageBox(L"Cannot load one or more data files", L"Load Animations", wxOK | wxICON_ERROR, this); } - if(!bXmlLoaded) { m_oAnims.markDuplicates(); } + m_oAnims.markDuplicates(); m_txtAnimCount->SetValue(wxString::Format(L"%u", (int)m_oAnims.getAnimationCount())); @@ -377,284 +354,6 @@ _onAnimChange(0); } -void frmMain::export_png() -{ - wxBusyCursor oBusy; - wxString sPath = m_txtTHPath->GetValue(); - if(sPath.IsEmpty()) - return; - if(sPath.Mid(sPath.Len() - 1) != wxFileName::GetPathSeparator()) - { - sPath += wxFileName::GetPathSeparator(); - } - if(!wxFileName::DirExists(sPath)) - { - ::wxMessageBox(L"Theme Hospital path non-existant", L"Load Animations", wxOK | wxICON_ERROR, this); - return; - } - wxString sdPath = _getCaseSensitivePath(L"DATA", sPath); - sdPath += wxFileName::GetPathSeparator(); - - //wxDialog warnDialog(this, wxID_ANY, L"Export Warning"); - //warnDialog::CreateButtonSizer(wxOK|wxCANCEL); - bool bWriteFrames = false; - int response = ::wxMessageBox(L"If you click Yes, the export process will write animation frames \n \ -in separate folders and will run for about 20 minutes, and will create about 18,000 files on \n \ -your hard disk (~250MB). \n If you click No, it will write the XML and element files only. This will create \n \ -2,950 files (~80MB) and is everything you need to modify graphics. As long as the XML file is present in \n \ -the DATA folder, the Animation Viewer will use PNG sprites instead of Theme Hospital data files.", - L"Export Warning", wxYES_NO | wxCANCEL); - if( response == wxYES) { bWriteFrames = true; } - if( response != wxCANCEL) - { - //Start with animations, then move on to sprite sheets (map tiles) - if(!m_oAnims.loadAnimationFile(_getCaseSensitivePath(L"VSTART-1.ANI", sdPath)) - ||!m_oAnims.loadFrameFile(_getCaseSensitivePath(L"VFRA-1.ANI", sdPath)) - ||!m_oAnims.loadListFile(_getCaseSensitivePath(L"VLIST-1.ANI", sdPath)) - ||!m_oAnims.loadElementFile(_getCaseSensitivePath(L"VELE-1.ANI", sdPath)) - ||!m_oAnims.loadTableFile(_getCaseSensitivePath(L"VSPR-0.TAB", sdPath)) - ||!m_oAnims.loadSpriteFile(_getCaseSensitivePath(L"VSPR-0.DAT",sdPath)) - ||!m_oAnims.loadPaletteFile(_getCaseSensitivePath(L"MPALETTE.DAT", sdPath)) - ||!m_oAnims.loadGhostFile(_getCaseSensitivePath(L"../QDATA/GHOST1.DAT", sdPath), 1) - ||!m_oAnims.loadGhostFile(_getCaseSensitivePath(L"../QDATA/GHOST2.DAT", sdPath), 2) - ||!m_oAnims.loadGhostFile(_getCaseSensitivePath(L"../QDATA/GHOST66.DAT", sdPath), 3)) - { - ::wxMessageBox(L"Cannot load one or more data files", L"Load Animations", wxOK | wxICON_ERROR, this); - } - m_oAnims.markDuplicates(); - wxString aPath = _getCaseSensitivePath(L"VSPR-0", sdPath); - aPath += wxFileName::GetPathSeparator(); - if(!wxFileName::DirExists(aPath)) - { - wxFileName::Mkdir(aPath); - } - size_t iExportCount = m_oAnims.getAnimationCount(); - wxFile f(_getCaseSensitivePath(L"VSPR-0export.log", sdPath), wxFile::write_append); - wxFileOutputStream fos(f); - wxTextOutputStream outputLog(fos); - outputLog.WriteString(wxString::Format(L"File\tIndex\tFrame\tLayer\tID\tWidth\tHeight\tUnknown\n")); - m_oAnims.writeTableDataHeader(&outputLog); - wxFile fxml(_getCaseSensitivePath(L"VSPR-0.xml", sdPath), wxFile::write); - wxFileOutputStream fosxml(fxml); - wxTextOutputStream outputXml(fosxml); - outputXml.WriteString(wxString::Format(L"\n")); - outputXml.WriteString(wxString::Format(L"\n")); - - int iAnimationCount = 0; - int iFrameCountTotal = 1; - int iElementCount = 0; - int iSpriteCount = 0; - int iListIndex = 0; - for(size_t iAnimation = 0; iAnimation < iExportCount; ++iAnimation) - { - if(!m_oAnims.isAnimationDuplicate(iAnimation) && m_oAnims.getFrameField(iAnimation) >= iFrameCountTotal) - { - wxString aiPath = aPath + wxString::Format(L"a%04u", iAnimation); - if(!wxFileName::DirExists(aiPath)) - { - wxFileName::Mkdir(aiPath); - } - outputXml.WriteString(wxString::Format(L"\n", - iAnimation, m_oAnims.getFrameField(iAnimation), m_oAnims.getUnknownField(iAnimation))); - aiPath += wxFileName::GetPathSeparator(); - size_t iFrameCount = m_oAnims.getFrameCount(iAnimation); - for(size_t iFrame = 0; iFrame < iFrameCount; ++iFrame) - { - wxImage imgCanvas; - th_frame_t* pFrame = m_oAnims.getFrameStruct(iAnimation,iFrame); - outputXml.WriteString(wxString::Format(L"\t\n", - iFrameCountTotal, iListIndex, pFrame->width, pFrame->height, pFrame->flags, pFrame->next)); - - wxSize oSize; - m_oAnims.writeElementData(aPath, &outputLog, &outputXml, iAnimation, iFrame, &m_mskLayers, oSize, &iListIndex); - - if( bWriteFrames && oSize.x > 0 && oSize.y > 0 ) - { - if(!imgCanvas.IsOk()) - { - imgCanvas.Create(oSize.x, oSize.y, true); - if(!imgCanvas.HasAlpha()) - { - imgCanvas.SetAlpha(); - } - for(int iX = 0; iX < oSize.x; ++iX) - { - for(int iY = 0; iY < oSize.y; ++iY) - { - //set completely transparent - imgCanvas.SetAlpha(iX,iY,(unsigned char)0); - } - } - } - - m_oAnims.drawFrame(imgCanvas, iAnimation, iFrame, &m_mskLayers, oSize, 0, 0); - outputLog.WriteString(wxString::Format(L"%s\t%u\t%u\t%u\t%u\t%u\n", L"VSPR-0", iAnimation, iFrame, - oSize.x, oSize.y, m_oAnims.getUnknownField(iAnimation))); - } - - outputXml.WriteString(wxString::Format(L"\t\n")); - iFrameCountTotal++; - - if( bWriteFrames && imgCanvas.IsOk() ) - { - if(!imgCanvas.SaveFile(aiPath + wxString::Format(L"a%u_f%u.png", iAnimation, iFrame),wxBITMAP_TYPE_PNG)) - return; - imgCanvas.Destroy(); - } - } - outputXml.WriteString(wxString::Format(L"\n")); - iAnimationCount++; - } - } - //outputXml.WriteString(wxString::Format(L"\t\n", - // iAnimationCount, iFrameCount, iElementCount, iSpriteCount)); - outputXml.WriteString(wxString::Format(L"\n")); - - //Sprite sheet code for Data directory - exportSpritesPage(false, sdPath, L"MONEY01V"); - exportSpritesPage(false, sdPath, L"MPOINTER"); - exportSpritesPage(true, sdPath, L"PANEL02V"); - exportSpritesPage(true, sdPath, L"PANEL04V"); - exportSpritesPage(true, sdPath, L"PULLDV"); - exportSpritesPage(false, sdPath, L"VBLK-0"); - exportSpritesPage(true, sdPath, L"WATCH01V"); - //Skip DataM directory because it appears to be low-res versions of same - - //Sprite sheet code for QData directory - wxString sqPath = _getCaseSensitivePath(L"QDATA", sPath); - sqPath += wxFileName::GetPathSeparator(); - exportSpritesPage(true, sqPath, L"AWARD03V", L"", L"AWARD02V.PAL"); - exportSpritesPage(true, sqPath, L"BANK02V", L"", L"BANK01V.PAL"); - exportSpritesPage(true, sqPath, L"DRUGN02V", L"", L"DRUGN01V.PAL"); - exportSpritesPage(true, sqPath, L"FAME02V", L"", L"FAME01V.PAL"); - exportSpritesPage(true, sqPath, L"FAX02V", L"", L"FAX01V.PAL"); - exportSpritesPage(false, sqPath, L"FONT00V", sdPath); - exportSpritesPage(false, sqPath, L"FONT01V", sdPath); - exportSpritesPage(false, sqPath, L"FONT02V", sdPath); - exportSpritesPage(false, sqPath, L"FONT04V", sdPath); - exportSpritesPage(false, sqPath, L"FONT05V", sdPath); - exportSpritesPage(false, sqPath, L"FONT09V", sdPath); - exportSpritesPage(false, sqPath, L"FONT16V", sdPath); - exportSpritesPage(false, sqPath, L"FONT18V", sdPath); - exportSpritesPage(false, sqPath, L"FONT19V", sdPath); - exportSpritesPage(false, sqPath, L"FONT24V", sdPath); - exportSpritesPage(false, sqPath, L"FONT25V", sdPath); - exportSpritesPage(false, sqPath, L"FONT26V", sdPath); - exportSpritesPage(false, sqPath, L"FONT31V", sdPath); - exportSpritesPage(false, sqPath, L"FONT34V", sdPath); - exportSpritesPage(false, sqPath, L"FONT35V", sdPath); - exportSpritesPage(false, sqPath, L"FONT36V", sdPath); - exportSpritesPage(false, sqPath, L"FONT37V", sdPath); - exportSpritesPage(false, sqPath, L"FONT38V", sdPath); - exportSpritesPage(false, sqPath, L"FONT39V", sdPath); - exportSpritesPage(false, sqPath, L"FONT40V", sdPath); - exportSpritesPage(false, sqPath, L"FONT43V", sdPath); - exportSpritesPage(false, sqPath, L"FONT44V", sdPath); - exportSpritesPage(false, sqPath, L"FONT45V", sdPath); - exportSpritesPage(false, sqPath, L"FONT46V", sdPath); - exportSpritesPage(false, sqPath, L"FONT47V", sdPath); - exportSpritesPage(false, sqPath, L"FONT50V", sdPath); - exportSpritesPage(false, sqPath, L"FONT51V", sdPath); - exportSpritesPage(false, sqPath, L"FONT60V", sdPath); - exportSpritesPage(false, sqPath, L"FONT74V", sdPath); - exportSpritesPage(false, sqPath, L"FONT100V", sdPath); - exportSpritesPage(false, sqPath, L"FONT101V", sdPath); - exportSpritesPage(false, sqPath, L"FONT102V", sdPath); - exportSpritesPage(false, sqPath, L"FONT105V", sdPath); - exportSpritesPage(false, sqPath, L"FONT106V", sdPath); - exportSpritesPage(false, sqPath, L"FONT110V", sdPath); - exportSpritesPage(false, sqPath, L"FONT111V", sdPath); - exportSpritesPage(false, sqPath, L"FONT112V", sdPath); - exportSpritesPage(false, sqPath, L"FONT113V", sdPath); - exportSpritesPage(false, sqPath, L"FONT115V", sdPath); - exportSpritesPage(false, sqPath, L"FONT120V", sdPath); - exportSpritesPage(false, sqPath, L"FONT121V", sdPath); - exportSpritesPage(false, sqPath, L"FONT122V", sdPath); - exportSpritesPage(false, sqPath, L"FONT124V", sdPath); - exportSpritesPage(false, sqPath, L"FONT250V", sdPath); - exportSpritesPage(false, sqPath, L"FONT502V", sdPath); - exportSpritesPage(true, sqPath, L"GRAPH02V", L"", L"GRAPH01V.PAL"); - exportSpritesPage(true, sqPath, L"LETTR02V", L"", L"REP01V.PAL"); - exportSpritesPage(true, sqPath, L"LOAD02V", L"", L"LOAD01V.PAL"); - exportSpritesPage(true, sqPath, L"MAIN02M", L"", L"MAIN01M.PAL"); - exportSpritesPage(true, sqPath, L"POL02V", L"", L"POL01V.PAL"); - exportSpritesPage(true, sqPath, L"PREF02V", L"", L"PREF01V.PAL"); - exportSpritesPage(true, sqPath, L"REP02V", L"", L"REP01V.PAL"); - //exportSpritesPage(true, sqPath, L"REQ00V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ01V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ02V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ03V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ04V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ05V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ06V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ09V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ10V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ11V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ12V", sdPath); - //exportSpritesPage(true, sqPath, L"REQ13V", sdPath); - exportSpritesPage(true, sqPath, L"RES02V", L"", L"RES01V.PAL"); - exportSpritesPage(true, sqPath, L"REP02V", L"", L"REP01V.PAL"); - exportSpritesPage(true, sqPath, L"SPOINTER", sdPath); - exportSpritesPage(true, sqPath, L"STAFF02V", L"", L"STAFF01V.PAL"); - exportSpritesPage(true, sqPath, L"STAT02V", L"", L"STAT01V.PAL"); - exportSpritesPage(true, sqPath, L"TOWN02V", L"", L"TOWN01V.PAL"); - exportSpritesPage(true, sqPath, L"VER00V", L"", L"REP01V.PAL"); - } -} - -void frmMain::exportSpritesPage(bool bComplex, wxString sPath, wxString sFilename, wxString spPath, wxString sPalette) -{ - if(spPath.length() == 0) - { - spPath = sPath; - } - if(!m_oAnims.loadTableFile(_getCaseSensitivePath(wxString::Format(L"%s.TAB",sFilename.wx_str()), sPath)) - ||!m_oAnims.loadSpriteFile(_getCaseSensitivePath(wxString::Format(L"%s.DAT",sFilename.wx_str()), sPath)) - ||!m_oAnims.loadPaletteFile(_getCaseSensitivePath(sPalette, spPath))) - { - return; - } - - wxFile f(_getCaseSensitivePath(sFilename + L"export.log", sPath), wxFile::write); - wxFileOutputStream fos(f); - wxTextOutputStream outputLog(fos); - outputLog.WriteString(wxString::Format(L"File\tIndex\tPalette\tComplex\tWidth\tHeight\n")); - - wxString aPath = _getCaseSensitivePath(sFilename, sPath); - aPath += wxFileName::GetPathSeparator(); - if(!wxFileName::DirExists(aPath)) - { - wxFileName::Mkdir(aPath); - for(size_t i = 0; i < m_oAnims.getSpriteCount(); ++i) - { - Bitmap* pSpriteBitmap = m_oAnims.getSpriteBitmap(i, bComplex); - if(pSpriteBitmap->getWidth() * pSpriteBitmap->getHeight() > 0) - { - wxImage imgSprite(pSpriteBitmap->getWidth(), pSpriteBitmap->getHeight(), false); - pSpriteBitmap->blit(imgSprite, 0, 0, NULL, m_oAnims.getPalette(), 0x8000); - if(!imgSprite.HasAlpha()) - { - imgSprite.SetAlpha(); - } - for(int iX = 0; iX < pSpriteBitmap->getWidth(); ++iX) - { - for(int iY = 0; iY < pSpriteBitmap->getHeight(); ++iY) - { - if(imgSprite.GetRed(iX,iY) == 255 && imgSprite.GetBlue(iX,iY) == 255) { - imgSprite.SetAlpha(iX,iY,(unsigned char)0); - } else { - imgSprite.SetAlpha(iX,iY,(unsigned char)255); - } - } - } - if(!imgSprite.SaveFile(_getCaseSensitivePath(wxString::Format(L"s%u.png", i), aPath),wxBITMAP_TYPE_PNG)) - return; - outputLog.WriteString(wxString::Format(L"%s\t%u\t%s\t%u\t%u\n", sFilename.wx_str(), i, sPalette.wx_str(), pSpriteBitmap->getWidth(),pSpriteBitmap->getHeight())); - } - } - } -} - void frmMain::_onToggleMask(wxCommandEvent& evt) { int iID = evt.GetId() - ID_LAYER_CHECKS; diff -Nru corsix-th-0.30/AnimView/frmSprites.cpp corsix-th-0.62/AnimView/frmSprites.cpp --- corsix-th-0.30/AnimView/frmSprites.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/frmSprites.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -26,6 +26,7 @@ #include #include #include +#include #include BEGIN_EVENT_TABLE(frmSprites, wxFrame) @@ -63,7 +64,7 @@ pMainSizer->Add(pFiles, 0, wxEXPAND | wxALL, 2); wxStaticBoxSizer *pSprites = new wxStaticBoxSizer(wxVERTICAL, this, L"Sprites"); - pSprites->Add(m_panFrame = new wxPanel(this, wxID_ANY), 1, wxEXPAND); + pSprites->Add(m_panFrame = new MyVScrolled(this), 1, wxEXPAND); pMainSizer->Add(pSprites, 1, wxEXPAND | wxALL, 2); m_panFrame->Connect(wxEVT_PAINT, (wxObjectEventFunction)&frmSprites::_onPanelPaint, NULL, this); @@ -153,44 +154,56 @@ int iAvailableWidth, iAvailableHeight; m_panFrame->GetClientSize(&iAvailableWidth, &iAvailableHeight); - int iX = 0, iY = 0, iTallest = 0; + int iX = 0; + int iTallest = 0; + int iTotal = 0; + int iY = -m_panFrame->GetVisibleRowsBegin(); for(std::vector<_sprite_t>::iterator itr = m_vSprites.begin(), itrEnd = m_vSprites.end(); itr != itrEnd; ++itr) { wxSize szLabel = dc.GetTextExtent(itr->caption); int iWidth = wxMax(szLabel.GetWidth(), itr->bitmap.IsOk() ? itr->bitmap.GetWidth() : 0); + int iHeight = (itr->bitmap.IsOk() ? itr->bitmap.GetHeight() : 0) + szLabel.GetHeight() + 2; if(iWidth + iX > iAvailableWidth) { iY += iTallest; + iTotal += iTallest; iX = iTallest = 0; - if(iY > iAvailableHeight) - break; } - dc.DrawText(itr->caption, iX, iY); - if(itr->bitmap.IsOk()) - dc.DrawBitmap(itr->bitmap, iX, iY + szLabel.GetHeight() + 1); + if (iY + iHeight >= 0 && iY < iAvailableHeight) { + dc.DrawText(itr->caption, iX, iY); + if(itr->bitmap.IsOk()) + dc.DrawBitmap(itr->bitmap, iX, iY + szLabel.GetHeight() + 1); + } - int iHeight = (itr->bitmap.IsOk() ? itr->bitmap.GetHeight() : 0) + szLabel.GetHeight() + 2; iTallest = wxMax(iTallest, iHeight); iX += iWidth + 2; } + + iTotal += iTallest; // Add last row too. + + // Update the row count if it doesn't match. + if (iTotal != m_panFrame->iMyCount) { + m_panFrame->iMyCount = iTotal; + m_panFrame->SetRowCount(iTotal); + } } void frmSprites::_onBrowseTable(wxCommandEvent& WXUNUSED(evt)) { m_txtTable->SetValue(::wxFileSelector(L"Select location of Font00V.tab (DATA)", - m_txtTable->GetValue(),L"Font00V.tab",L"tab",L"Tab files (*.tab)|*.tab" + m_txtTable->GetValue(),L"Font00V.tab",L"tab",L"Tab files (*.tab)|*.[tT][aA][bB]" ,0, this)); } void frmSprites::_onBrowseData(wxCommandEvent& WXUNUSED(evt)) { m_txtData->SetValue(::wxFileSelector(L"Choose Theme Hospital data file", - m_txtData->GetValue(),L"",L"dat",L"Dat files (*.dat)|*.dat", 0, this)); + m_txtData->GetValue(),L"",L"dat",L"Dat files (*.dat)|*.[dD][aA][tT]", 0, this)); } void frmSprites::_onBrowsePalette(wxCommandEvent& WXUNUSED(evt)) { m_txtPalette->SetValue(::wxFileSelector(L"Select location of MPalette.dat (QDATA)", - m_txtPalette->GetValue(),L"MPalette.dat",L"dat",L"Dat or Pal files (*.dat, *.pal)|*.dat;*.pal", 0, this)); + m_txtPalette->GetValue(),L"MPalette.dat",L"dat",L"Dat or Pal files (*.dat, *.pal)|*.[dD][aA][tT];*.[pP][aA][lL]", 0, this)); } diff -Nru corsix-th-0.30/AnimView/frmSprites.h corsix-th-0.62/AnimView/frmSprites.h --- corsix-th-0.30/AnimView/frmSprites.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/frmSprites.h 2018-07-21 11:13:17.000000000 +0000 @@ -29,9 +29,24 @@ #include #include #include +#include #include "th.h" #include +static const int ROW_COUNT = 1000; + +// Derived class to add scrollbars to the window. +class MyVScrolled : public wxVScrolledWindow { +public: + MyVScrolled(wxWindow *parent) : wxVScrolledWindow(parent, wxID_ANY) { iMyCount = ROW_COUNT; } + + wxCoord OnGetRowHeight(size_t row) const { return 1; } + + wxCoord EstimateTotalHeight() const { return iMyCount; } + + int iMyCount; +}; + class frmSprites : public wxFrame { public: @@ -70,6 +85,6 @@ wxTextCtrl* m_txtTable; wxTextCtrl* m_txtData; wxTextCtrl* m_txtPalette; - wxPanel* m_panFrame; + MyVScrolled* m_panFrame; DECLARE_EVENT_TABLE(); }; diff -Nru corsix-th-0.30/AnimView/Makefile corsix-th-0.62/AnimView/Makefile --- corsix-th-0.30/AnimView/Makefile 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# Makefile for building AnimViewer -# This is quite a simple makefile and could probably do with some love from -# someone who understands the *nix buildchain better than I do. - -CC= gcc -CPP= g++ -RM= rm -f -CFLAGS= `wx-config --cflags` -LIBS= `wx-config --libs` - -ALL_T= AnimViewer -ALL_O= app.o frmMain.o frmSprites.o rnc.o th.o - -default: all - -all: $(ALL_T) - -clean: - $(RM) $(ALL_O) $(ALL_T) - -AnimViewer: $(ALL_O) - $(CPP) -o $@ $(ALL_O) $(LIBS) - -app.o: - $(CPP) -c app.cpp $(CFLAGS) - -frmMain.o: - $(CPP) -c frmMain.cpp $(CFLAGS) - -frmSprites.o: - $(CPP) -c frmSprites.cpp $(CFLAGS) - -rnc.o: - $(CPP) -c rnc.cpp $(CFLAGS) - -th.o: - $(CPP) -c th.cpp $(CFLAGS) - diff -Nru corsix-th-0.30/AnimView/rnc.cpp corsix-th-0.62/AnimView/rnc.cpp --- corsix-th-0.30/AnimView/rnc.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/rnc.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,409 +0,0 @@ -/* - RNC decompression library. Copyright and ownership status unknown. - - Original code was from http://www.yoda.arachsys.com/dk/utils.html, but that - site nor the code itself states any ownership or copyright claims. - Modifications made to the original code include: - * Const correctness - * Prebuilt CRC table - * Indentation and code style -*/ - -#include "th.h" - -#define RNC_OK 0 -#define RNC_FILE_IS_NOT_RNC -1 -#define RNC_HUF_DECODE_ERROR -2 -#define RNC_FILE_SIZE_MISMATCH -3 -#define RNC_PACKED_CRC_ERROR -4 -#define RNC_UNPACKED_CRC_ERROR -5 -#define RNC_SIGNATURE 0x524E4301 /* "RNC\001" */ - -static const unsigned short rnc_crc_table[256] = { - 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, - 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, - 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, - 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, - 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, - 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, - 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, - 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, - 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, - 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, - 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, - 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, - 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, - 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, - 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, - 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, - 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, - 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, - 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, - 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, - 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, - 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, - 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, - 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, - 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, - 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, - 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, - 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, - 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, - 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, - 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, - 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, -}; - -struct bit_stream -{ - unsigned long bitbuf; /* holds between 16 and 32 bits */ - int bitcount; /* how many bits does bitbuf hold? */ -}; - -struct huf_table -{ - int num; /* number of nodes in the tree */ - struct - { - unsigned long code; - int codelen; - int value; - } table[32]; -}; - -/* - * Calculate a CRC, the RNC way. - */ -static long rnc_crc(const unsigned char* data, long len) -{ - unsigned short val = 0; - - while(len--) - { - val ^= *data++; - val = (val >> 8) ^ rnc_crc_table[val & 0xFF]; - } - - return val; -} - - -/* - * Return the big-endian longword at p. - */ -static unsigned long blong (const unsigned char *p) -{ - unsigned long n; - n = p[0]; - n = (n << 8) + p[1]; - n = (n << 8) + p[2]; - n = (n << 8) + p[3]; - return n; -} - -/* - * Return the little-endian longword at p. - */ -static unsigned long llong (const unsigned char *p) -{ - unsigned long n; - n = p[3]; - n = (n << 8) + p[2]; - n = (n << 8) + p[1]; - n = (n << 8) + p[0]; - return n; -} - -/* - * Return the big-endian word at p. - */ -static unsigned long bword (const unsigned char *p) -{ - unsigned long n; - n = p[0]; - n = (n << 8) + p[1]; - return n; -} - -/* - * Return the little-endian word at p. - */ -static unsigned long lword (const unsigned char *p) -{ - unsigned long n; - n = p[1]; - n = (n << 8) + p[0]; - return n; -} - -/* - * Mirror the bottom n bits of x. - */ -static unsigned long mirror (unsigned long x, int n) -{ - unsigned long top = 1 << (n-1), bottom = 1; - while (top > bottom) - { - unsigned long mask = top | bottom; - unsigned long masked = x & mask; - if (masked != 0 && masked != mask) - { - x ^= mask; - } - top >>= 1; - bottom <<= 1; - } - return x; -} - - -/* - * Initialises a bit stream with the first two bytes of the packed - * data. - */ -static void bitread_init (bit_stream *bs, const unsigned char **p) -{ - bs->bitbuf = lword (*p); - bs->bitcount = 16; -} - -/* - * Fixes up a bit stream after literals have been read out of the - * data stream. - */ -static void bitread_fix (bit_stream *bs, const unsigned char **p) -{ - bs->bitcount -= 16; - bs->bitbuf &= (1<bitcount)-1; /* remove the top 16 bits */ - bs->bitbuf |= (lword(*p)<bitcount);/* replace with what's at *p */ - bs->bitcount += 16; -} - -/* - * Returns some bits. - */ -static unsigned long bit_peek (bit_stream *bs, const unsigned long mask) -{ - return bs->bitbuf & mask; -} - -/* - * Advances the bit stream. - */ -static void bit_advance (bit_stream *bs, int n, const unsigned char **p) -{ - bs->bitbuf >>= n; - bs->bitcount -= n; - if (bs->bitcount < 16) - { - (*p) += 2; - bs->bitbuf |= (lword(*p)<bitcount); - bs->bitcount += 16; - } -} - -/* - * Reads some bits in one go (ie the above two routines combined). - */ -static unsigned long bit_read (bit_stream *bs, unsigned long mask, int n, const unsigned char **p) -{ - unsigned long result = bit_peek(bs, mask); - bit_advance(bs, n, p); - return result; -} - -/* - * Read a Huffman table out of the bit stream and data stream given. - */ -static void read_huftable(huf_table *h, bit_stream *bs, const unsigned char **p) -{ - int i, j, k, num; - int leaflen[32]; - int leafmax; - unsigned long codeb; /* big-endian form of code */ - - num = bit_read(bs, 0x1F, 5, p); - - if(num == 0) - { - return; - } - - leafmax = 1; - for(i = 0; i < num; i++) - { - leaflen[i] = bit_read(bs, 0x0F, 4, p); - if (leafmax < leaflen[i]) - { - leafmax = leaflen[i]; - } - } - - codeb = 0L; - k = 0; - for(i = 1; i <= leafmax; i++) - { - for(j = 0; j < num; j++) - { - if(leaflen[j] == i) - { - h->table[k].code = mirror(codeb, i); - h->table[k].codelen = i; - h->table[k].value = j; - codeb++; - k++; - } - } - codeb <<= 1; - } - h->num = k; -} - -/* - * Read a value out of the bit stream using the given Huffman table. - */ -static unsigned long huf_read(huf_table *h, bit_stream *bs, const unsigned char **p) -{ - int i; - unsigned long val; - - for (i = 0; i < h->num; i++) - { - unsigned long mask = (1 << h->table[i].codelen) - 1; - if(bit_peek(bs, mask) == h->table[i].code) - { - break; - } - } - if(i == h->num) - { - return -1; - } - bit_advance(bs, h->table[i].codelen, p); - - val = h->table[i].value; - - if (val >= 2) - { - val = 1 << (val-1); - val |= bit_read(bs, val-1, h->table[i].value - 1, p); - } - return val; -} - -static int rnc_unpack(const unsigned char* input, unsigned char* output) -{ - const unsigned char *inputend; - unsigned char *outputend; - bit_stream bs; - huf_table raw, dist, len; - unsigned long ch_count; - unsigned long ret_len; - unsigned out_crc; - if(blong(input) != RNC_SIGNATURE) - { - return RNC_FILE_IS_NOT_RNC; - } - ret_len = blong(input + 4); - outputend = output + ret_len; - inputend = input + 18 + blong(input + 8); - - input += 18; /* skip header */ - - /* - * Check the packed-data CRC. Also save the unpacked-data CRC - * for later. - */ - if(rnc_crc(input, inputend-input) != bword(input - 4)) - { - return RNC_PACKED_CRC_ERROR; - } - out_crc = bword(input - 6); - - bitread_init(&bs, &input); - bit_advance(&bs, 2, &input); /* discard first two bits */ - - /* - * Process chunks. - */ - while (output < outputend) - { - read_huftable(&raw, &bs, &input); - read_huftable(&dist, &bs, &input); - read_huftable(&len, &bs, &input); - ch_count = bit_read(&bs, 0xFFFF, 16, &input); - - while(true) - { - long length, posn; - - length = huf_read(&raw, &bs, &input); - if(length == -1) - { - return RNC_HUF_DECODE_ERROR; - } - if(length) - { - while(length--) - *output++ = *input++; - bitread_fix(&bs, &input); - } - if(--ch_count <= 0) - { - break; - } - - posn = huf_read(&dist, &bs, &input); - if(posn == -1) - { - return RNC_HUF_DECODE_ERROR; - } - length = huf_read(&len, &bs, &input); - if(length == -1) - { - return RNC_HUF_DECODE_ERROR; - } - posn += 1; - length += 2; - while(length--) - { - *output = output[-posn]; - output++; - } - } - } - - if(outputend != output) - { - return RNC_FILE_SIZE_MISMATCH; - } - - /* - * Check the unpacked-data CRC. - */ - if(rnc_crc(outputend - ret_len, ret_len) != out_crc) - { - return RNC_UNPACKED_CRC_ERROR; - } - - return RNC_OK; -} - -unsigned char* THAnimations::Decompress(unsigned char* pData, size_t& iLength) -{ - unsigned long outlen = blong(pData + 4); - unsigned char* outbuf = new unsigned char[outlen]; - if(rnc_unpack(pData, outbuf) == RNC_OK) - { - delete[] pData; - iLength = outlen; - return outbuf; - } - else - { - delete[] pData; - delete[] outbuf; - iLength = 0; - return NULL; - } -} diff -Nru corsix-th-0.30/AnimView/th.cpp corsix-th-0.62/AnimView/th.cpp --- corsix-th-0.30/AnimView/th.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/th.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -21,10 +21,15 @@ */ #include "th.h" +#include "../common/rnc.h" #include #include #include -#include +#include +#include +#include +#include +#include static const unsigned char palette_upscale_map[0x40] = { 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, @@ -227,50 +232,33 @@ THAnimations::THAnimations() { - m_pAnims = NULL; - m_pFrames = NULL; - m_pElementList = NULL; - m_pElements = NULL; - m_pSprites = NULL; - m_pSpriteBitmaps = NULL; - m_pChunks = NULL; - m_pColours = NULL; - m_pGhostMaps = new unsigned char[256 * 256 * 4]; + anims = std::vector(); + frames = std::vector(); + elementList = std::vector(); + elements = std::vector(); + sprites = std::vector(); + spriteBitmaps = std::vector(); + chunks = std::vector(); + colours = std::vector(); + ghostMaps = std::array(); for(int iMap = 0; iMap < 256 * 4; ++iMap) { for(int iCol = 0; iCol < 256; ++iCol) { - m_pGhostMaps[iMap * 256 + iCol] = iCol; + ghostMaps[iMap * 256 + iCol] = iCol; } } m_iGhostMapOffset = 0; - m_iAnimCount = 0; - m_iFrameCount = 0; - m_iElementListCount = 0; - m_iElementCount = 0; - m_iSpriteCount = 0; - m_iChunkCount = 0; - m_iColourCount = 0; - m_bXmlLoaded = false; } THAnimations::~THAnimations() { - delete[] m_pAnims; - delete[] m_pFrames; - delete[] m_pElementList; - delete[] m_pElements; - delete[] m_pSprites; - delete[] m_pSpriteBitmaps; - delete[] m_pChunks; - delete[] m_pColours; - delete[] m_pGhostMaps; } bool THAnimations::isAnimationDuplicate(size_t iAnimation) { - if(iAnimation < m_iAnimCount) - return m_pAnims[iAnimation].unknown == 1; + if(iAnimation < anims.size()) + return anims.at(iAnimation).unknown == 1; else return true; } @@ -279,20 +267,22 @@ { size_t iNonDuplicateCount = 0; - std::map mapSeen; - for(size_t i = 0; i < m_iAnimCount; ++i) + std::set seen; + for(th_anim_t& anim : anims) { - uint16_t iFrame = m_pAnims[i].frame; + uint16_t iFrame = anim.frame; uint16_t iFirstFrame = iFrame; do { - if(mapSeen[iFrame]) - m_pAnims[i].unknown = 1; - else - mapSeen[iFrame] = true; - iFrame = m_pFrames[iFrame].next; + if(seen.find(iFrame) != seen.end()) { + anim.unknown = 1; + } else { + seen.insert(iFrame); + } + iFrame = frames.at(iFrame).next; } while(iFrame != iFirstFrame); - if(m_pAnims[i].unknown == 0) + + if(anim.unknown == 0) { ++iNonDuplicateCount; } @@ -303,24 +293,13 @@ bool THAnimations::loadFrameFile(wxString sFilename) { - if(!_loadArray(m_pFrames, m_iFrameCount, sFilename)) + if(!loadVector(frames, sFilename)) return false; /* 256 is a common flag - could be x-flip. The lower byte can also take non-zero values - could be ghost palette - indicies. - */ - /* - FILE *f = fopen("E:\\list.txt", "wt"); - for(size_t i = 0; i < m_iFrameCount; ++i) - { - if(m_pFrames[i].flags != 0) - { - fprintf(f, "%i, %i,\n", (int)i, (int)m_pFrames[i].flags); - } - } - fclose(f); + indices. */ return true; @@ -328,245 +307,22 @@ bool THAnimations::loadTableFile(wxString sFilename) { - delete[] m_pSpriteBitmaps; - m_pSpriteBitmaps = 0; - if(!_loadArray(m_pSprites, m_iSpriteCount, sFilename)) + spriteBitmaps.clear(); + if(!loadVector(sprites, sFilename)) return false; - m_pSpriteBitmaps = new Bitmap[m_iSpriteCount]; + spriteBitmaps.resize(sprites.size()); return true; } -bool THAnimations::loadXMLFile(TiXmlDocument* xmlDocument) -{ - TiXmlHandle hDoc(xmlDocument); - TiXmlElement* pElem; - TiXmlHandle hRoot(0); - - //navigate to - pElem=hDoc.FirstChildElement().Element(); - hRoot=TiXmlHandle(pElem); - - //count elements - int iAnimation = 0; - pElem=pElem->LastChild()->ToElement(); - pElem->QueryIntAttribute("id",&iAnimation); - m_pAnims = new th_anim_t[iAnimation]; - - for( int i=0; i <= iAnimation; i++ ) - { - m_pAnims[i].unknown = 1; - m_pAnims[i].frame = 1; - } - //temporary hacks to avoid complicated allocation, the only drawback is that reducing - //element count won't automatically reduce memory consumption, and increasing element - //count might require a recompile. - m_iAnimCount = iAnimation+1; - m_iFrameCount = 11642; - m_iElementListCount = 185864; - m_iElementCount = 26557; - m_iSpriteCount = 4399; - m_pFrames = new th_frame_t[m_iFrameCount]; - m_pElementList = new uint16_t[m_iElementListCount]; - m_pElements = new th_element_t[m_iElementCount]; - uint16_t* tmp_pElementMap = new uint16_t[m_iElementListCount]; - m_pSprites = new th_sprite_t[m_iSpriteCount]; - m_pSpriteImages = new wxImage[m_iSpriteCount]; - m_pSpriteScaleFactors = new uint8_t[m_iSpriteCount]; - //navigate to first element - pElem=hRoot.FirstChild( "an" ).Element(); - //pElem->QueryIntAttribute("id",&iAnimation); - iAnimation = 0; - int iFrame = 0; - int tmpInteger = 0; - int iNewListIndex = 0; - int iOldElementCount = 0; - int iNewElementCount = 0; - int iOldElement = 0; - m_pFrames[0].list_index = 0; - m_pFrames[0].width = 0; - m_pFrames[0].height = 0; - m_pFrames[0].flags = 0; - m_pFrames[0].next = 0; - for( pElem; pElem; pElem=pElem->NextSiblingElement()) - { - pElem->QueryIntAttribute("id",&iAnimation); - pElem->QueryIntAttribute("fr",&iFrame); - m_pAnims[iAnimation].frame = iFrame; - m_pAnims[iAnimation].unknown = 0; - TiXmlElement* pFrameElement = pElem->FirstChildElement("fr"); - for( pFrameElement; pFrameElement; pFrameElement=pFrameElement->NextSiblingElement()) - { - pFrameElement->QueryIntAttribute("id",&iFrame); - //ignore original frame indexes, they are only for looking up "first elements" - //pFrameElement->QueryIntAttribute("li",&iListIndex); - //m_pElementList[iListIndex] = iFrame; - if(iFrame < m_iFrameCount) { - m_pFrames[iFrame].list_index = iNewListIndex; - pFrameElement->QueryIntAttribute("w",&tmpInteger); - m_pFrames[iFrame].width=tmpInteger; - pFrameElement->QueryIntAttribute("h",&tmpInteger); - m_pFrames[iFrame].height=tmpInteger; - pFrameElement->QueryIntAttribute("fl",&tmpInteger); - m_pFrames[iFrame].flags=tmpInteger; - pFrameElement->QueryIntAttribute("nx",&tmpInteger); - m_pFrames[iFrame].next=tmpInteger; - TiXmlElement* pElementElement = pFrameElement->FirstChildElement("el"); - for( pElementElement; pElementElement; pElementElement=pElementElement->NextSiblingElement()) - { - int iNewElement = 0; - pElementElement->QueryIntAttribute("id",&iOldElement); - //complex mapping of original element ids to new sequential id system - if(iOldElement < iOldElementCount) { - //this is a re-used element id from the old numbering system, so look up the new element id - //in the new numbering system. - iNewElement = tmp_pElementMap[iOldElement]; - } else { - if( iNewElementCount < m_iElementCount ) - { - tmp_pElementMap[iOldElement]=iNewElementCount; - iOldElementCount = iOldElement + 1; - iNewElement = iNewElementCount; - iNewElementCount++; - //new fill fields in the new element - pElementElement->QueryIntAttribute("fl",&tmpInteger); - m_pElements[iNewElement].flags = tmpInteger; - pElementElement->QueryIntAttribute("ox",&tmpInteger); - m_pElements[iNewElement].offx = tmpInteger; - pElementElement->QueryIntAttribute("oy",&tmpInteger); - m_pElements[iNewElement].offy = tmpInteger; - //pElementElement->QueryIntAttribute("tb",&tmpInteger); - //m_pElements[iNewElement].table_position = tmpInteger; - pElementElement->QueryIntAttribute("ly",&tmpInteger); - m_pElements[iNewElement].layerid = tmpInteger; - int iSprite = 0; - pElementElement->QueryIntAttribute("sp",&iSprite); - if(iSprite < m_iSpriteCount) - { - //set table position to Sprite ID * 6 (sizeof th_sprite_t) - m_pElements[iNewElement].table_position = iSprite*6; - //zero means "attribute found", 1 means "no such attribute" - if(pElementElement->QueryIntAttribute("sf",&tmpInteger) == 0) - { - m_pSpriteScaleFactors[iSprite] = tmpInteger; - pElementElement->QueryIntAttribute("w",&tmpInteger); - m_pSprites[iSprite].width = tmpInteger/m_pSpriteScaleFactors[iSprite]; - pElementElement->QueryIntAttribute("h",&tmpInteger); - m_pSprites[iSprite].height = tmpInteger/m_pSpriteScaleFactors[iSprite]; - } else { - m_pSpriteScaleFactors[iSprite] = 1; - pElementElement->QueryIntAttribute("w",&tmpInteger); - m_pSprites[iSprite].width = tmpInteger; - pElementElement->QueryIntAttribute("h",&tmpInteger); - m_pSprites[iSprite].height = tmpInteger; - } - pElementElement->QueryIntAttribute("of",&tmpInteger); - m_pSprites[iSprite].offset = tmpInteger; - } - } - } - m_pElementList[iNewListIndex] = iNewElement; - iNewListIndex++; - if(iNewListIndex >= m_iElementListCount) - break; - } - m_pElementList[iNewListIndex] = 65535; - iNewListIndex++; - if(iNewListIndex >= m_iElementListCount) - break; - } - } - } - - m_bXmlLoaded = true; - return m_bXmlLoaded; -} - -void THAnimations::writeElementData(wxString aPath, wxTextOutputStream *outputLog, wxTextOutputStream *outputXml, - size_t iAnimation, size_t iFrame, const THLayerMask* pMask, wxSize& size, int *iListIndex) -{ - if(iAnimation >= m_iAnimCount) - return; - uint16_t iFrameIndex = m_pAnims[iAnimation].frame; - while(iFrame--) - { - iFrameIndex = m_pFrames[iFrameIndex].next; - } - - th_frame_t* pFrame = m_pFrames + iFrameIndex; - th_element_t* pElement; - uint32_t iOldListIndex = pFrame->list_index; - int iFarX = 0; - int iFarY = 0; - int iNewListIndex = *iListIndex; - - while((pElement = _getElement(iOldListIndex))) - { - if(pElement->flags >> 4 != 1) - { - uint16_t iElementIndex = m_pElementList[iOldListIndex]; - outputXml->WriteString(wxString::Format(L"\t\ttable_position, pElement->flags, pElement->offx, pElement->offy, pElement->layerid )); - uint16_t iSpriteIndex = pElement->table_position / sizeof(th_sprite_t); - wxString spriteFile = aPath + wxString::Format(L"a%04ue.png", iSpriteIndex); - - th_sprite_t* pSprite = m_pSprites + iSpriteIndex; - int iRight = pElement->offx + pSprite->width; - int iBottom = pElement->offy + pSprite->height; - if(iRight > iFarX) - iFarX = iRight; - if(iBottom > iFarY) - iFarY = iBottom; - //if(pMask != NULL && !pMask->isSet(pElement->flags >> 4, pElement->layerid)) - // continue; - outputXml->WriteString(wxString::Format(L"sp='%u' of='%u' w='%u' h='%u'/>\n", - iSpriteIndex, pSprite->offset, pSprite->width, pSprite->height )); - if(!wxFileName::FileExists(spriteFile) && pSprite->width > 0 && pSprite->height > 0) - { - wxImage imgSprite(pSprite->width, pSprite->height, true); - if(!imgSprite.HasAlpha()) - { - imgSprite.SetAlpha(); - } - for(int iX = 0; iX < pSprite->width; ++iX) - { - for(int iY = 0; iY < pSprite->height; ++iY) - { - imgSprite.SetAlpha(iX,iY,(unsigned char)0); - } - } - //ignore element "mirroring" flags, they will cause the sprite to be written mirrored and then that sprite - //will mirrored again when loaded later. - getSpriteBitmap(iSpriteIndex)->blit(imgSprite, 0, 0, m_pGhostMaps + m_iGhostMapOffset, m_pColours, 0 & 0xF); - if(!imgSprite.SaveFile(spriteFile,wxBITMAP_TYPE_PNG)) - return; - outputLog->WriteString(wxString::Format(L"E%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\n", iSpriteIndex, - pElement->table_position, pElement->flags, pElement->layerid, pElement->offx, pElement->offy, - iNewListIndex, sizeof(th_sprite_t), pSprite->width, pSprite->height, pSprite->offset)); - } - iNewListIndex++; - } - iOldListIndex++; - } - size.x = iFarX; - size.y = iFarY; - *iListIndex = iNewListIndex; - -} - -void THAnimations::writeTableDataHeader(wxTextOutputStream *outputLog) -{ - outputLog->WriteString(wxString::Format(L"Element\tTablePos\tFlags\tLayerID\tXoff\tYoff\tListIndex\tSpriteSize\tWidth\tHeight\tOffset\n")); -} - bool THAnimations::loadPaletteFile(wxString sFilename) { - if(!_loadArray(m_pColours, m_iColourCount, sFilename)) + if (!loadVector(colours, sFilename)) return false; - for(size_t i = 0; i < m_iColourCount; ++i) + for (th_colour_t& colour : colours) { - m_pColours[i].r = palette_upscale_map[m_pColours[i].r & 0x3F]; - m_pColours[i].g = palette_upscale_map[m_pColours[i].g & 0x3F]; - m_pColours[i].b = palette_upscale_map[m_pColours[i].b & 0x3F]; + colour.r = palette_upscale_map[colour.r & 0x3F]; + colour.g = palette_upscale_map[colour.g & 0x3F]; + colour.b = palette_upscale_map[colour.b & 0x3F]; } return true; } @@ -576,20 +332,16 @@ if(iIndex < 0 || iIndex >= 4) return false; - unsigned char *pData = NULL; - size_t iDataLen; + std::vector data; - if(!_loadArray(pData, iDataLen, sFilename)) + if (!loadVector(data, sFilename)) return false; - if(iDataLen != 256 * 256) - { - delete[] pData; + if (data.size() != 256 * 256) { return false; } - memcpy(m_pGhostMaps + iIndex * 256 * 256, pData, 256 * 256); - delete[] pData; + std::copy(data.begin(), data.end(), ghostMaps.begin() + iIndex * 256 * 256); return true; } @@ -600,12 +352,12 @@ size_t THAnimations::getAnimationCount() { - return m_iAnimCount; + return anims.size(); } size_t THAnimations::getSpriteCount() { - return m_iSpriteCount; + return sprites.size(); } void THAnimations::setSpritePath(wxString aPath) @@ -616,41 +368,41 @@ void THAnimations::getAnimationMask(size_t iAnimation, THLayerMask& mskLayers) { mskLayers.clear(); - if(iAnimation >= m_iAnimCount) + if(iAnimation >= anims.size()) return; - uint16_t iFrameIndex = m_pAnims[iAnimation].frame; - if(iFrameIndex >= m_iFrameCount) + uint16_t iFrameIndex = anims.at(iAnimation).frame; + if(iFrameIndex >= frames.size()) return; uint16_t iFirstFrameIndex = iFrameIndex; do { - th_frame_t* pFrame = m_pFrames + iFrameIndex; + th_frame_t* pFrame = &(frames.at(iFrameIndex)); uint32_t iListIndex = pFrame->list_index; th_element_t* pElement; while((pElement = _getElement(iListIndex++))) { mskLayers.set(pElement->flags >> 4, pElement->layerid); } - iFrameIndex = m_pFrames[iFrameIndex].next; - } while(iFrameIndex != iFirstFrameIndex); + iFrameIndex = frames.at(iFrameIndex).next; + } while(iFrameIndex < frames.size() && iFrameIndex != iFirstFrameIndex); } size_t THAnimations::getFrameCount(size_t iAnimation) { - if(iAnimation >= m_iAnimCount) + if(iAnimation >= anims.size()) return 0; size_t iCount = 0; - uint16_t iFirstFrame = m_pAnims[iAnimation].frame; - if(iFirstFrame < m_iFrameCount) + uint16_t iFirstFrame = anims.at(iAnimation).frame; + if(iFirstFrame < frames.size()) { ++iCount; - uint16_t iFrame = m_pFrames[iFirstFrame].next; - while(iFrame != iFirstFrame && iFrame < m_iFrameCount && iCount < 1024) + uint16_t iFrame = frames.at(iFirstFrame).next; + while(iFrame != iFirstFrame && iFrame < frames.size() && iCount < 1024) { ++iCount; - iFrame = m_pFrames[iFrame].next; + iFrame = frames.at(iFrame).next; } } return iCount; @@ -658,69 +410,62 @@ bool THAnimations::doesAnimationIncludeFrame(size_t iAnimation, size_t iFrame) { - if(iAnimation >= m_iAnimCount || iFrame >= m_iFrameCount) + if(iAnimation >= anims.size() || iFrame >= frames.size()) return 0; - uint16_t iFirstFrame = m_pAnims[iAnimation].frame; + uint16_t iFirstFrame = anims.at(iAnimation).frame; uint16_t iFrameNow = iFirstFrame; do { - if(iFrameNow >= m_iFrameCount) + if(iFrameNow >= frames.size()) break; if(iFrame == iFrameNow) return true; - iFrameNow = m_pFrames[iFrameNow].next; + iFrameNow = frames.at(iFrameNow).next; } while(iFrameNow != iFirstFrame); return false; } Bitmap* THAnimations::getSpriteBitmap(size_t iSprite, bool bComplex) { - if(iSprite >= m_iSpriteCount) - return NULL; + if(iSprite >= sprites.size()) + return nullptr; - if(!m_pSpriteBitmaps[iSprite].IsOk()) + if (!spriteBitmaps.at(iSprite).IsOk()) { wxString spriteFile = m_sSpritePath + wxString::Format(L"a%04ue.png", (int)iSprite); - th_sprite_t* pSprite = m_pSprites + iSprite; + th_sprite_t* pSprite = &(sprites.at(iSprite)); - if(m_bXmlLoaded && wxFileName::FileExists(spriteFile)) - { - wxImage imgSprite(pSprite->width, pSprite->height, true); - imgSprite.LoadFile(spriteFile,wxBITMAP_TYPE_PNG); - m_pSpriteBitmaps[iSprite].create(pSprite->width, pSprite->height, imgSprite.GetData()); - } else { - ChunkRenderer oRenderer(pSprite->width, pSprite->height); - (bComplex ? decode_chunks_complex : decode_chunks)(oRenderer, (const unsigned char*)m_pChunks + pSprite->offset, m_iChunkCount - pSprite->offset, 0xFF); - m_pSpriteBitmaps[iSprite].create(pSprite->width, pSprite->height, oRenderer.getData()); - } + ChunkRenderer oRenderer(pSprite->width, pSprite->height); + (bComplex ? decode_chunks_complex : decode_chunks)(oRenderer, (const unsigned char*)chunks.data() + pSprite->offset, chunks.size() - pSprite->offset, 0xFF); + spriteBitmaps[iSprite].create(pSprite->width, pSprite->height, oRenderer.getData()); } - return m_pSpriteBitmaps + iSprite; + return &(spriteBitmaps.at(iSprite)); } th_frame_t* THAnimations::getFrameStruct(size_t iAnimation, size_t iFrame) { - if(iAnimation >= m_iAnimCount) + if(iAnimation >= anims.size()) return 0; - uint16_t iFrameIndex = m_pAnims[iAnimation].frame; + uint16_t iFrameIndex = anims.at(iAnimation).frame; while(iFrame--) { - iFrameIndex = m_pFrames[iFrameIndex].next; + iFrameIndex = frames.at(iFrameIndex).next; } - return &m_pFrames[iFrameIndex]; + return &(frames.at(iFrameIndex)); } void THAnimations::drawFrame(wxImage& imgCanvas, size_t iAnimation, size_t iFrame, const THLayerMask* pMask, wxSize& size, int iXOffset, int iYOffset) { - if(iAnimation >= m_iAnimCount) + if(iAnimation >= anims.size()) return; - uint16_t iFrameIndex = m_pAnims[iAnimation].frame; + uint16_t iFrameIndex = anims.at(iAnimation).frame; while(iFrame--) { - iFrameIndex = m_pFrames[iFrameIndex].next; + iFrameIndex = frames.at(iFrameIndex).next; } - th_frame_t* pFrame = m_pFrames + iFrameIndex; + th_frame_t* pFrame = &(frames.at(iFrameIndex)); th_element_t* pElement; uint32_t iListIndex = pFrame->list_index; int iFarX = 0; @@ -730,89 +475,58 @@ if(pMask != NULL && !pMask->isSet(pElement->flags >> 4, pElement->layerid)) continue; uint16_t iSpriteIndex = pElement->table_position / sizeof(th_sprite_t); - th_sprite_t* pSprite = m_pSprites + iSpriteIndex; + th_sprite_t* pSprite = &(sprites.at(iSpriteIndex)); int iRight = pElement->offx + pSprite->width; int iBottom = pElement->offy + pSprite->height; if(iRight > iFarX) iFarX = iRight; if(iBottom > iFarY) iFarY = iBottom; - wxString spriteFile = m_sSpritePath + wxString::Format(L"a%04ue.png", iSpriteIndex); - if(m_bXmlLoaded && wxFileName::FileExists(spriteFile)) - { - copySpriteToCanvas(spriteFile, iSpriteIndex, imgCanvas, pElement->offx + iXOffset, pElement->offy + iYOffset, pElement->flags & 0xF); - } else { - getSpriteBitmap(iSpriteIndex)->blit(imgCanvas, pElement->offx + iXOffset, pElement->offy + iYOffset, m_pGhostMaps + m_iGhostMapOffset, m_pColours, pElement->flags & 0xF); - } + + getSpriteBitmap(iSpriteIndex)->blit(imgCanvas, pElement->offx + iXOffset, pElement->offy + iYOffset, ghostMaps.data() + m_iGhostMapOffset, colours.data(), pElement->flags & 0xF); } size.x = iFarX; size.y = iFarY; } -void THAnimations::copySpriteToCanvas(wxString spriteFile, int iSpriteIndex, wxImage& imgCanvas, int iX, int iY, int iFlags) { - if(!m_pSpriteImages[iSpriteIndex].IsOk()) - { - th_sprite_t* pSprite = m_pSprites + iSpriteIndex; - if(m_pSpriteScaleFactors[iSpriteIndex] > 1) - { - int scale = m_pSpriteScaleFactors[iSpriteIndex]; - m_pSpriteImages[iSpriteIndex].Create(pSprite->width*scale, pSprite->height*scale, true); - m_pSpriteImages[iSpriteIndex].LoadFile(spriteFile,wxBITMAP_TYPE_PNG); - m_pSpriteImages[iSpriteIndex].Rescale(pSprite->width, pSprite->height); - } else { - m_pSpriteImages[iSpriteIndex].Create(pSprite->width, pSprite->height, true); - m_pSpriteImages[iSpriteIndex].LoadFile(spriteFile,wxBITMAP_TYPE_PNG); - } - //m_pSpriteImages[iSpriteIndex].SetMaskColour(0,0,0); - if(!m_pSpriteImages[iSpriteIndex].HasAlpha()) - { - m_pSpriteImages[iSpriteIndex].InitAlpha(); - } +th_element_t* THAnimations::_getElement(uint32_t iListIndex) +{ + if(iListIndex >= elementList.size()) + return nullptr; + uint16_t iElementIndex = elementList.at(iListIndex); + if(iElementIndex >= elements.size()) + return nullptr; + return &(elements.at(iElementIndex)); +} + +unsigned char* THAnimations::Decompress(unsigned char* pData, size_t& iLength) +{ + unsigned long outlen = rnc_output_size(pData); + unsigned char* outbuf = new unsigned char[outlen]; + if (rnc_input_size(pData) != iLength) { + throw std::length_error("rnc data does not match the expected length"); } - for(int y = 0; y < m_pSpriteImages[iSpriteIndex].GetHeight(); ++y) + if(rnc_unpack(pData, outbuf) == rnc_status::ok) { - for(int x = 0; x < m_pSpriteImages[iSpriteIndex].GetWidth(); ++x) - { - int iDstX = iX + x; - int iDstY = iY + y; - if(iFlags & 0x2) - iDstY = iY + m_pSpriteImages[iSpriteIndex].GetHeight() - 1 - y; - if(iFlags & 0x1) - iDstX = iX + m_pSpriteImages[iSpriteIndex].GetWidth() - 1 - x; - - if(m_pSpriteImages[iSpriteIndex].HasAlpha()) - { - if(!m_pSpriteImages[iSpriteIndex].IsTransparent(x,y,128)) - { - imgCanvas.SetRGB(iDstX,iDstY,m_pSpriteImages[iSpriteIndex].GetRed(x,y),m_pSpriteImages[iSpriteIndex].GetGreen(x,y), - m_pSpriteImages[iSpriteIndex].GetBlue(x,y)); - imgCanvas.SetAlpha(iDstX,iDstY,m_pSpriteImages[iSpriteIndex].GetAlpha(x,y)); - } - } else { - imgCanvas.SetRGB(iDstX,iDstY,m_pSpriteImages[iSpriteIndex].GetRed(x,y),m_pSpriteImages[iSpriteIndex].GetGreen(x,y), - m_pSpriteImages[iSpriteIndex].GetBlue(x,y)); - //imgCanvas.SetAlpha(iDstX,iDstY,m_pSpriteImages[iSpriteIndex].GetAlpha(x,y)); - } - } + delete[] pData; + iLength = outlen; + return outbuf; + } + else + { + delete[] pData; + delete[] outbuf; + iLength = 0; + return nullptr; } } -th_element_t* THAnimations::_getElement(uint32_t iListIndex) +Bitmap::Bitmap() : + m_iWidth(0), + m_iHeight(0), + m_pData(nullptr) { - if(iListIndex >= m_iElementListCount) - return NULL; - uint16_t iElementIndex = m_pElementList[iListIndex]; - if(iElementIndex > m_iElementCount) - return NULL; - return m_pElements + iElementIndex; -} - -Bitmap::Bitmap() -{ - m_iWidth = 0; - m_iHeight = 0; - m_pData = NULL; } Bitmap::~Bitmap() diff -Nru corsix-th-0.30/AnimView/th.h corsix-th-0.62/AnimView/th.h --- corsix-th-0.30/AnimView/th.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/th.h 2018-07-21 11:13:17.000000000 +0000 @@ -39,17 +39,9 @@ #include #include #include -#include "tinyxml.h" -#ifdef _MSC_VER -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -#else +#include #include -#endif // _MSC_VER +#include #pragma pack(push) #pragma pack(1) @@ -153,7 +145,7 @@ void blit(Bitmap& bmpCanvas, int iX, int iY, int iFlags = 0) const; void blit(wxImage& imgCanvas, int iX, int iY, const unsigned char* pColourTranslate, const th_colour_t* pPalette, int iFlags = 0) const; - bool IsOk() {return m_pData != NULL;} + bool IsOk() {return m_pData != nullptr;} protected: int m_iWidth; @@ -167,30 +159,37 @@ THAnimations(); ~THAnimations(); - bool loadAnimationFile(wxString sFilename) {return _loadArray(m_pAnims, m_iAnimCount, sFilename);} + bool loadAnimationFile(wxString sFilename) { + return loadVector(anims, sFilename); + } + bool loadFrameFile(wxString sFilename); - bool loadListFile(wxString sFilename) {return _loadArray(m_pElementList, m_iElementListCount, sFilename);} - bool loadElementFile(wxString sFilename) {return _loadArray(m_pElements, m_iElementCount, sFilename);} + + bool loadListFile(wxString sFilename) { + return loadVector(elementList, sFilename); + } + + bool loadElementFile(wxString sFilename) { + return loadVector(elements, sFilename); + } + bool loadTableFile(wxString sFilename); - bool loadSpriteFile(wxString sFilename) {return _loadArray(m_pChunks, m_iChunkCount, sFilename);} + + bool loadSpriteFile(wxString sFilename) { + return loadVector(chunks, sFilename); + } + bool loadPaletteFile(wxString sFilename); - bool loadGhostFile(wxString sFilename, int iIndex); - bool loadXMLFile(TiXmlDocument* xmlDocument); - void writeElementData(wxString aPath, wxTextOutputStream *outputLog, wxTextOutputStream *outputXml, - size_t iAnimation, size_t iFrame, const THLayerMask* pMask, wxSize& size, int* iListIndex); - void writeTableDataHeader(wxTextOutputStream *outputLog); + bool loadGhostFile(wxString sFilename, int iIndex); size_t markDuplicates(); size_t getAnimationCount(); size_t getSpriteCount(); size_t getFrameCount(size_t iAnimation); - uint16_t getUnknownField(size_t iAnimation) {return m_pAnims[iAnimation].unknown; } - uint16_t getFrameField(size_t iAnimation) {return m_pAnims[iAnimation].frame; } - //uint32_t getListIndexField(size_t iFrame) {return m_pFrames[iFrame].list_index; } - //uint8_t getFrameWidthField(size_t iFrame) {return m_pFrames[iFrame].width; } - //uint8_t getFrameHeightField(size_t iFrame) {return m_pFrames[iFrame].height; } + uint16_t getUnknownField(size_t iAnimation) {return anims.at(iAnimation).unknown; } + uint16_t getFrameField(size_t iAnimation) {return anims.at(iAnimation).frame; } th_frame_t* getFrameStruct(size_t iAnimation, size_t iFrame); bool isAnimationDuplicate(size_t iAnimation); bool doesAnimationIncludeFrame(size_t iAnimation, size_t iFrame); @@ -198,7 +197,7 @@ void setSpritePath(wxString aPath); Bitmap* getSpriteBitmap(size_t iSprite, bool bComplex = false); - th_colour_t* getPalette() {return m_pColours;} + th_colour_t* getPalette() { return colours.data(); } void setGhost(int iFile, int iIndex); void drawFrame(wxImage& imgCanvas, size_t iAnimation, size_t iFrame, const THLayerMask* pMask, wxSize& size, int iXOffset = 0, int iYOffset = 0); @@ -207,18 +206,13 @@ static unsigned char* Decompress(unsigned char* pData, size_t& iLength); protected: template - bool _loadArray(T*& pArray, size_t& iCount, wxString sFilename) - { - if(pArray != NULL) - { - delete[] pArray; - pArray = NULL; - } - iCount = 0; + bool loadVector(std::vector& vector, wxString sFilename) { + vector.clear(); wxFile oFile(sFilename); - if(!oFile.IsOpened()) + if (!oFile.IsOpened()) return false; + size_t iLen = oFile.Length(); unsigned char* pBuffer = new unsigned char[iLen]; oFile.Read(pBuffer, iLen); @@ -230,31 +224,25 @@ return false; } } - pArray = (T*)pBuffer; - iCount = iLen / sizeof(T); + + for (int offset = 0; offset < iLen; offset += sizeof(T)) { + vector.push_back(*(reinterpret_cast(pBuffer + offset))); + } + return true; } + th_element_t* _getElement(uint32_t iListIndex); - th_anim_t* m_pAnims; - th_frame_t* m_pFrames; - uint16_t* m_pElementList; - th_element_t* m_pElements; - th_sprite_t* m_pSprites; - Bitmap* m_pSpriteBitmaps; - wxImage* m_pSpriteImages; - uint8_t* m_pSpriteScaleFactors; - uint8_t* m_pChunks; - th_colour_t* m_pColours; - unsigned char* m_pGhostMaps; + std::vector anims; + std::vector frames; + std::vector elementList; + std::vector elements; + std::vector sprites; + std::vector spriteBitmaps; + std::vector chunks; + std::vector colours; + std::array ghostMaps; size_t m_iGhostMapOffset; - size_t m_iAnimCount; - size_t m_iFrameCount; - size_t m_iElementListCount; - size_t m_iElementCount; - size_t m_iSpriteCount; - size_t m_iChunkCount; - size_t m_iColourCount; - bool m_bXmlLoaded; wxString m_sSpritePath; }; diff -Nru corsix-th-0.30/AnimView/tinystr.cpp corsix-th-0.62/AnimView/tinystr.cpp --- corsix-th-0.30/AnimView/tinystr.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/tinystr.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#ifndef TIXML_USE_STL - -#include "tinystr.h" - -// Error value for find primitive -const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); - - -// Null rep. -TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; - - -void TiXmlString::reserve (size_type cap) -{ - if (cap > capacity()) - { - TiXmlString tmp; - tmp.init(length(), cap); - memcpy(tmp.start(), data(), length()); - swap(tmp); - } -} - - -TiXmlString& TiXmlString::assign(const char* str, size_type len) -{ - size_type cap = capacity(); - if (len > cap || cap > 3*(len + 8)) - { - TiXmlString tmp; - tmp.init(len); - memcpy(tmp.start(), str, len); - swap(tmp); - } - else - { - memmove(start(), str, len); - set_size(len); - } - return *this; -} - - -TiXmlString& TiXmlString::append(const char* str, size_type len) -{ - size_type newsize = length() + len; - if (newsize > capacity()) - { - reserve (newsize + capacity()); - } - memmove(finish(), str, len); - set_size(newsize); - return *this; -} - - -TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) -{ - TiXmlString tmp; - tmp.reserve(a.length() + b.length()); - tmp += a; - tmp += b; - return tmp; -} - -TiXmlString operator + (const TiXmlString & a, const char* b) -{ - TiXmlString tmp; - TiXmlString::size_type b_len = static_cast( strlen(b) ); - tmp.reserve(a.length() + b_len); - tmp += a; - tmp.append(b, b_len); - return tmp; -} - -TiXmlString operator + (const char* a, const TiXmlString & b) -{ - TiXmlString tmp; - TiXmlString::size_type a_len = static_cast( strlen(a) ); - tmp.reserve(a_len + b.length()); - tmp.append(a, a_len); - tmp += b; - return tmp; -} - - -#endif // TIXML_USE_STL diff -Nru corsix-th-0.30/AnimView/tinystr.h corsix-th-0.62/AnimView/tinystr.h --- corsix-th-0.30/AnimView/tinystr.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/tinystr.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,305 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#ifndef TIXML_USE_STL - -#ifndef TIXML_STRING_INCLUDED -#define TIXML_STRING_INCLUDED - -#include -#include - -/* The support for explicit isn't that universal, and it isn't really - required - it is used to check that the TiXmlString class isn't incorrectly - used. Be nice to old compilers and macro it here: -*/ -#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) - // Microsoft visual studio, version 6 and higher. - #define TIXML_EXPLICIT explicit -#elif defined(__GNUC__) && (__GNUC__ >= 3 ) - // GCC version 3 and higher.s - #define TIXML_EXPLICIT explicit -#else - #define TIXML_EXPLICIT -#endif - - -/* - TiXmlString is an emulation of a subset of the std::string template. - Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. - Only the member functions relevant to the TinyXML project have been implemented. - The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase - a string and there's no more room, we allocate a buffer twice as big as we need. -*/ -class TiXmlString -{ - public : - // The size type used - typedef size_t size_type; - - // Error value for find primitive - static const size_type npos; // = -1; - - - // TiXmlString empty constructor - TiXmlString () : rep_(&nullrep_) - { - } - - // TiXmlString copy constructor - TiXmlString ( const TiXmlString & copy) : rep_(0) - { - init(copy.length()); - memcpy(start(), copy.data(), length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) - { - init( static_cast( strlen(copy) )); - memcpy(start(), copy, length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) - { - init(len); - memcpy(start(), str, len); - } - - // TiXmlString destructor - ~TiXmlString () - { - quit(); - } - - TiXmlString& operator = (const char * copy) - { - return assign( copy, (size_type)strlen(copy)); - } - - TiXmlString& operator = (const TiXmlString & copy) - { - return assign(copy.start(), copy.length()); - } - - - // += operator. Maps to append - TiXmlString& operator += (const char * suffix) - { - return append(suffix, static_cast( strlen(suffix) )); - } - - // += operator. Maps to append - TiXmlString& operator += (char single) - { - return append(&single, 1); - } - - // += operator. Maps to append - TiXmlString& operator += (const TiXmlString & suffix) - { - return append(suffix.data(), suffix.length()); - } - - - // Convert a TiXmlString into a null-terminated char * - const char * c_str () const { return rep_->str; } - - // Convert a TiXmlString into a char * (need not be null terminated). - const char * data () const { return rep_->str; } - - // Return the length of a TiXmlString - size_type length () const { return rep_->size; } - - // Alias for length() - size_type size () const { return rep_->size; } - - // Checks if a TiXmlString is empty - bool empty () const { return rep_->size == 0; } - - // Return capacity of string - size_type capacity () const { return rep_->capacity; } - - - // single char extraction - const char& at (size_type index) const - { - assert( index < length() ); - return rep_->str[ index ]; - } - - // [] operator - char& operator [] (size_type index) const - { - assert( index < length() ); - return rep_->str[ index ]; - } - - // find a char in a string. Return TiXmlString::npos if not found - size_type find (char lookup) const - { - return find(lookup, 0); - } - - // find a char in a string from an offset. Return TiXmlString::npos if not found - size_type find (char tofind, size_type offset) const - { - if (offset >= length()) return npos; - - for (const char* p = c_str() + offset; *p != '\0'; ++p) - { - if (*p == tofind) return static_cast< size_type >( p - c_str() ); - } - return npos; - } - - void clear () - { - //Lee: - //The original was just too strange, though correct: - // TiXmlString().swap(*this); - //Instead use the quit & re-init: - quit(); - init(0,0); - } - - /* Function to reserve a big amount of data when we know we'll need it. Be aware that this - function DOES NOT clear the content of the TiXmlString if any exists. - */ - void reserve (size_type cap); - - TiXmlString& assign (const char* str, size_type len); - - TiXmlString& append (const char* str, size_type len); - - void swap (TiXmlString& other) - { - Rep* r = rep_; - rep_ = other.rep_; - other.rep_ = r; - } - - private: - - void init(size_type sz) { init(sz, sz); } - void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } - char* start() const { return rep_->str; } - char* finish() const { return rep_->str + rep_->size; } - - struct Rep - { - size_type size, capacity; - char str[1]; - }; - - void init(size_type sz, size_type cap) - { - if (cap) - { - // Lee: the original form: - // rep_ = static_cast(operator new(sizeof(Rep) + cap)); - // doesn't work in some cases of new being overloaded. Switching - // to the normal allocation, although use an 'int' for systems - // that are overly picky about structure alignment. - const size_type bytesNeeded = sizeof(Rep) + cap; - const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); - rep_ = reinterpret_cast( new int[ intsNeeded ] ); - - rep_->str[ rep_->size = sz ] = '\0'; - rep_->capacity = cap; - } - else - { - rep_ = &nullrep_; - } - } - - void quit() - { - if (rep_ != &nullrep_) - { - // The rep_ is really an array of ints. (see the allocator, above). - // Cast it back before delete, so the compiler won't incorrectly call destructors. - delete [] ( reinterpret_cast( rep_ ) ); - } - } - - Rep * rep_; - static Rep nullrep_; - -} ; - - -inline bool operator == (const TiXmlString & a, const TiXmlString & b) -{ - return ( a.length() == b.length() ) // optimization on some platforms - && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare -} -inline bool operator < (const TiXmlString & a, const TiXmlString & b) -{ - return strcmp(a.c_str(), b.c_str()) < 0; -} - -inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } -inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } -inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } -inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } - -inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } -inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } -inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } -inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } - -TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); -TiXmlString operator + (const TiXmlString & a, const char* b); -TiXmlString operator + (const char* a, const TiXmlString & b); - - -/* - TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. - Only the operators that we need for TinyXML have been developped. -*/ -class TiXmlOutStream : public TiXmlString -{ -public : - - // TiXmlOutStream << operator. - TiXmlOutStream & operator << (const TiXmlString & in) - { - *this += in; - return *this; - } - - // TiXmlOutStream << operator. - TiXmlOutStream & operator << (const char * in) - { - *this += in; - return *this; - } - -} ; - -#endif // TIXML_STRING_INCLUDED -#endif // TIXML_USE_STL diff -Nru corsix-th-0.30/AnimView/tinyxml.cpp corsix-th-0.62/AnimView/tinyxml.cpp --- corsix-th-0.30/AnimView/tinyxml.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/tinyxml.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1886 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include - -#ifdef TIXML_USE_STL -#include -#include -#endif - -#include "tinyxml.h" - -FILE* TiXmlFOpen( const char* filename, const char* mode ); - -bool TiXmlBase::condenseWhiteSpace = true; - -// Microsoft compiler security -FILE* TiXmlFOpen( const char* filename, const char* mode ) -{ - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - FILE* fp = 0; - errno_t err = fopen_s( &fp, filename, mode ); - if ( !err && fp ) - return fp; - return 0; - #else - return fopen( filename, mode ); - #endif -} - -void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) -{ - int i=0; - - while( i<(int)str.length() ) - { - unsigned char c = (unsigned char) str[i]; - - if ( c == '&' - && i < ( (int)str.length() - 2 ) - && str[i+1] == '#' - && str[i+2] == 'x' ) - { - // Hexadecimal character reference. - // Pass through unchanged. - // © -- copyright symbol, for example. - // - // The -1 is a bug fix from Rob Laveaux. It keeps - // an overflow from happening if there is no ';'. - // There are actually 2 ways to exit this loop - - // while fails (error case) and break (semicolon found). - // However, there is no mechanism (currently) for - // this function to return an error. - while ( i<(int)str.length()-1 ) - { - outString->append( str.c_str() + i, 1 ); - ++i; - if ( str[i] == ';' ) - break; - } - } - else if ( c == '&' ) - { - outString->append( entity[0].str, entity[0].strLength ); - ++i; - } - else if ( c == '<' ) - { - outString->append( entity[1].str, entity[1].strLength ); - ++i; - } - else if ( c == '>' ) - { - outString->append( entity[2].str, entity[2].strLength ); - ++i; - } - else if ( c == '\"' ) - { - outString->append( entity[3].str, entity[3].strLength ); - ++i; - } - else if ( c == '\'' ) - { - outString->append( entity[4].str, entity[4].strLength ); - ++i; - } - else if ( c < 32 ) - { - // Easy pass at non-alpha/numeric/symbol - // Below 32 is symbolic. - char buf[ 32 ]; - - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); - #else - sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); - #endif - - //*ME: warning C4267: convert 'size_t' to 'int' - //*ME: Int-Cast to make compiler happy ... - outString->append( buf, (int)strlen( buf ) ); - ++i; - } - else - { - //char realc = (char) c; - //outString->append( &realc, 1 ); - *outString += (char) c; // somewhat more efficient function call. - ++i; - } - } -} - - -TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() -{ - parent = 0; - type = _type; - firstChild = 0; - lastChild = 0; - prev = 0; - next = 0; -} - - -TiXmlNode::~TiXmlNode() -{ - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } -} - - -void TiXmlNode::CopyTo( TiXmlNode* target ) const -{ - target->SetValue (value.c_str() ); - target->userData = userData; - target->location = location; -} - - -void TiXmlNode::Clear() -{ - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } - - firstChild = 0; - lastChild = 0; -} - - -TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) -{ - assert( node->parent == 0 || node->parent == this ); - assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); - - if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - delete node; - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - node->parent = this; - - node->prev = lastChild; - node->next = 0; - - if ( lastChild ) - lastChild->next = node; - else - firstChild = node; // it was an empty list. - - lastChild = node; - return node; -} - - -TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) -{ - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - - return LinkEndChild( node ); -} - - -TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) -{ - if ( !beforeThis || beforeThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->next = beforeThis; - node->prev = beforeThis->prev; - if ( beforeThis->prev ) - { - beforeThis->prev->next = node; - } - else - { - assert( firstChild == beforeThis ); - firstChild = node; - } - beforeThis->prev = node; - return node; -} - - -TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) -{ - if ( !afterThis || afterThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->prev = afterThis; - node->next = afterThis->next; - if ( afterThis->next ) - { - afterThis->next->prev = node; - } - else - { - assert( lastChild == afterThis ); - lastChild = node; - } - afterThis->next = node; - return node; -} - - -TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) -{ - if ( !replaceThis ) - return 0; - - if ( replaceThis->parent != this ) - return 0; - - if ( withThis.ToDocument() ) { - // A document can never be a child. Thanks to Noam. - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = withThis.Clone(); - if ( !node ) - return 0; - - node->next = replaceThis->next; - node->prev = replaceThis->prev; - - if ( replaceThis->next ) - replaceThis->next->prev = node; - else - lastChild = node; - - if ( replaceThis->prev ) - replaceThis->prev->next = node; - else - firstChild = node; - - delete replaceThis; - node->parent = this; - return node; -} - - -bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) -{ - if ( !removeThis ) { - return false; - } - - if ( removeThis->parent != this ) - { - assert( 0 ); - return false; - } - - if ( removeThis->next ) - removeThis->next->prev = removeThis->prev; - else - lastChild = removeThis->prev; - - if ( removeThis->prev ) - removeThis->prev->next = removeThis->next; - else - firstChild = removeThis->next; - - delete removeThis; - return true; -} - -const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = firstChild; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = lastChild; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const -{ - if ( !previous ) - { - return FirstChild(); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling(); - } -} - - -const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const -{ - if ( !previous ) - { - return FirstChild( val ); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling( val ); - } -} - - -const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = next; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = prev; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -void TiXmlElement::RemoveAttribute( const char * name ) -{ - #ifdef TIXML_USE_STL - TIXML_STRING str( name ); - TiXmlAttribute* node = attributeSet.Find( str ); - #else - TiXmlAttribute* node = attributeSet.Find( name ); - #endif - if ( node ) - { - attributeSet.Remove( node ); - delete node; - } -} - -const TiXmlElement* TiXmlNode::FirstChildElement() const -{ - const TiXmlNode* node; - - for ( node = FirstChild(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const -{ - const TiXmlNode* node; - - for ( node = FirstChild( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::NextSiblingElement() const -{ - const TiXmlNode* node; - - for ( node = NextSibling(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const -{ - const TiXmlNode* node; - - for ( node = NextSibling( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlDocument* TiXmlNode::GetDocument() const -{ - const TiXmlNode* node; - - for( node = this; node; node = node->parent ) - { - if ( node->ToDocument() ) - return node->ToDocument(); - } - return 0; -} - - -TiXmlElement::TiXmlElement (const char * _value) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) -{ - firstChild = lastChild = 0; - value = _value; -} - - -#ifdef TIXML_USE_STL -TiXmlElement::TiXmlElement( const std::string& _value ) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) -{ - firstChild = lastChild = 0; - value = _value; -} -#endif - - -TiXmlElement::TiXmlElement( const TiXmlElement& copy) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) -{ - firstChild = lastChild = 0; - copy.CopyTo( this ); -} - - -TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) -{ - ClearThis(); - base.CopyTo( this ); - return *this; -} - - -TiXmlElement::~TiXmlElement() -{ - ClearThis(); -} - - -void TiXmlElement::ClearThis() -{ - Clear(); - while( attributeSet.First() ) - { - TiXmlAttribute* node = attributeSet.First(); - attributeSet.Remove( node ); - delete node; - } -} - - -const char* TiXmlElement::Attribute( const char* name ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return node->Value(); - return 0; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( attrib ) - return &attrib->ValueStr(); - return 0; -} -#endif - - -const char* TiXmlElement::Attribute( const char* name, int* i ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const char* result = 0; - - if ( attrib ) { - result = attrib->Value(); - if ( i ) { - attrib->QueryIntValue( i ); - } - } - return result; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const std::string* result = 0; - - if ( attrib ) { - result = &attrib->ValueStr(); - if ( i ) { - attrib->QueryIntValue( i ); - } - } - return result; -} -#endif - - -const char* TiXmlElement::Attribute( const char* name, double* d ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const char* result = 0; - - if ( attrib ) { - result = attrib->Value(); - if ( d ) { - attrib->QueryDoubleValue( d ); - } - } - return result; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const std::string* result = 0; - - if ( attrib ) { - result = &attrib->ValueStr(); - if ( d ) { - attrib->QueryDoubleValue( d ); - } - } - return result; -} -#endif - - -int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryIntValue( ival ); -} - - -int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - int ival = 0; - int result = node->QueryIntValue( &ival ); - *value = (unsigned)ival; - return result; -} - - -int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - int result = TIXML_WRONG_TYPE; - if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) - { - *bval = true; - result = TIXML_SUCCESS; - } - else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) - { - *bval = false; - result = TIXML_SUCCESS; - } - return result; -} - - - -#ifdef TIXML_USE_STL -int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryIntValue( ival ); -} -#endif - - -int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryDoubleValue( dval ); -} - - -#ifdef TIXML_USE_STL -int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryDoubleValue( dval ); -} -#endif - - -void TiXmlElement::SetAttribute( const char * name, int val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetIntValue( val ); - } -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& name, int val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetIntValue( val ); - } -} -#endif - - -void TiXmlElement::SetDoubleAttribute( const char * name, double val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetDoubleValue( val ); - } -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetDoubleValue( val ); - } -} -#endif - - -void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); - if ( attrib ) { - attrib->SetValue( cvalue ); - } -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); - if ( attrib ) { - attrib->SetValue( _value ); - } -} -#endif - - -void TiXmlElement::Print( FILE* cfile, int depth ) const -{ - int i; - assert( cfile ); - for ( i=0; iNext() ) - { - fprintf( cfile, " " ); - attrib->Print( cfile, depth ); - } - - // There are 3 different formatting approaches: - // 1) An element without children is printed as a node - // 2) An element with only a text child is printed as text - // 3) An element with children is printed on multiple lines. - TiXmlNode* node; - if ( !firstChild ) - { - fprintf( cfile, " />" ); - } - else if ( firstChild == lastChild && firstChild->ToText() ) - { - fprintf( cfile, ">" ); - firstChild->Print( cfile, depth + 1 ); - fprintf( cfile, "", value.c_str() ); - } - else - { - fprintf( cfile, ">" ); - - for ( node = firstChild; node; node=node->NextSibling() ) - { - if ( !node->ToText() ) - { - fprintf( cfile, "\n" ); - } - node->Print( cfile, depth+1 ); - } - fprintf( cfile, "\n" ); - for( i=0; i", value.c_str() ); - } -} - - -void TiXmlElement::CopyTo( TiXmlElement* target ) const -{ - // superclass: - TiXmlNode::CopyTo( target ); - - // Element class: - // Clone the attributes, then clone the children. - const TiXmlAttribute* attribute = 0; - for( attribute = attributeSet.First(); - attribute; - attribute = attribute->Next() ) - { - target->SetAttribute( attribute->Name(), attribute->Value() ); - } - - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } -} - -bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const -{ - if ( visitor->VisitEnter( *this, attributeSet.First() ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); -} - - -TiXmlNode* TiXmlElement::Clone() const -{ - TiXmlElement* clone = new TiXmlElement( Value() ); - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -const char* TiXmlElement::GetText() const -{ - const TiXmlNode* child = this->FirstChild(); - if ( child ) { - const TiXmlText* childText = child->ToText(); - if ( childText ) { - return childText->Value(); - } - } - return 0; -} - - -TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - ClearError(); -} - -TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} - - -#ifdef TIXML_USE_STL -TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} -#endif - - -TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) -{ - copy.CopyTo( this ); -} - - -TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) -{ - Clear(); - copy.CopyTo( this ); - return *this; -} - - -bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) -{ - return LoadFile( Value(), encoding ); -} - - -bool TiXmlDocument::SaveFile() const -{ - return SaveFile( Value() ); -} - -bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) -{ - TIXML_STRING filename( _filename ); - value = filename; - - // reading in binary mode so that tinyxml can normalize the EOL - FILE* file = TiXmlFOpen( value.c_str (), "rb" ); - - if ( file ) - { - bool result = LoadFile( file, encoding ); - fclose( file ); - return result; - } - else - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } -} - -bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) -{ - if ( !file ) - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Delete the existing data: - Clear(); - location.Clear(); - - // Get the file size, so we can pre-allocate the string. HUGE speed impact. - long length = 0; - fseek( file, 0, SEEK_END ); - length = ftell( file ); - fseek( file, 0, SEEK_SET ); - - // Strange case, but good to handle up front. - if ( length <= 0 ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Subtle bug here. TinyXml did use fgets. But from the XML spec: - // 2.11 End-of-Line Handling - // - // - // ...the XML processor MUST behave as if it normalized all line breaks in external - // parsed entities (including the document entity) on input, before parsing, by translating - // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to - // a single #xA character. - // - // - // It is not clear fgets does that, and certainly isn't clear it works cross platform. - // Generally, you expect fgets to translate from the convention of the OS to the c/unix - // convention, and not work generally. - - /* - while( fgets( buf, sizeof(buf), file ) ) - { - data += buf; - } - */ - - char* buf = new char[ length+1 ]; - buf[0] = 0; - - if ( fread( buf, length, 1, file ) != 1 ) { - delete [] buf; - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Process the buffer in place to normalize new lines. (See comment above.) - // Copies from the 'p' to 'q' pointer, where p can advance faster if - // a newline-carriage return is hit. - // - // Wikipedia: - // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or - // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... - // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others - // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS - // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 - - const char* p = buf; // the read head - char* q = buf; // the write head - const char CR = 0x0d; - const char LF = 0x0a; - - buf[length] = 0; - while( *p ) { - assert( p < (buf+length) ); - assert( q <= (buf+length) ); - assert( q <= p ); - - if ( *p == CR ) { - *q++ = LF; - p++; - if ( *p == LF ) { // check for CR+LF (and skip LF) - p++; - } - } - else { - *q++ = *p++; - } - } - assert( q <= (buf+length) ); - *q = 0; - - Parse( buf, 0, encoding ); - - delete [] buf; - return !Error(); -} - - -bool TiXmlDocument::SaveFile( const char * filename ) const -{ - // The old c stuff lives on... - FILE* fp = TiXmlFOpen( filename, "w" ); - if ( fp ) - { - bool result = SaveFile( fp ); - fclose( fp ); - return result; - } - return false; -} - - -bool TiXmlDocument::SaveFile( FILE* fp ) const -{ - if ( useMicrosoftBOM ) - { - const unsigned char TIXML_UTF_LEAD_0 = 0xefU; - const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; - const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - - fputc( TIXML_UTF_LEAD_0, fp ); - fputc( TIXML_UTF_LEAD_1, fp ); - fputc( TIXML_UTF_LEAD_2, fp ); - } - Print( fp, 0 ); - return (ferror(fp) == 0); -} - - -void TiXmlDocument::CopyTo( TiXmlDocument* target ) const -{ - TiXmlNode::CopyTo( target ); - - target->error = error; - target->errorId = errorId; - target->errorDesc = errorDesc; - target->tabsize = tabsize; - target->errorLocation = errorLocation; - target->useMicrosoftBOM = useMicrosoftBOM; - - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } -} - - -TiXmlNode* TiXmlDocument::Clone() const -{ - TiXmlDocument* clone = new TiXmlDocument(); - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlDocument::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - node->Print( cfile, depth ); - fprintf( cfile, "\n" ); - } -} - - -bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const -{ - if ( visitor->VisitEnter( *this ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); -} - - -const TiXmlAttribute* TiXmlAttribute::Next() const -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} - -/* -TiXmlAttribute* TiXmlAttribute::Next() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} -*/ - -const TiXmlAttribute* TiXmlAttribute::Previous() const -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} - -/* -TiXmlAttribute* TiXmlAttribute::Previous() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} -*/ - -void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const -{ - TIXML_STRING n, v; - - EncodeString( name, &n ); - EncodeString( value, &v ); - - if (value.find ('\"') == TIXML_STRING::npos) { - if ( cfile ) { - fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; - } - } - else { - if ( cfile ) { - fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; - } - } -} - - -int TiXmlAttribute::QueryIntValue( int* ival ) const -{ - if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -int TiXmlAttribute::QueryDoubleValue( double* dval ) const -{ - if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -void TiXmlAttribute::SetIntValue( int _value ) -{ - char buf [64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); - #else - sprintf (buf, "%d", _value); - #endif - SetValue (buf); -} - -void TiXmlAttribute::SetDoubleValue( double _value ) -{ - char buf [256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); - #else - sprintf (buf, "%g", _value); - #endif - SetValue (buf); -} - -int TiXmlAttribute::IntValue() const -{ - return atoi (value.c_str ()); -} - -double TiXmlAttribute::DoubleValue() const -{ - return atof (value.c_str ()); -} - - -TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) -{ - copy.CopyTo( this ); -} - - -TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) -{ - Clear(); - base.CopyTo( this ); - return *this; -} - - -void TiXmlComment::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - for ( int i=0; i", value.c_str() ); -} - - -void TiXmlComment::CopyTo( TiXmlComment* target ) const -{ - TiXmlNode::CopyTo( target ); -} - - -bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlComment::Clone() const -{ - TiXmlComment* clone = new TiXmlComment(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlText::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - if ( cdata ) - { - int i; - fprintf( cfile, "\n" ); - for ( i=0; i\n", value.c_str() ); // unformatted output - } - else - { - TIXML_STRING buffer; - EncodeString( value, &buffer ); - fprintf( cfile, "%s", buffer.c_str() ); - } -} - - -void TiXmlText::CopyTo( TiXmlText* target ) const -{ - TiXmlNode::CopyTo( target ); - target->cdata = cdata; -} - - -bool TiXmlText::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlText::Clone() const -{ - TiXmlText* clone = 0; - clone = new TiXmlText( "" ); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -TiXmlDeclaration::TiXmlDeclaration( const char * _version, - const char * _encoding, - const char * _standalone ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) -{ - version = _version; - encoding = _encoding; - standalone = _standalone; -} - - -#ifdef TIXML_USE_STL -TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) -{ - version = _version; - encoding = _encoding; - standalone = _standalone; -} -#endif - - -TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) -{ - copy.CopyTo( this ); -} - - -TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) -{ - Clear(); - copy.CopyTo( this ); - return *this; -} - - -void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const -{ - if ( cfile ) fprintf( cfile, "" ); - if ( str ) (*str) += "?>"; -} - - -void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const -{ - TiXmlNode::CopyTo( target ); - - target->version = version; - target->encoding = encoding; - target->standalone = standalone; -} - - -bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlDeclaration::Clone() const -{ - TiXmlDeclaration* clone = new TiXmlDeclaration(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlUnknown::Print( FILE* cfile, int depth ) const -{ - for ( int i=0; i", value.c_str() ); -} - - -void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const -{ - TiXmlNode::CopyTo( target ); -} - - -bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlUnknown::Clone() const -{ - TiXmlUnknown* clone = new TiXmlUnknown(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -TiXmlAttributeSet::TiXmlAttributeSet() -{ - sentinel.next = &sentinel; - sentinel.prev = &sentinel; -} - - -TiXmlAttributeSet::~TiXmlAttributeSet() -{ - assert( sentinel.next == &sentinel ); - assert( sentinel.prev == &sentinel ); -} - - -void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) -{ - #ifdef TIXML_USE_STL - assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. - #else - assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. - #endif - - addMe->next = &sentinel; - addMe->prev = sentinel.prev; - - sentinel.prev->next = addMe; - sentinel.prev = addMe; -} - -void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) -{ - TiXmlAttribute* node; - - for( node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node == removeMe ) - { - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; - return; - } - } - assert( 0 ); // we tried to remove a non-linked attribute. -} - - -#ifdef TIXML_USE_STL -TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const -{ - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; - } - return 0; -} - -TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) -{ - TiXmlAttribute* attrib = Find( _name ); - if ( !attrib ) { - attrib = new TiXmlAttribute(); - Add( attrib ); - attrib->SetName( _name ); - } - return attrib; -} -#endif - - -TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const -{ - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; - } - return 0; -} - - -TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) -{ - TiXmlAttribute* attrib = Find( _name ); - if ( !attrib ) { - attrib = new TiXmlAttribute(); - Add( attrib ); - attrib->SetName( _name ); - } - return attrib; -} - - -#ifdef TIXML_USE_STL -std::istream& operator>> (std::istream & in, TiXmlNode & base) -{ - TIXML_STRING tag; - tag.reserve( 8 * 1000 ); - base.StreamIn( &in, &tag ); - - base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); - return in; -} -#endif - - -#ifdef TIXML_USE_STL -std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) -{ - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out << printer.Str(); - - return out; -} - - -std::string& operator<< (std::string& out, const TiXmlNode& base ) -{ - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out.append( printer.Str() ); - - return out; -} -#endif - - -TiXmlHandle TiXmlHandle::FirstChild() const -{ - if ( node ) - { - TiXmlNode* child = node->FirstChild(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const -{ - if ( node ) - { - TiXmlNode* child = node->FirstChild( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChildElement() const -{ - if ( node ) - { - TiXmlElement* child = node->FirstChildElement(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const -{ - if ( node ) - { - TiXmlElement* child = node->FirstChildElement( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::Child( int count ) const -{ - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild(); - for ( i=0; - child && iNextSibling(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const -{ - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild( value ); - for ( i=0; - child && iNextSibling( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::ChildElement( int count ) const -{ - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement(); - for ( i=0; - child && iNextSiblingElement(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const -{ - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement( value ); - for ( i=0; - child && iNextSiblingElement( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) -{ - return true; -} - -bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) -{ - return true; -} - -bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) -{ - DoIndent(); - buffer += "<"; - buffer += element.Value(); - - for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) - { - buffer += " "; - attrib->Print( 0, 0, &buffer ); - } - - if ( !element.FirstChild() ) - { - buffer += " />"; - DoLineBreak(); - } - else - { - buffer += ">"; - if ( element.FirstChild()->ToText() - && element.LastChild() == element.FirstChild() - && element.FirstChild()->ToText()->CDATA() == false ) - { - simpleTextPrint = true; - // no DoLineBreak()! - } - else - { - DoLineBreak(); - } - } - ++depth; - return true; -} - - -bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) -{ - --depth; - if ( !element.FirstChild() ) - { - // nothing. - } - else - { - if ( simpleTextPrint ) - { - simpleTextPrint = false; - } - else - { - DoIndent(); - } - buffer += ""; - DoLineBreak(); - } - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlText& text ) -{ - if ( text.CDATA() ) - { - DoIndent(); - buffer += ""; - DoLineBreak(); - } - else if ( simpleTextPrint ) - { - TIXML_STRING str; - TiXmlBase::EncodeString( text.ValueTStr(), &str ); - buffer += str; - } - else - { - DoIndent(); - TIXML_STRING str; - TiXmlBase::EncodeString( text.ValueTStr(), &str ); - buffer += str; - DoLineBreak(); - } - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) -{ - DoIndent(); - declaration.Print( 0, 0, &buffer ); - DoLineBreak(); - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlComment& comment ) -{ - DoIndent(); - buffer += ""; - DoLineBreak(); - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) -{ - DoIndent(); - buffer += "<"; - buffer += unknown.Value(); - buffer += ">"; - DoLineBreak(); - return true; -} - diff -Nru corsix-th-0.30/AnimView/tinyxmlerror.cpp corsix-th-0.62/AnimView/tinyxmlerror.cpp --- corsix-th-0.30/AnimView/tinyxmlerror.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/tinyxmlerror.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include "tinyxml.h" - -// The goal of the seperate error file is to make the first -// step towards localization. tinyxml (currently) only supports -// english error messages, but the could now be translated. -// -// It also cleans up the code a bit. -// - -const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = -{ - "No error", - "Error", - "Failed to open file", - "Error parsing Element.", - "Failed to read Element name", - "Error reading Element value.", - "Error reading Attributes.", - "Error: empty tag.", - "Error reading end tag.", - "Error parsing Unknown.", - "Error parsing Comment.", - "Error parsing Declaration.", - "Error document empty.", - "Error null (0) or unexpected EOF found in input stream.", - "Error parsing CDATA.", - "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", -}; diff -Nru corsix-th-0.30/AnimView/tinyxml.h corsix-th-0.62/AnimView/tinyxml.h --- corsix-th-0.30/AnimView/tinyxml.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/AnimView/tinyxml.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1805 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#ifndef TINYXML_INCLUDED -#define TINYXML_INCLUDED - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4530 ) -#pragma warning( disable : 4786 ) -#endif - -#include -#include -#include -#include -#include - -// Help out windows: -#if defined( _DEBUG ) && !defined( DEBUG ) -#define DEBUG -#endif - -#ifdef TIXML_USE_STL - #include - #include - #include - #define TIXML_STRING std::string -#else - #include "tinystr.h" - #define TIXML_STRING TiXmlString -#endif - -// Deprecated library function hell. Compilers want to use the -// new safe versions. This probably doesn't fully address the problem, -// but it gets closer. There are too many compilers for me to fully -// test. If you get compilation troubles, undefine TIXML_SAFE -#define TIXML_SAFE - -#ifdef TIXML_SAFE - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - // Microsoft visual studio, version 2005 and higher. - #define TIXML_SNPRINTF _snprintf_s - #define TIXML_SSCANF sscanf_s - #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) - // Microsoft visual studio, version 6 and higher. - //#pragma message( "Using _sn* functions." ) - #define TIXML_SNPRINTF _snprintf - #define TIXML_SSCANF sscanf - #elif defined(__GNUC__) && (__GNUC__ >= 3 ) - // GCC version 3 and higher.s - //#warning( "Using sn* functions." ) - #define TIXML_SNPRINTF snprintf - #define TIXML_SSCANF sscanf - #else - #define TIXML_SNPRINTF snprintf - #define TIXML_SSCANF sscanf - #endif -#endif - -class TiXmlDocument; -class TiXmlElement; -class TiXmlComment; -class TiXmlUnknown; -class TiXmlAttribute; -class TiXmlText; -class TiXmlDeclaration; -class TiXmlParsingData; - -const int TIXML_MAJOR_VERSION = 2; -const int TIXML_MINOR_VERSION = 6; -const int TIXML_PATCH_VERSION = 2; - -/* Internal structure for tracking location of items - in the XML file. -*/ -struct TiXmlCursor -{ - TiXmlCursor() { Clear(); } - void Clear() { row = col = -1; } - - int row; // 0 based. - int col; // 0 based. -}; - - -/** - Implements the interface to the "Visitor pattern" (see the Accept() method.) - If you call the Accept() method, it requires being passed a TiXmlVisitor - class to handle callbacks. For nodes that contain other nodes (Document, Element) - you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves - are simply called with Visit(). - - If you return 'true' from a Visit method, recursive parsing will continue. If you return - false, no children of this node or its sibilings will be Visited. - - All flavors of Visit methods have a default implementation that returns 'true' (continue - visiting). You need to only override methods that are interesting to you. - - Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. - - You should never change the document from a callback. - - @sa TiXmlNode::Accept() -*/ -class TiXmlVisitor -{ -public: - virtual ~TiXmlVisitor() {} - - /// Visit a document. - virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } - /// Visit a document. - virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } - - /// Visit an element. - virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } - /// Visit an element. - virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } - - /// Visit a declaration - virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } - /// Visit a text node - virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } - /// Visit a comment node - virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } - /// Visit an unknown node - virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } -}; - -// Only used by Attribute::Query functions -enum -{ - TIXML_SUCCESS, - TIXML_NO_ATTRIBUTE, - TIXML_WRONG_TYPE -}; - - -// Used by the parsing routines. -enum TiXmlEncoding -{ - TIXML_ENCODING_UNKNOWN, - TIXML_ENCODING_UTF8, - TIXML_ENCODING_LEGACY -}; - -const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; - -/** TiXmlBase is a base class for every class in TinyXml. - It does little except to establish that TinyXml classes - can be printed and provide some utility functions. - - In XML, the document and elements can contain - other elements and other types of nodes. - - @verbatim - A Document can contain: Element (container or leaf) - Comment (leaf) - Unknown (leaf) - Declaration( leaf ) - - An Element can contain: Element (container or leaf) - Text (leaf) - Attributes (not on tree) - Comment (leaf) - Unknown (leaf) - - A Decleration contains: Attributes (not on tree) - @endverbatim -*/ -class TiXmlBase -{ - friend class TiXmlNode; - friend class TiXmlElement; - friend class TiXmlDocument; - -public: - TiXmlBase() : userData(0) {} - virtual ~TiXmlBase() {} - - /** All TinyXml classes can print themselves to a filestream - or the string class (TiXmlString in non-STL mode, std::string - in STL mode.) Either or both cfile and str can be null. - - This is a formatted print, and will insert - tabs and newlines. - - (For an unformatted stream, use the << operator.) - */ - virtual void Print( FILE* cfile, int depth ) const = 0; - - /** The world does not agree on whether white space should be kept or - not. In order to make everyone happy, these global, static functions - are provided to set whether or not TinyXml will condense all white space - into a single space or not. The default is to condense. Note changing this - value is not thread safe. - */ - static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } - - /// Return the current white space setting. - static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } - - /** Return the position, in the original source file, of this node or attribute. - The row and column are 1-based. (That is the first row and first column is - 1,1). If the returns values are 0 or less, then the parser does not have - a row and column value. - - Generally, the row and column value will be set when the TiXmlDocument::Load(), - TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set - when the DOM was created from operator>>. - - The values reflect the initial load. Once the DOM is modified programmatically - (by adding or changing nodes and attributes) the new values will NOT update to - reflect changes in the document. - - There is a minor performance cost to computing the row and column. Computation - can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. - - @sa TiXmlDocument::SetTabSize() - */ - int Row() const { return location.row + 1; } - int Column() const { return location.col + 1; } ///< See Row() - - void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. - void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. - const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. - - // Table that returs, for a given lead byte, the total number of bytes - // in the UTF-8 sequence. - static const int utf8ByteTable[256]; - - virtual const char* Parse( const char* p, - TiXmlParsingData* data, - TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; - - /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, - or they will be transformed into entities! - */ - static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); - - enum - { - TIXML_NO_ERROR = 0, - TIXML_ERROR, - TIXML_ERROR_OPENING_FILE, - TIXML_ERROR_PARSING_ELEMENT, - TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, - TIXML_ERROR_READING_ELEMENT_VALUE, - TIXML_ERROR_READING_ATTRIBUTES, - TIXML_ERROR_PARSING_EMPTY, - TIXML_ERROR_READING_END_TAG, - TIXML_ERROR_PARSING_UNKNOWN, - TIXML_ERROR_PARSING_COMMENT, - TIXML_ERROR_PARSING_DECLARATION, - TIXML_ERROR_DOCUMENT_EMPTY, - TIXML_ERROR_EMBEDDED_NULL, - TIXML_ERROR_PARSING_CDATA, - TIXML_ERROR_DOCUMENT_TOP_ONLY, - - TIXML_ERROR_STRING_COUNT - }; - -protected: - - static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); - - inline static bool IsWhiteSpace( char c ) - { - return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); - } - inline static bool IsWhiteSpace( int c ) - { - if ( c < 256 ) - return IsWhiteSpace( (char) c ); - return false; // Again, only truly correct for English/Latin...but usually works. - } - - #ifdef TIXML_USE_STL - static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); - static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); - #endif - - /* Reads an XML name into the string provided. Returns - a pointer just past the last character of the name, - or 0 if the function has an error. - */ - static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); - - /* Reads text. Returns a pointer past the given end tag. - Wickedly complex options, but it keeps the (sensitive) code in one place. - */ - static const char* ReadText( const char* in, // where to start - TIXML_STRING* text, // the string read - bool ignoreWhiteSpace, // whether to keep the white space - const char* endTag, // what ends this text - bool ignoreCase, // whether to ignore case in the end tag - TiXmlEncoding encoding ); // the current encoding - - // If an entity has been found, transform it into a character. - static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); - - // Get a character, while interpreting entities. - // The length can be from 0 to 4 bytes. - inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) - { - assert( p ); - if ( encoding == TIXML_ENCODING_UTF8 ) - { - *length = utf8ByteTable[ *((const unsigned char*)p) ]; - assert( *length >= 0 && *length < 5 ); - } - else - { - *length = 1; - } - - if ( *length == 1 ) - { - if ( *p == '&' ) - return GetEntity( p, _value, length, encoding ); - *_value = *p; - return p+1; - } - else if ( *length ) - { - //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), - // and the null terminator isn't needed - for( int i=0; p[i] && i<*length; ++i ) { - _value[i] = p[i]; - } - return p + (*length); - } - else - { - // Not valid text. - return 0; - } - } - - // Return true if the next characters in the stream are any of the endTag sequences. - // Ignore case only works for english, and should only be relied on when comparing - // to English words: StringEqual( p, "version", true ) is fine. - static bool StringEqual( const char* p, - const char* endTag, - bool ignoreCase, - TiXmlEncoding encoding ); - - static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; - - TiXmlCursor location; - - /// Field containing a generic user pointer - void* userData; - - // None of these methods are reliable for any language except English. - // Good for approximation, not great for accuracy. - static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); - static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); - inline static int ToLower( int v, TiXmlEncoding encoding ) - { - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( v < 128 ) return tolower( v ); - return v; - } - else - { - return tolower( v ); - } - } - static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); - -private: - TiXmlBase( const TiXmlBase& ); // not implemented. - void operator=( const TiXmlBase& base ); // not allowed. - - struct Entity - { - const char* str; - unsigned int strLength; - char chr; - }; - enum - { - NUM_ENTITY = 5, - MAX_ENTITY_LENGTH = 6 - - }; - static Entity entity[ NUM_ENTITY ]; - static bool condenseWhiteSpace; -}; - - -/** The parent class for everything in the Document Object Model. - (Except for attributes). - Nodes have siblings, a parent, and children. A node can be - in a document, or stand on its own. The type of a TiXmlNode - can be queried, and it can be cast to its more defined type. -*/ -class TiXmlNode : public TiXmlBase -{ - friend class TiXmlDocument; - friend class TiXmlElement; - -public: - #ifdef TIXML_USE_STL - - /** An input stream operator, for every class. Tolerant of newlines and - formatting, but doesn't expect them. - */ - friend std::istream& operator >> (std::istream& in, TiXmlNode& base); - - /** An output stream operator, for every class. Note that this outputs - without any newlines or formatting, as opposed to Print(), which - includes tabs and new lines. - - The operator<< and operator>> are not completely symmetric. Writing - a node to a stream is very well defined. You'll get a nice stream - of output, without any extra whitespace or newlines. - - But reading is not as well defined. (As it always is.) If you create - a TiXmlElement (for example) and read that from an input stream, - the text needs to define an element or junk will result. This is - true of all input streams, but it's worth keeping in mind. - - A TiXmlDocument will read nodes until it reads a root element, and - all the children of that root element. - */ - friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); - - /// Appends the XML node or attribute to a std::string. - friend std::string& operator<< (std::string& out, const TiXmlNode& base ); - - #endif - - /** The types of XML nodes supported by TinyXml. (All the - unsupported types are picked up by UNKNOWN.) - */ - enum NodeType - { - TINYXML_DOCUMENT, - TINYXML_ELEMENT, - TINYXML_COMMENT, - TINYXML_UNKNOWN, - TINYXML_TEXT, - TINYXML_DECLARATION, - TINYXML_TYPECOUNT - }; - - virtual ~TiXmlNode(); - - /** The meaning of 'value' changes for the specific type of - TiXmlNode. - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - - The subclasses will wrap this function. - */ - const char *Value() const { return value.c_str (); } - - #ifdef TIXML_USE_STL - /** Return Value() as a std::string. If you only use STL, - this is more efficient than calling Value(). - Only available in STL mode. - */ - const std::string& ValueStr() const { return value; } - #endif - - const TIXML_STRING& ValueTStr() const { return value; } - - /** Changes the value of the node. Defined as: - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - */ - void SetValue(const char * _value) { value = _value;} - - #ifdef TIXML_USE_STL - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } - #endif - - /// Delete all the children of this node. Does not affect 'this'. - void Clear(); - - /// One step up the DOM. - TiXmlNode* Parent() { return parent; } - const TiXmlNode* Parent() const { return parent; } - - const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. - TiXmlNode* FirstChild() { return firstChild; } - const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. - /// The first child of this node with the matching 'value'. Will be null if none found. - TiXmlNode* FirstChild( const char * _value ) { - // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) - // call the method, cast the return back to non-const. - return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); - } - const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. - TiXmlNode* LastChild() { return lastChild; } - - const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. - TiXmlNode* LastChild( const char * _value ) { - return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. - const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. - #endif - - /** An alternate way to walk the children of a node. - One way to iterate over nodes is: - @verbatim - for( child = parent->FirstChild(); child; child = child->NextSibling() ) - @endverbatim - - IterateChildren does the same thing with the syntax: - @verbatim - child = 0; - while( child = parent->IterateChildren( child ) ) - @endverbatim - - IterateChildren takes the previous child as input and finds - the next one. If the previous child is null, it returns the - first. IterateChildren will return null when done. - */ - const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; - TiXmlNode* IterateChildren( const TiXmlNode* previous ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); - } - - /// This flavor of IterateChildren searches for children with a particular 'value' - const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; - TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. - TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. - #endif - - /** Add a new node related to this. Adds a child past the LastChild. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); - - - /** Add a new node related to this. Adds a child past the LastChild. - - NOTE: the node to be added is passed by pointer, and will be - henceforth owned (and deleted) by tinyXml. This method is efficient - and avoids an extra copy, but should be used with care as it - uses a different memory model than the other insert functions. - - @sa InsertEndChild - */ - TiXmlNode* LinkEndChild( TiXmlNode* addThis ); - - /** Add a new node related to this. Adds a child before the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); - - /** Add a new node related to this. Adds a child after the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); - - /** Replace a child of this node. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); - - /// Delete a child of this node. - bool RemoveChild( TiXmlNode* removeThis ); - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling() const { return prev; } - TiXmlNode* PreviousSibling() { return prev; } - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling( const char * ) const; - TiXmlNode* PreviousSibling( const char *_prev ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. - const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. - #endif - - /// Navigate to a sibling node. - const TiXmlNode* NextSibling() const { return next; } - TiXmlNode* NextSibling() { return next; } - - /// Navigate to a sibling node with the given 'value'. - const TiXmlNode* NextSibling( const char * ) const; - TiXmlNode* NextSibling( const char* _next ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement() const; - TiXmlElement* NextSiblingElement() { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement( const char * ) const; - TiXmlElement* NextSiblingElement( const char *_next ) { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. - TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. - #endif - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement() const; - TiXmlElement* FirstChildElement() { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); - } - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement( const char * _value ) const; - TiXmlElement* FirstChildElement( const char * _value ) { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. - TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. - #endif - - /** Query the type (as an enumerated value, above) of this node. - The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, - TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. - */ - int Type() const { return type; } - - /** Return a pointer to the Document this node lives in. - Returns null if not in a document. - */ - const TiXmlDocument* GetDocument() const; - TiXmlDocument* GetDocument() { - return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); - } - - /// Returns true if this node has no children. - bool NoChildren() const { return !firstChild; } - - virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - - virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - - /** Create an exact duplicate of this node and return it. The memory must be deleted - by the caller. - */ - virtual TiXmlNode* Clone() const = 0; - - /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the - XML tree will be conditionally visited and the host will be called back - via the TiXmlVisitor interface. - - This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse - the XML for the callbacks, so the performance of TinyXML is unchanged by using this - interface versus any other.) - - The interface has been based on ideas from: - - - http://www.saxproject.org/ - - http://c2.com/cgi/wiki?HierarchicalVisitorPattern - - Which are both good references for "visiting". - - An example of using Accept(): - @verbatim - TiXmlPrinter printer; - tinyxmlDoc.Accept( &printer ); - const char* xmlcstr = printer.CStr(); - @endverbatim - */ - virtual bool Accept( TiXmlVisitor* visitor ) const = 0; - -protected: - TiXmlNode( NodeType _type ); - - // Copy to the allocated object. Shared functionality between Clone, Copy constructor, - // and the assignment operator. - void CopyTo( TiXmlNode* target ) const; - - #ifdef TIXML_USE_STL - // The real work of the input operator. - virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; - #endif - - // Figure out what is at *p, and parse it. Returns null if it is not an xml node. - TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); - - TiXmlNode* parent; - NodeType type; - - TiXmlNode* firstChild; - TiXmlNode* lastChild; - - TIXML_STRING value; - - TiXmlNode* prev; - TiXmlNode* next; - -private: - TiXmlNode( const TiXmlNode& ); // not implemented. - void operator=( const TiXmlNode& base ); // not allowed. -}; - - -/** An attribute is a name-value pair. Elements have an arbitrary - number of attributes, each with a unique name. - - @note The attributes are not TiXmlNodes, since they are not - part of the tinyXML document object model. There are other - suggested ways to look at this problem. -*/ -class TiXmlAttribute : public TiXmlBase -{ - friend class TiXmlAttributeSet; - -public: - /// Construct an empty attribute. - TiXmlAttribute() : TiXmlBase() - { - document = 0; - prev = next = 0; - } - - #ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlAttribute( const std::string& _name, const std::string& _value ) - { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - #endif - - /// Construct an attribute with a name and value. - TiXmlAttribute( const char * _name, const char * _value ) - { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - - const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. - const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. - #ifdef TIXML_USE_STL - const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. - #endif - int IntValue() const; ///< Return the value of this attribute, converted to an integer. - double DoubleValue() const; ///< Return the value of this attribute, converted to a double. - - // Get the tinyxml string representation - const TIXML_STRING& NameTStr() const { return name; } - - /** QueryIntValue examines the value string. It is an alternative to the - IntValue() method with richer error checking. - If the value is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. - - A specialized but useful call. Note that for success it returns 0, - which is the opposite of almost all other TinyXml calls. - */ - int QueryIntValue( int* _value ) const; - /// QueryDoubleValue examines the value string. See QueryIntValue(). - int QueryDoubleValue( double* _value ) const; - - void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. - void SetValue( const char* _value ) { value = _value; } ///< Set the value. - - void SetIntValue( int _value ); ///< Set the value from an integer. - void SetDoubleValue( double _value ); ///< Set the value from a double. - - #ifdef TIXML_USE_STL - /// STL std::string form. - void SetName( const std::string& _name ) { name = _name; } - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } - #endif - - /// Get the next sibling attribute in the DOM. Returns null at end. - const TiXmlAttribute* Next() const; - TiXmlAttribute* Next() { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); - } - - /// Get the previous sibling attribute in the DOM. Returns null at beginning. - const TiXmlAttribute* Previous() const; - TiXmlAttribute* Previous() { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); - } - - bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } - bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } - bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } - - /* Attribute parsing starts: first letter of the name - returns: the next char after the value end quote - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - // Prints this Attribute to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const { - Print( cfile, depth, 0 ); - } - void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; - - // [internal use] - // Set the document pointer so the attribute can report errors. - void SetDocument( TiXmlDocument* doc ) { document = doc; } - -private: - TiXmlAttribute( const TiXmlAttribute& ); // not implemented. - void operator=( const TiXmlAttribute& base ); // not allowed. - - TiXmlDocument* document; // A pointer back to a document, for error reporting. - TIXML_STRING name; - TIXML_STRING value; - TiXmlAttribute* prev; - TiXmlAttribute* next; -}; - - -/* A class used to manage a group of attributes. - It is only used internally, both by the ELEMENT and the DECLARATION. - - The set can be changed transparent to the Element and Declaration - classes that use it, but NOT transparent to the Attribute - which has to implement a next() and previous() method. Which makes - it a bit problematic and prevents the use of STL. - - This version is implemented with circular lists because: - - I like circular lists - - it demonstrates some independence from the (typical) doubly linked list. -*/ -class TiXmlAttributeSet -{ -public: - TiXmlAttributeSet(); - ~TiXmlAttributeSet(); - - void Add( TiXmlAttribute* attribute ); - void Remove( TiXmlAttribute* attribute ); - - const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } - TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } - const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - - TiXmlAttribute* Find( const char* _name ) const; - TiXmlAttribute* FindOrCreate( const char* _name ); - -# ifdef TIXML_USE_STL - TiXmlAttribute* Find( const std::string& _name ) const; - TiXmlAttribute* FindOrCreate( const std::string& _name ); -# endif - - -private: - //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), - //*ME: this class must be also use a hidden/disabled copy-constructor !!! - TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed - void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) - - TiXmlAttribute sentinel; -}; - - -/** The element is a container class. It has a value, the element name, - and can contain other elements, text, comments, and unknowns. - Elements also contain an arbitrary number of attributes. -*/ -class TiXmlElement : public TiXmlNode -{ -public: - /// Construct an element. - TiXmlElement (const char * in_value); - - #ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlElement( const std::string& _value ); - #endif - - TiXmlElement( const TiXmlElement& ); - - TiXmlElement& operator=( const TiXmlElement& base ); - - virtual ~TiXmlElement(); - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - */ - const char* Attribute( const char* name ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an integer, - the integer value will be put in the return 'i', if 'i' - is non-null. - */ - const char* Attribute( const char* name, int* i ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an double, - the double value will be put in the return 'd', if 'd' - is non-null. - */ - const char* Attribute( const char* name, double* d ) const; - - /** QueryIntAttribute examines the attribute - it is an alternative to the - Attribute() method with richer error checking. - If the attribute is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. If the attribute - does not exist, then TIXML_NO_ATTRIBUTE is returned. - */ - int QueryIntAttribute( const char* name, int* _value ) const; - /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). - int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; - /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). - Note that '1', 'true', or 'yes' are considered true, while '0', 'false' - and 'no' are considered false. - */ - int QueryBoolAttribute( const char* name, bool* _value ) const; - /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). - int QueryDoubleAttribute( const char* name, double* _value ) const; - /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). - int QueryFloatAttribute( const char* name, float* _value ) const { - double d; - int result = QueryDoubleAttribute( name, &d ); - if ( result == TIXML_SUCCESS ) { - *_value = (float)d; - } - return result; - } - - #ifdef TIXML_USE_STL - /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). - int QueryStringAttribute( const char* name, std::string* _value ) const { - const char* cstr = Attribute( name ); - if ( cstr ) { - *_value = std::string( cstr ); - return TIXML_SUCCESS; - } - return TIXML_NO_ATTRIBUTE; - } - - /** Template form of the attribute query which will try to read the - attribute into the specified type. Very easy, very powerful, but - be careful to make sure to call this with the correct type. - - NOTE: This method doesn't work correctly for 'string' types that contain spaces. - - @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE - */ - template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const - { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - std::stringstream sstream( node->ValueStr() ); - sstream >> *outValue; - if ( !sstream.fail() ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; - } - - int QueryValueAttribute( const std::string& name, std::string* outValue ) const - { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - *outValue = node->ValueStr(); - return TIXML_SUCCESS; - } - #endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute( const char* name, const char * _value ); - - #ifdef TIXML_USE_STL - const std::string* Attribute( const std::string& name ) const; - const std::string* Attribute( const std::string& name, int* i ) const; - const std::string* Attribute( const std::string& name, double* d ) const; - int QueryIntAttribute( const std::string& name, int* _value ) const; - int QueryDoubleAttribute( const std::string& name, double* _value ) const; - - /// STL std::string form. - void SetAttribute( const std::string& name, const std::string& _value ); - ///< STL std::string form. - void SetAttribute( const std::string& name, int _value ); - ///< STL std::string form. - void SetDoubleAttribute( const std::string& name, double value ); - #endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute( const char * name, int value ); - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetDoubleAttribute( const char * name, double value ); - - /** Deletes an attribute with the given name. - */ - void RemoveAttribute( const char * name ); - #ifdef TIXML_USE_STL - void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. - #endif - - const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. - TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } - const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. - TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } - - /** Convenience function for easy access to the text inside an element. Although easy - and concise, GetText() is limited compared to getting the TiXmlText child - and accessing it directly. - - If the first child of 'this' is a TiXmlText, the GetText() - returns the character string of the Text node, else null is returned. - - This is a convenient method for getting the text of simple contained text: - @verbatim - This is text - const char* str = fooElement->GetText(); - @endverbatim - - 'str' will be a pointer to "This is text". - - Note that this function can be misleading. If the element foo was created from - this XML: - @verbatim - This is text - @endverbatim - - then the value of str would be null. The first child node isn't a text node, it is - another element. From this XML: - @verbatim - This is text - @endverbatim - GetText() will return "This is ". - - WARNING: GetText() accesses a child node - don't become confused with the - similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are - safe type casts on the referenced node. - */ - const char* GetText() const; - - /// Creates a new Element and returns it - the returned element is a copy. - virtual TiXmlNode* Clone() const; - // Print the Element to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /* Attribtue parsing starts: next char past '<' - returns: next char past '>' - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - - void CopyTo( TiXmlElement* target ) const; - void ClearThis(); // like clear, but initializes 'this' object as well - - // Used to be public [internal use] - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - /* [internal use] - Reads the "value" of the element -- another element, or text. - This should terminate with the current end tag. - */ - const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); - -private: - TiXmlAttributeSet attributeSet; -}; - - -/** An XML comment. -*/ -class TiXmlComment : public TiXmlNode -{ -public: - /// Constructs an empty comment. - TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} - /// Construct a comment from text. - TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { - SetValue( _value ); - } - TiXmlComment( const TiXmlComment& ); - TiXmlComment& operator=( const TiXmlComment& base ); - - virtual ~TiXmlComment() {} - - /// Returns a copy of this Comment. - virtual TiXmlNode* Clone() const; - // Write this Comment to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /* Attribtue parsing starts: at the ! of the !-- - returns: next char past '>' - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - void CopyTo( TiXmlComment* target ) const; - - // used to be public - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif -// virtual void StreamOut( TIXML_OSTREAM * out ) const; - -private: - -}; - - -/** XML text. A text node can have 2 ways to output the next. "normal" output - and CDATA. It will default to the mode it was parsed from the XML file and - you generally want to leave it alone, but you can change the output mode with - SetCDATA() and query it with CDATA(). -*/ -class TiXmlText : public TiXmlNode -{ - friend class TiXmlElement; -public: - /** Constructor for text element. By default, it is treated as - normal, encoded text. If you want it be output as a CDATA text - element, set the parameter _cdata to 'true' - */ - TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) - { - SetValue( initValue ); - cdata = false; - } - virtual ~TiXmlText() {} - - #ifdef TIXML_USE_STL - /// Constructor. - TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) - { - SetValue( initValue ); - cdata = false; - } - #endif - - TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } - TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } - - // Write this text object to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /// Queries whether this represents text using a CDATA section. - bool CDATA() const { return cdata; } - /// Turns on or off a CDATA representation of text. - void SetCDATA( bool _cdata ) { cdata = _cdata; } - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected : - /// [internal use] Creates a new Element and returns it. - virtual TiXmlNode* Clone() const; - void CopyTo( TiXmlText* target ) const; - - bool Blank() const; // returns true if all white space and new lines - // [internal use] - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - bool cdata; // true if this should be input and output as a CDATA style text element -}; - - -/** In correct XML the declaration is the first entry in the file. - @verbatim - - @endverbatim - - TinyXml will happily read or write files without a declaration, - however. There are 3 possible attributes to the declaration: - version, encoding, and standalone. - - Note: In this version of the code, the attributes are - handled as special cases, not generic attributes, simply - because there can only be at most 3 and they are always the same. -*/ -class TiXmlDeclaration : public TiXmlNode -{ -public: - /// Construct an empty declaration. - TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} - -#ifdef TIXML_USE_STL - /// Constructor. - TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ); -#endif - - /// Construct. - TiXmlDeclaration( const char* _version, - const char* _encoding, - const char* _standalone ); - - TiXmlDeclaration( const TiXmlDeclaration& copy ); - TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); - - virtual ~TiXmlDeclaration() {} - - /// Version. Will return an empty string if none was found. - const char *Version() const { return version.c_str (); } - /// Encoding. Will return an empty string if none was found. - const char *Encoding() const { return encoding.c_str (); } - /// Is this a standalone document? - const char *Standalone() const { return standalone.c_str (); } - - /// Creates a copy of this Declaration and returns it. - virtual TiXmlNode* Clone() const; - // Print this declaration to a FILE stream. - virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; - virtual void Print( FILE* cfile, int depth ) const { - Print( cfile, depth, 0 ); - } - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - void CopyTo( TiXmlDeclaration* target ) const; - // used to be public - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - - TIXML_STRING version; - TIXML_STRING encoding; - TIXML_STRING standalone; -}; - - -/** Any tag that tinyXml doesn't recognize is saved as an - unknown. It is a tag of text, but should not be modified. - It will be written back to the XML, unchanged, when the file - is saved. - - DTD tags get thrown into TiXmlUnknowns. -*/ -class TiXmlUnknown : public TiXmlNode -{ -public: - TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} - virtual ~TiXmlUnknown() {} - - TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } - TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } - - /// Creates a copy of this Unknown and returns it. - virtual TiXmlNode* Clone() const; - // Print this Unknown to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected: - void CopyTo( TiXmlUnknown* target ) const; - - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - -}; - - -/** Always the top level node. A document binds together all the - XML pieces. It can be saved, loaded, and printed to the screen. - The 'value' of a document node is the xml file name. -*/ -class TiXmlDocument : public TiXmlNode -{ -public: - /// Create an empty document, that has no name. - TiXmlDocument(); - /// Create a document with a name. The name of the document is also the filename of the xml. - TiXmlDocument( const char * documentName ); - - #ifdef TIXML_USE_STL - /// Constructor. - TiXmlDocument( const std::string& documentName ); - #endif - - TiXmlDocument( const TiXmlDocument& copy ); - TiXmlDocument& operator=( const TiXmlDocument& copy ); - - virtual ~TiXmlDocument() {} - - /** Load a file using the current document value. - Returns true if successful. Will delete any existing - document data before loading. - */ - bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the current document value. Returns true if successful. - bool SaveFile() const; - /// Load a file using the given filename. Returns true if successful. - bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the given filename. Returns true if successful. - bool SaveFile( const char * filename ) const; - /** Load a file using the given FILE*. Returns true if successful. Note that this method - doesn't stream - the entire object pointed at by the FILE* - will be interpreted as an XML file. TinyXML doesn't stream in XML from the current - file location. Streaming may be added in the future. - */ - bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the given FILE*. Returns true if successful. - bool SaveFile( FILE* ) const; - - #ifdef TIXML_USE_STL - bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. - { - return LoadFile( filename.c_str(), encoding ); - } - bool SaveFile( const std::string& filename ) const ///< STL std::string version. - { - return SaveFile( filename.c_str() ); - } - #endif - - /** Parse the given null terminated block of xml data. Passing in an encoding to this - method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml - to use that encoding, regardless of what TinyXml might otherwise try to detect. - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - - /** Get the root element -- the only top level element -- of the document. - In well formed XML, there should only be one. TinyXml is tolerant of - multiple elements at the document level. - */ - const TiXmlElement* RootElement() const { return FirstChildElement(); } - TiXmlElement* RootElement() { return FirstChildElement(); } - - /** If an error occurs, Error will be set to true. Also, - - The ErrorId() will contain the integer identifier of the error (not generally useful) - - The ErrorDesc() method will return the name of the error. (very useful) - - The ErrorRow() and ErrorCol() will return the location of the error (if known) - */ - bool Error() const { return error; } - - /// Contains a textual (english) description of the error if one occurs. - const char * ErrorDesc() const { return errorDesc.c_str (); } - - /** Generally, you probably want the error string ( ErrorDesc() ). But if you - prefer the ErrorId, this function will fetch it. - */ - int ErrorId() const { return errorId; } - - /** Returns the location (if known) of the error. The first column is column 1, - and the first row is row 1. A value of 0 means the row and column wasn't applicable - (memory errors, for example, have no row/column) or the parser lost the error. (An - error in the error reporting, in that case.) - - @sa SetTabSize, Row, Column - */ - int ErrorRow() const { return errorLocation.row+1; } - int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() - - /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) - to report the correct values for row and column. It does not change the output - or input in any way. - - By calling this method, with a tab size - greater than 0, the row and column of each node and attribute is stored - when the file is loaded. Very useful for tracking the DOM back in to - the source file. - - The tab size is required for calculating the location of nodes. If not - set, the default of 4 is used. The tabsize is set per document. Setting - the tabsize to 0 disables row/column tracking. - - Note that row and column tracking is not supported when using operator>>. - - The tab size needs to be enabled before the parse or load. Correct usage: - @verbatim - TiXmlDocument doc; - doc.SetTabSize( 8 ); - doc.Load( "myfile.xml" ); - @endverbatim - - @sa Row, Column - */ - void SetTabSize( int _tabsize ) { tabsize = _tabsize; } - - int TabSize() const { return tabsize; } - - /** If you have handled the error, it can be reset with this call. The error - state is automatically cleared if you Parse a new XML block. - */ - void ClearError() { error = false; - errorId = 0; - errorDesc = ""; - errorLocation.row = errorLocation.col = 0; - //errorLocation.last = 0; - } - - /** Write the document to standard out using formatted printing ("pretty print"). */ - void Print() const { Print( stdout, 0 ); } - - /* Write the document to a string using formatted printing ("pretty print"). This - will allocate a character array (new char[]) and return it as a pointer. The - calling code pust call delete[] on the return char* to avoid a memory leak. - */ - //char* PrintToMemory() const; - - /// Print this Document to a FILE stream. - virtual void Print( FILE* cfile, int depth = 0 ) const; - // [internal use] - void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); - - virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected : - // [internal use] - virtual TiXmlNode* Clone() const; - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - void CopyTo( TiXmlDocument* target ) const; - - bool error; - int errorId; - TIXML_STRING errorDesc; - int tabsize; - TiXmlCursor errorLocation; - bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. -}; - - -/** - A TiXmlHandle is a class that wraps a node pointer with null checks; this is - an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml - DOM structure. It is a separate utility class. - - Take an example: - @verbatim - - - - - - - @endverbatim - - Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very - easy to write a *lot* of code that looks like: - - @verbatim - TiXmlElement* root = document.FirstChildElement( "Document" ); - if ( root ) - { - TiXmlElement* element = root->FirstChildElement( "Element" ); - if ( element ) - { - TiXmlElement* child = element->FirstChildElement( "Child" ); - if ( child ) - { - TiXmlElement* child2 = child->NextSiblingElement( "Child" ); - if ( child2 ) - { - // Finally do something useful. - @endverbatim - - And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity - of such code. A TiXmlHandle checks for null pointers so it is perfectly safe - and correct to use: - - @verbatim - TiXmlHandle docHandle( &document ); - TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); - if ( child2 ) - { - // do something useful - @endverbatim - - Which is MUCH more concise and useful. - - It is also safe to copy handles - internally they are nothing more than node pointers. - @verbatim - TiXmlHandle handleCopy = handle; - @endverbatim - - What they should not be used for is iteration: - - @verbatim - int i=0; - while ( true ) - { - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); - if ( !child ) - break; - // do something - ++i; - } - @endverbatim - - It seems reasonable, but it is in fact two embedded while loops. The Child method is - a linear walk to find the element, so this code would iterate much more than it needs - to. Instead, prefer: - - @verbatim - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); - - for( child; child; child=child->NextSiblingElement() ) - { - // do something - } - @endverbatim -*/ -class TiXmlHandle -{ -public: - /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. - TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } - /// Copy constructor - TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } - TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } - - /// Return a handle to the first child node. - TiXmlHandle FirstChild() const; - /// Return a handle to the first child node with the given name. - TiXmlHandle FirstChild( const char * value ) const; - /// Return a handle to the first child element. - TiXmlHandle FirstChildElement() const; - /// Return a handle to the first child element with the given name. - TiXmlHandle FirstChildElement( const char * value ) const; - - /** Return a handle to the "index" child with the given name. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child( const char* value, int index ) const; - /** Return a handle to the "index" child. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child( int index ) const; - /** Return a handle to the "index" child element with the given name. - The first child element is 0, the second 1, etc. Note that only TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement( const char* value, int index ) const; - /** Return a handle to the "index" child element. - The first child element is 0, the second 1, etc. Note that only TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement( int index ) const; - - #ifdef TIXML_USE_STL - TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } - TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } - - TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } - TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } - #endif - - /** Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* ToNode() const { return node; } - /** Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } - /** Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } - /** Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } - - /** @deprecated use ToNode. - Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* Node() const { return ToNode(); } - /** @deprecated use ToElement. - Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* Element() const { return ToElement(); } - /** @deprecated use ToText() - Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* Text() const { return ToText(); } - /** @deprecated use ToUnknown() - Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* Unknown() const { return ToUnknown(); } - -private: - TiXmlNode* node; -}; - - -/** Print to memory functionality. The TiXmlPrinter is useful when you need to: - - -# Print to memory (especially in non-STL mode) - -# Control formatting (line endings, etc.) - - When constructed, the TiXmlPrinter is in its default "pretty printing" mode. - Before calling Accept() you can call methods to control the printing - of the XML document. After TiXmlNode::Accept() is called, the printed document can - be accessed via the CStr(), Str(), and Size() methods. - - TiXmlPrinter uses the Visitor API. - @verbatim - TiXmlPrinter printer; - printer.SetIndent( "\t" ); - - doc.Accept( &printer ); - fprintf( stdout, "%s", printer.CStr() ); - @endverbatim -*/ -class TiXmlPrinter : public TiXmlVisitor -{ -public: - TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), - buffer(), indent( " " ), lineBreak( "\n" ) {} - - virtual bool VisitEnter( const TiXmlDocument& doc ); - virtual bool VisitExit( const TiXmlDocument& doc ); - - virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); - virtual bool VisitExit( const TiXmlElement& element ); - - virtual bool Visit( const TiXmlDeclaration& declaration ); - virtual bool Visit( const TiXmlText& text ); - virtual bool Visit( const TiXmlComment& comment ); - virtual bool Visit( const TiXmlUnknown& unknown ); - - /** Set the indent characters for printing. By default 4 spaces - but tab (\t) is also useful, or null/empty string for no indentation. - */ - void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } - /// Query the indention string. - const char* Indent() { return indent.c_str(); } - /** Set the line breaking string. By default set to newline (\n). - Some operating systems prefer other characters, or can be - set to the null/empty string for no indenation. - */ - void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } - /// Query the current line breaking string. - const char* LineBreak() { return lineBreak.c_str(); } - - /** Switch over to "stream printing" which is the most dense formatting without - linebreaks. Common when the XML is needed for network transmission. - */ - void SetStreamPrinting() { indent = ""; - lineBreak = ""; - } - /// Return the result. - const char* CStr() { return buffer.c_str(); } - /// Return the length of the result string. - size_t Size() { return buffer.size(); } - - #ifdef TIXML_USE_STL - /// Return the result. - const std::string& Str() { return buffer; } - #endif - -private: - void DoIndent() { - for( int i=0; i -#include - -#include "tinyxml.h" - -//#define DEBUG_PARSER -#if defined( DEBUG_PARSER ) -# if defined( DEBUG ) && defined( _MSC_VER ) -# include -# define TIXML_LOG OutputDebugString -# else -# define TIXML_LOG printf -# endif -#endif - -// Note tha "PutString" hardcodes the same list. This -// is less flexible than it appears. Changing the entries -// or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = -{ - { "&", 5, '&' }, - { "<", 4, '<' }, - { ">", 4, '>' }, - { """, 6, '\"' }, - { "'", 6, '\'' } -}; - -// Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html -// Including the basic of this table, which determines the #bytes in the -// sequence from the lead byte. 1 placed for invalid sequences -- -// although the result will be junk, pass it through as much as possible. -// Beware of the non-characters in UTF-8: -// ef bb bf (Microsoft "lead bytes") -// ef bf be -// ef bf bf - -const unsigned char TIXML_UTF_LEAD_0 = 0xefU; -const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; -const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - -const int TiXmlBase::utf8ByteTable[256] = -{ - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 - 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte - 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid -}; - - -void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) -{ - const unsigned long BYTE_MASK = 0xBF; - const unsigned long BYTE_MARK = 0x80; - const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - if (input < 0x80) - *length = 1; - else if ( input < 0x800 ) - *length = 2; - else if ( input < 0x10000 ) - *length = 3; - else if ( input < 0x200000 ) - *length = 4; - else - { *length = 0; return; } // This code won't covert this correctly anyway. - - output += *length; - - // Scary scary fall throughs. - switch (*length) - { - case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 1: - --output; - *output = (char)(input | FIRST_BYTE_MARK[*length]); - } -} - - -/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) -{ - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - -// if ( encoding == TIXML_ENCODING_UTF8 ) -// { - if ( anyByte < 127 ) - return isalpha( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. -// } -// else -// { -// return isalpha( anyByte ); -// } -} - - -/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) -{ - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - -// if ( encoding == TIXML_ENCODING_UTF8 ) -// { - if ( anyByte < 127 ) - return isalnum( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. -// } -// else -// { -// return isalnum( anyByte ); -// } -} - - -class TiXmlParsingData -{ - friend class TiXmlDocument; - public: - void Stamp( const char* now, TiXmlEncoding encoding ); - - const TiXmlCursor& Cursor() const { return cursor; } - - private: - // Only used by the document! - TiXmlParsingData( const char* start, int _tabsize, int row, int col ) - { - assert( start ); - stamp = start; - tabsize = _tabsize; - cursor.row = row; - cursor.col = col; - } - - TiXmlCursor cursor; - const char* stamp; - int tabsize; -}; - - -void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) -{ - assert( now ); - - // Do nothing if the tabsize is 0. - if ( tabsize < 1 ) - { - return; - } - - // Get the current row, column. - int row = cursor.row; - int col = cursor.col; - const char* p = stamp; - assert( p ); - - while ( p < now ) - { - // Treat p as unsigned, so we have a happy compiler. - const unsigned char* pU = (const unsigned char*)p; - - // Code contributed by Fletcher Dunn: (modified by lee) - switch (*pU) { - case 0: - // We *should* never get here, but in case we do, don't - // advance past the terminating null character, ever - return; - - case '\r': - // bump down to the next line - ++row; - col = 0; - // Eat the character - ++p; - - // Check for \r\n sequence, and treat this as a single character - if (*p == '\n') { - ++p; - } - break; - - case '\n': - // bump down to the next line - ++row; - col = 0; - - // Eat the character - ++p; - - // Check for \n\r sequence, and treat this as a single - // character. (Yes, this bizarre thing does occur still - // on some arcane platforms...) - if (*p == '\r') { - ++p; - } - break; - - case '\t': - // Eat the character - ++p; - - // Skip to next tab stop - col = (col / tabsize + 1) * tabsize; - break; - - case TIXML_UTF_LEAD_0: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( *(p+1) && *(p+2) ) - { - // In these cases, don't advance the column. These are - // 0-width spaces. - if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) - p += 3; - else - { p +=3; ++col; } // A normal character. - } - } - else - { - ++p; - ++col; - } - break; - - default: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // Eat the 1 to 4 byte utf8 character. - int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; - if ( step == 0 ) - step = 1; // Error case from bad encoding, but handle gracefully. - p += step; - - // Just advance one column, of course. - ++col; - } - else - { - ++p; - ++col; - } - break; - } - } - cursor.row = row; - cursor.col = col; - assert( cursor.row >= -1 ); - assert( cursor.col >= -1 ); - stamp = p; - assert( stamp ); -} - - -const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) -{ - if ( !p || !*p ) - { - return 0; - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - while ( *p ) - { - const unsigned char* pU = (const unsigned char*)p; - - // Skip the stupid Microsoft UTF-8 Byte order marks - if ( *(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==TIXML_UTF_LEAD_1 - && *(pU+2)==TIXML_UTF_LEAD_2 ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbeU ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbfU ) - { - p += 3; - continue; - } - - if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. - ++p; - else - break; - } - } - else - { - while ( *p && IsWhiteSpace( *p ) ) - ++p; - } - - return p; -} - -#ifdef TIXML_USE_STL -/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) -{ - for( ;; ) - { - if ( !in->good() ) return false; - - int c = in->peek(); - // At this scope, we can't get to a document. So fail silently. - if ( !IsWhiteSpace( c ) || c <= 0 ) - return true; - - *tag += (char) in->get(); - } -} - -/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) -{ - //assert( character > 0 && character < 128 ); // else it won't work in utf-8 - while ( in->good() ) - { - int c = in->peek(); - if ( c == character ) - return true; - if ( c <= 0 ) // Silent failure: can't get document at this scope - return false; - - in->get(); - *tag += (char) c; - } - return false; -} -#endif - -// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The -// "assign" optimization removes over 10% of the execution time. -// -const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) -{ - // Oddly, not supported on some comilers, - //name->clear(); - // So use this: - *name = ""; - assert( p ); - - // Names start with letters or underscores. - // Of course, in unicode, tinyxml has no idea what a letter *is*. The - // algorithm is generous. - // - // After that, they can be letters, underscores, numbers, - // hyphens, or colons. (Colons are valid ony for namespaces, - // but tinyxml can't tell namespaces from names.) - if ( p && *p - && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) - { - const char* start = p; - while( p && *p - && ( IsAlphaNum( (unsigned char ) *p, encoding ) - || *p == '_' - || *p == '-' - || *p == '.' - || *p == ':' ) ) - { - //(*name) += *p; // expensive - ++p; - } - if ( p-start > 0 ) { - name->assign( start, p-start ); - } - return p; - } - return 0; -} - -const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) -{ - // Presume an entity, and pull it out. - TIXML_STRING ent; - int i; - *length = 0; - - if ( *(p+1) && *(p+1) == '#' && *(p+2) ) - { - unsigned long ucs = 0; - ptrdiff_t delta = 0; - unsigned mult = 1; - - if ( *(p+2) == 'x' ) - { - // Hexadecimal. - if ( !*(p+3) ) return 0; - - const char* q = p+3; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != 'x' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else if ( *q >= 'a' && *q <= 'f' ) - ucs += mult * (*q - 'a' + 10); - else if ( *q >= 'A' && *q <= 'F' ) - ucs += mult * (*q - 'A' + 10 ); - else - return 0; - mult *= 16; - --q; - } - } - else - { - // Decimal. - if ( !*(p+2) ) return 0; - - const char* q = p+2; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != '#' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else - return 0; - mult *= 10; - --q; - } - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // convert the UCS to UTF-8 - ConvertUTF32ToUTF8( ucs, value, length ); - } - else - { - *value = (char)ucs; - *length = 1; - } - return p + delta + 1; - } - - // Now try to match it. - for( i=0; iappend( cArr, len ); - } - } - else - { - bool whitespace = false; - - // Remove leading white space: - p = SkipWhiteSpace( p, encoding ); - while ( p && *p - && !StringEqual( p, endTag, caseInsensitive, encoding ) ) - { - if ( *p == '\r' || *p == '\n' ) - { - whitespace = true; - ++p; - } - else if ( IsWhiteSpace( *p ) ) - { - whitespace = true; - ++p; - } - else - { - // If we've found whitespace, add it before the - // new character. Any whitespace just becomes a space. - if ( whitespace ) - { - (*text) += ' '; - whitespace = false; - } - int len; - char cArr[4] = { 0, 0, 0, 0 }; - p = GetChar( p, cArr, &len, encoding ); - if ( len == 1 ) - (*text) += cArr[0]; // more efficient - else - text->append( cArr, len ); - } - } - } - if ( p && *p ) - p += strlen( endTag ); - return ( p && *p ) ? p : 0; -} - -#ifdef TIXML_USE_STL - -void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - // The basic issue with a document is that we don't know what we're - // streaming. Read something presumed to be a tag (and hope), then - // identify it, and call the appropriate stream method on the tag. - // - // This "pre-streaming" will never read the closing ">" so the - // sub-tag can orient itself. - - if ( !StreamTo( in, '<', tag ) ) - { - SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - while ( in->good() ) - { - int tagIndex = (int) tag->length(); - while ( in->good() && in->peek() != '>' ) - { - int c = in->get(); - if ( c <= 0 ) - { - SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - break; - } - (*tag) += (char) c; - } - - if ( in->good() ) - { - // We now have something we presume to be a node of - // some sort. Identify it, and call the node to - // continue streaming. - TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); - - if ( node ) - { - node->StreamIn( in, tag ); - bool isElement = node->ToElement() != 0; - delete node; - node = 0; - - // If this is the root element, we're done. Parsing will be - // done by the >> operator. - if ( isElement ) - { - return; - } - } - else - { - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - } - } - // We should have returned sooner. - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); -} - -#endif - -const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) -{ - ClearError(); - - // Parse away, at the document level. Since a document - // contains nothing but other tags, most of what happens - // here is skipping white space. - if ( !p || !*p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - // Note that, for a document, this needs to come - // before the while space skip, so that parsing - // starts from the pointer we are given. - location.Clear(); - if ( prevData ) - { - location.row = prevData->cursor.row; - location.col = prevData->cursor.col; - } - else - { - location.row = 0; - location.col = 0; - } - TiXmlParsingData data( p, TabSize(), location.row, location.col ); - location = data.Cursor(); - - if ( encoding == TIXML_ENCODING_UNKNOWN ) - { - // Check for the Microsoft UTF-8 lead bytes. - const unsigned char* pU = (const unsigned char*)p; - if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 - && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 - && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) - { - encoding = TIXML_ENCODING_UTF8; - useMicrosoftBOM = true; - } - } - - p = SkipWhiteSpace( p, encoding ); - if ( !p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - while ( p && *p ) - { - TiXmlNode* node = Identify( p, encoding ); - if ( node ) - { - p = node->Parse( p, &data, encoding ); - LinkEndChild( node ); - } - else - { - break; - } - - // Did we get encoding info? - if ( encoding == TIXML_ENCODING_UNKNOWN - && node->ToDeclaration() ) - { - TiXmlDeclaration* dec = node->ToDeclaration(); - const char* enc = dec->Encoding(); - assert( enc ); - - if ( *enc == 0 ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice - else - encoding = TIXML_ENCODING_LEGACY; - } - - p = SkipWhiteSpace( p, encoding ); - } - - // Was this empty? - if ( !firstChild ) { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); - return 0; - } - - // All is well. - return p; -} - -void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - // The first error in a chain is more accurate - don't set again! - if ( error ) - return; - - assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); - error = true; - errorId = err; - errorDesc = errorString[ errorId ]; - - errorLocation.Clear(); - if ( pError && data ) - { - data->Stamp( pError, encoding ); - errorLocation = data->Cursor(); - } -} - - -TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) -{ - TiXmlNode* returnNode = 0; - - p = SkipWhiteSpace( p, encoding ); - if( !p || !*p || *p != '<' ) - { - return 0; - } - - p = SkipWhiteSpace( p, encoding ); - - if ( !p || !*p ) - { - return 0; - } - - // What is this thing? - // - Elements start with a letter or underscore, but xml is reserved. - // - Comments: "; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - if ( document ) - document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // [ 1475201 ] TinyXML parses entities in comments - // Oops - ReadText doesn't work, because we don't want to parse the entities. - // p = ReadText( p, &value, false, endTag, false, encoding ); - // - // from the XML spec: - /* - [Definition: Comments may appear anywhere in a document outside other markup; in addition, - they may appear within the document type declaration at places allowed by the grammar. - They are not part of the document's character data; an XML processor MAY, but need not, - make it possible for an application to retrieve the text of comments. For compatibility, - the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity - references MUST NOT be recognized within comments. - - An example of a comment: - - - */ - - value = ""; - // Keep all the white space. - while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) - { - value.append( p, 1 ); - ++p; - } - if ( p && *p ) - p += strlen( endTag ); - - return p; -} - - -const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) return 0; - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - // Read the name, the '=' and the value. - const char* pErr = p; - p = ReadName( p, &name, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); - return 0; - } - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p || *p != '=' ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - ++p; // skip '=' - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - const char* end; - const char SINGLE_QUOTE = '\''; - const char DOUBLE_QUOTE = '\"'; - - if ( *p == SINGLE_QUOTE ) - { - ++p; - end = "\'"; // single quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else if ( *p == DOUBLE_QUOTE ) - { - ++p; - end = "\""; // double quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else - { - // All attribute values should be in single or double quotes. - // But this is such a common error that the parser will try - // its best, even without them. - value = ""; - while ( p && *p // existence - && !IsWhiteSpace( *p ) // whitespace - && *p != '/' && *p != '>' ) // tag end - { - if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { - // [ 1451649 ] Attribute values with trailing quotes not handled correctly - // We did not have an opening quote but seem to have a - // closing one. Give up and throw an error. - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - value += *p; - ++p; - } - } - return p; -} - -#ifdef TIXML_USE_STL -void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - while ( in->good() ) - { - int c = in->peek(); - if ( !cdata && (c == '<' ) ) - { - return; - } - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - (*tag) += (char) c; - in->get(); // "commits" the peek made above - - if ( cdata && c == '>' && tag->size() >= 3 ) { - size_t len = tag->size(); - if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { - // terminator of cdata. - return; - } - } - } -} -#endif - -const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - value = ""; - TiXmlDocument* document = GetDocument(); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - - const char* const startTag = ""; - - if ( cdata || StringEqual( p, startTag, false, encoding ) ) - { - cdata = true; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - if ( document ) - document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // Keep all the white space, ignore the encoding, etc. - while ( p && *p - && !StringEqual( p, endTag, false, encoding ) - ) - { - value += *p; - ++p; - } - - TIXML_STRING dummy; - p = ReadText( p, &dummy, false, endTag, false, encoding ); - return p; - } - else - { - bool ignoreWhite = true; - - const char* end = "<"; - p = ReadText( p, &value, ignoreWhite, end, false, encoding ); - if ( p && *p ) - return p-1; // don't truncate the '<' - return 0; - } -} - -#ifdef TIXML_USE_STL -void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - while ( in->good() ) - { - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - (*tag) += (char) c; - - if ( c == '>' ) - { - // All is well. - return; - } - } -} -#endif - -const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) -{ - p = SkipWhiteSpace( p, _encoding ); - // Find the beginning, find the end, and look for - // the stuff in-between. - TiXmlDocument* document = GetDocument(); - if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); - return 0; - } - if ( data ) - { - data->Stamp( p, _encoding ); - location = data->Cursor(); - } - p += 5; - - version = ""; - encoding = ""; - standalone = ""; - - while ( p && *p ) - { - if ( *p == '>' ) - { - ++p; - return p; - } - - p = SkipWhiteSpace( p, _encoding ); - if ( StringEqual( p, "version", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - version = attrib.Value(); - } - else if ( StringEqual( p, "encoding", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - encoding = attrib.Value(); - } - else if ( StringEqual( p, "standalone", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - standalone = attrib.Value(); - } - else - { - // Read over whatever it is. - while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) - ++p; - } - } - return 0; -} - -bool TiXmlText::Blank() const -{ - for ( unsigned i=0; i - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru corsix-th-0.30/appveyor.yml corsix-th-0.62/appveyor.yml --- corsix-th-0.30/appveyor.yml 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/appveyor.yml 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,25 @@ +version: '{build}' +image: Visual Studio 2017 +pull_requests: + do_not_increment_build_number: true +init: +environment: + matrix: + - GENERATOR: Visual Studio 15 2017 Win64 +cache: + - vcpkg -> CMake/VcpkgDeps.cmake, scripts/build_vcpkg_deps.ps1 +configuration: Release +before_build: + - cmd: cmake -G "%GENERATOR%" -DUSE_VCPKG_DEPS=ON +build: + project: CorsixTH_Top_Level.sln + verbosity: minimal +after_build: +- cp -R %APPVEYOR_BUILD_FOLDER%/CorsixTH/Lua %APPVEYOR_BUILD_FOLDER%/CorsixTH/Release/Lua +- cp -R %APPVEYOR_BUILD_FOLDER%/CorsixTH/Bitmap %APPVEYOR_BUILD_FOLDER%/CorsixTH/Release/Bitmap +- cp -R %APPVEYOR_BUILD_FOLDER%/CorsixTH/Levels %APPVEYOR_BUILD_FOLDER%/CorsixTH/Release/Levels +- cp -R %APPVEYOR_BUILD_FOLDER%/CorsixTH/Campaigns %APPVEYOR_BUILD_FOLDER%/CorsixTH/Release/Campaigns +- cp %APPVEYOR_BUILD_FOLDER%/CorsixTH/CorsixTH.lua %APPVEYOR_BUILD_FOLDER%/CorsixTH/Release/ +artifacts: +- path: CorsixTH/Release/ + name: CorsixTH diff -Nru corsix-th-0.30/build_files/toolchain-mingw.cmake corsix-th-0.62/build_files/toolchain-mingw.cmake --- corsix-th-0.30/build_files/toolchain-mingw.cmake 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/build_files/toolchain-mingw.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -2,16 +2,16 @@ SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ -SET(CMAKE_C_COMPILER i586-mingw32msvc-gcc) -SET(CMAKE_CXX_COMPILER i586-mingw32msvc-g++) -SET(CMAKE_RC_COMPILER i586-mingw32msvc-windres) +SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc) +SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) +SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) # here is the target environment located -SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc) +SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) \ No newline at end of file +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff -Nru corsix-th-0.30/changelog.txt corsix-th-0.62/changelog.txt --- corsix-th-0.30/changelog.txt 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/changelog.txt 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,1126 @@ +------------------------------------------------------------------------------- +Version 0.62 - released July 2018 +------------------------------------------------------------------------------- +# New Features +* Player salary is now preserved between campaign levels +* Mouse capture is now shown on in game options screen +* Completely out of source builds are now supported on all platforms +* FHS style file layout (separate bin and share/corsixth directories) support + for Linux (and non-Apple Unixes) +* On Linux (and other non-Apple Unixes) the CorsixTH executable is now called + corsix-th +* LuaJIT 2.x is now supported, if using LuaJIT 1.x JIT is no longer enabled +* Meandering staff behaviour has been tweaked to look more natural + +# Bug Fixes +* Hoppalong map in the included campaign was fixed to not crash +* Correctly handle the death of emergency patients +* VIP and other game event scheduling fixes +* VIP now works correctly when the hospital has no functional rooms +* Heat now spreads out from radiators in all directions again +* Fix for game error that caused the same litter to be cleaned up twice, and + resulted in a crash +* Fix moving machines with no state +* All known memory leaks caused by our code have been fixed +* Many text and formatting improvements across languages + + +------------------------------------------------------------------------------- +Version 0.61 - released December 2017 +------------------------------------------------------------------------------- +* Mouse capture support. Now by default the mouse will be captured in its + window. You can use CTRL-F10 to temporarily toggle the mouse capture state, + or disable it in the config file. +* Added multigesture movement and zoom for supported devices. +* Fix for broken pathfinding involving the removal of side objects such as + benches and radiators. +* Allow objects to be built on top of litter and rat holes. +* Fix for game error when handymen attempted to clean removed litter. +* Can now click and hold to quickly change handyman priorities. +* Significant map editor performance improvement when selecting multiple tiles. +* If the config option to allow playing while paused is enabled, you can now + make use of the bottom panel. +* Fixed several bugs relating to the mood displays for staff and patients. +* Rooms can now be built over top of trash. +* Rat holes will now appear in dirty hospitals. Unfortunately the rats + themselves are still hiding away. +* Earthquakes now behave more like in Theme Hospital. A warning earthquake that + does no damage will come first so that you can get ready for the big one. The + damage calculations and visual effect have also been redone to be closer to + the original game. +* The game window can now be resized by dragging the edges. +* We now avoid overlapping graph labels so all labels are readable. +* Many many many bug fixes. + + +------------------------------------------------------------------------------- +Version 0.60 - released May 2016 +------------------------------------------------------------------------------- + +--- Highlights from this release --- + +* User campaigns - It is now possible to create a series of levels that play + together just like the original game. +* In game map editor - A new map editor is available directly from the game + menu. +* Drug price impact - Patients will now react to the price you set for + treatments. If treatments cost too much patients will opt to go home instead + and this can affect your reputation. +* Variable spawn rate - The spawn rate will now take into account your + hospital's reputation (after a date set in the level file.) +* Machine smoke is now visible when machines are close to worn out. +* Right clicking the timer is now supported like in the original game for + moving to affected patients - See issue #882 for details. +* Numpad support - The number pad can now be used to move around the map when + numlock is off, or to type numbers when numlock is on, without side effects. +* The MP3 folder can now be unset from within the game. Previously after + setting an mp3 folder it could only be removed by editing the config file by + hand. +* Uses the proper cursor for resizing rooms. +* Bins can now be placed in the hallways. +* Temperature impact has been tweaked. The initial grace period has been + removed and the overall impact has been softened. +* Custom maps can now be stored in a user directory separate from levels + shipped with the game. + +--- Notable bug fixes --- + +* Free build mode is now truly free - rooms used to cost money in this mode. +* In game movies will now work correctly on more hardware. +* Sound effects are no longer played when sound is disabled. +* VIP rewards have been tweaked to closer match expectations when the + impression is mediocre. +* Crash when a patient is selected while they walk off the map is fixed. +* A room built next to an unowned parcel no longer loses its wall when the + parcel is bought. +* Beta 1 regression that caused fired staff to continue to be paid has been + patched. +* Beta 1 regression that caused the last cured emergency patient not to count + has been patched. +* King complex patients only pay for their cure once. +* Patients will notice when a room they are waiting for becomes available. +* Properly load saves with more than one object on a tile. +* Do not get stuck in an infinite loop when no disease is available to spawn. + +------------------------------------------------------------------------------- +Version 0.50 - released July 2015 +------------------------------------------------------------------------------- + +The majority of changes in this update have been done under the hood. +Most of our third-party libraries have been updated, and especially Windows +users will notice that there is now only one executable after installation. +No more "which one should I use if I want zoom?"! + + +--- Gameplay --- + +* Fix: Crash when trying to play certain sounds from e.g. the French version. +* Fix: Potential crash from Esc-press before main menu. +* Fix: Patients could in some circumstances get really confused and try to exit + a room without putting any clothes on. + +* Added: Configuration of scroll speed. +* Change: Midi tracks will be played in the order they appear in MIDI.txt + +* Most languages have been updated. + + +--- Movies --- + +* Fix: Audio stutter in certain movies. +* Fix: The game could sometimes crash when a movie had finished. +* Support for LibAV as an alternative to FFMpeg. + + +--- Animation Viewer --- + +* Added: A vertical scroll bar to the sprite display. + + +--- CorsixTH development --- + +* We have moved to newer versions of a lot of libraries, most notably + SDL 1.2 -> SDL 2 and added support for Lua 5.2 and Lua 5.3. +* New ready-to-use Eclipse Workspace. +* Debugging Lua code using DBGp has been added. See + the Wiki for more information. +* The Windows Installer now uses NSIS 3.0 and only produces one executable + since SDL 2 handles renderer itself. +* Framework for Busted Unit Tests in Lua. +* Support for custom graphics has been improved. + + +------------------------------------------------------------------------------- +Version 0.40 - released December 2014 +------------------------------------------------------------------------------- + +It has been a while since our last release, but good things come to those who wait! +Or... in this case it's contagious diseases. Watch out for epidemics on the +later levels in the campaign! Your patients are not as good as they used to be +either, so those who are not lucky enough to get vaccinated and cured might +get a visit from the Grim Reaper. +Also, don't forget to try out the new map St. Peter's near Cawley! + +Happy gaming! + + +--- Gameplay --- + +* Added: Epidemics. You can either choose to pay a fine to the authorities or + try to cover up the epidemic by vaccinating and curing the contagious patients. + Patients going between buildings will NOT trigger the alarm to the authorities. +* Added: The Grim Reaper. Previously patients have always gone to heaven when + they die. No more! Sometimes they will instead fall down to the middle of the + earth in a Lava Hole. +* Added: People with visual diseases will no longer arrive at the beginning of + the level if that has been specified in the level file. Instead they arrive + once a certain amount of months have passed. +* Added: If you refuse VIP visits a few times he can sometimes show up anyway. + +* Change: Machine usage and explosions are now based on absolute number of uses. + A machine that goes down to 0 will explode. Previously they were percentage based. + +* Fix: The game would crash if you sacked a doctor in a room while a patient + was using some equipment in that room. +* Fix: Sometimes the emergency bonus was not correctly calculated. +* Fix: Patients could die inside a room. They will now die outside the room + unless they are just being cured. +* Fix: If winning the level at end of year the annual report would hide the + winning fax. +* Fix: If there was no queue to a room a leaving staff member would not trigger + a call for staff for the patient who had to abort their procedure in that room. +* Fix: If a handyman had pending tasks when he died in an exploding room the game + could crash. +* Fix: A surgeon that is removed in mid-operation will now get properly replaced + by a new one. +* Fix: If the GP room was built too early in the tutorial the game would crash + when building a GP room later on if debug mode was turned off. +* Fix: Patients would try to enter an exploding room. As you can imagine, + this was bad. +* Fix: Psychiatrists would become shut-ins and just wander about their office + forever. +* Fix: Patients leaving the queue to get a drink could be left to sit on a + bench forever. + + +--- User Interface --- + +* Added: Tooltips for the increase and decrease buttons in the research screen. +* Added: A sound that indicates if a screenshot was taken successfully. +* Added: Any dialog that pops up, such as the award screen, pauses the game. +* Added: 'Continue Game' in the main menu. + +* Fix: Sometimes the game would not pause on year end. +* Fix: Staff raise description was hard to read in some languages +* Fix: The current language setting is translated and consistent with the + options in the list. + + +--- Graphics --- + +* Fix: Instead of turning into a Bloaty Head, Baldness patients will die + with gracious hair. +* Fix: Patients will no longer fall through walls when dying. +* Fix: Dying Hairyitis patients should not lose their head when on the floor. + + +--- Hotkeys --- + +* Added: 'Z' temporarily moves the game at maximum speed. Release to go back + to the previous speed. +* Added: 'X' makes walls transparent until released. +* Added: Use the Numpad to change game speed. +* Added: Arrow key hotkeys in the staff management screen. +* Added: Press and hold on '+' and '-' when buying furniture to + repeat the action. + +* Change: Quick Save is now Shift+Alt+S, Quick Load is Shift+Alt+L. + + +--- Languages --- + +* Change: "Plot" is used instead of "Parcel" to indicate where a handyman has + been zoned to work in the Handyman staff dialog. + +Most languages have been updated since our last release, but if you find that +your language has not, please help us to finish it! + + +--- CorsixTH Development --- + +* Added: New flag for CMAKE: 'WITH_LUAJIT'. This way you can choose to use + either LuaJIT or Lua5.1. +* Added: CMake toolchain for building with MinGW. +* Added: New debug menu option 'Run debug Script' that executes + /Lua/debug_script.lua + + +------------------------------------------------------------------------------- +Version 0.30 - released November 2013 +------------------------------------------------------------------------------- + +This release contains a whole new Level Editor, which means that in combination +with the already existing Map Editor whole levels can now be created a lot +easier. Give it a try! We have also added many new options previously only +available by manually editing the config file to the options dialog. +Players will also notice that we have added an automatic update +check on game launch once we release the version after this one. +As usual there are of course also numerous minor tweaks here and there. + + + +--- Gameplay --- + +* Change: You can now build more than one desk in the ward. More nurses means + a slightly faster throughput. +* Change: Patients would previously queue outside toilets even though there were + free loos since it was dependent on number of people in the room. Now, as soon + as a loo becomes free another patient enters the room to use it, + even if there is a long queue for the sink). + If there is a queue for the sinks there is a chance the patient will leave + without washing their hands - but will not be happy about doing this. + +* Added: The ability to control alien behaviour - sitting, knocking doors, + only to be available through emergency or arrive like all other patients. +* Added: Winning fax opens automatically and pauses the game. +* Added: Option to automatically accept wage increase requests when they "time out". +* Added: A new option allows for your average build content for each type of room + to be remembered, so will be added for each new room built later. + +* Fix: Doctors should get stuck less often, and handymen should not crash the + game as frequently. +* Fix: It was not possible to replace a surgeon when a patient was in the room. +* Fix: Patients would sometimes get stuck inside a room when they should + have died. + + + +--- User Interface --- + +* Added: A new customization menu in the Options dialog. Most options from the + configuration file are now available for change in-game. +* Added: A new directory menu in the Options dialog. +* Added: The game does now check for a more recent version of itself when + launching. +* Added: A helpful message when the player puts more Researchers in the + research department than there are desks. +* Added: The game now does a small integrity check on the Theme Hospital + files to make sure that the most common corruptions are not present. +* Added: Confirm dialog to the quit/exit button on the main menu. + +* Fix: The tooltip for the tutorial button was incorrect since the dialog + has been visually changed. +* Fix: The announcer has had a few corrections made to his manuscripts. + He is very happy about this! + +* Removed: The settings menu is no longer available from within the game. + + + +--- Hotkeys --- + +Some hotkeys have been changed and/or added: + +* Alt + A = Toggle Announcements +* Alt + M = Toggle Music +* Alt + S = Toggle Sound Effects +* Shift and + to zoom in five steps and Shift and - to zoom out five steps at a time. + + + +--- Campaign levels --- + +* Fix: An error in level 8 made it possible to win without meeting the + reputation criterion. + + + +--- Custom levels --- + +* Change: For random emergencies each illness now has its own average number of + patients to spawn. Previously they were all the same. + +* Fix: Researching improvements was not really possible on some custom levels, + i.e. if the map creator had made it so there were no machines at the start. + + + +--- Demo files --- + +* Fix: When winning the demo level CorsixTH looked for another level to load, + showing the wrong fax options and eventually crashing. + + + +--- Languages --- + +* Added: Korean language. + +* Fix: It was not possible to dump strings for a language with unicode + characters in the name. + + + +--- Compiling --- + +* Fix: You could not compile the game with WITH_AUDIO=0 if SDL_mixer was + not present at all. +* Fix: WITH_AUDIO=OFF is now illegal in combination with WITH_MOVIES=ON. + + + +------------------------------------------------------------------------------- +Version 0.21 - released 2013-05-04 +------------------------------------------------------------------------------- + +This is mainly a bugfix release, but a few minor features are still also +introduced, see the changelog below. + + + +--- Gameplay --- + +* Fix: Staff would sometimes not go for a break. +* Fix: A few crashes related to Handymen. +* Fix: An error could occur if a fax message was removed just as it was animating + into view. +* Fix: Patients could sometimes be told to go home multiple times, + resulting in a crash. +* Fix: If a queueing patient was heading for a drinks machine just as the player + moved that machine the game would crash. + + + +--- User Interface --- + +* Added: Scrolling momentum when using the middle button. +* Added: There is now a clock in the right corner of the menu bar that + shows the real world time. It can be toggled between AM/PM and 24h + in the configuration file. + + + +--- Hotkeys --- + +* Added: Hotkeys for the Jukebox (J), Save game menu (Shift + S), + Load game menu (Shift + L), to restart the level (Shift + R) and finally + quit the current game and take you back to the opening screen (Shift + Q). + +* Change: Restart is now Shift + F10 instead of only F10. +* Change: Toggle adviser is now Shift + A instead of only A. +* Change: Key combinations will only trigger if that exact combination + is pressed. E.g. Ctrl + R will not trigger R too. +* Change: Alt + F4 is now the hotkey to quit CorsixTH. + +* Fix: Added a configuration option to have the possibility to use Shift + C + as hotkey to open the Drug casebook instead of C. This is to workaround + a bug that when you press on the volume down key on your keyboard + the Drug casebook would open. + + + +--- Map Editor --- + +* Added: Undo/Redo functionality. +* Added: Street lamps and the dead looking tree. + + + +------------------------------------------------------------------------------- +Version 0.20 - released 2013-03-24 +------------------------------------------------------------------------------- + +In this version major new features include in-game movies, objects that +occupy only the edge of a tile and the graph window. + + + +--- Main features not yet implemented --- + +* Epidemics. +* Rats (and the rat level). +* Insurance company graphs, illness graphs. +* Visual effects on patients with serious radiation and jellyitis. +* Some fullscreen animations such as the winning letter. +* Multiplayer support. + +For a (nearly) complete list, visit our Programming Ideas wiki page: +http://code.google.com/p/corsix-th/wiki/ProgrammingIdeas + + + +--- Known Issues --- + +* Emotion icons don't appear just above a humanoid's head at all times. +* Main menu/in-game may glitch when using the OpenGL version. + +For a complete list, visit the issue tracker: +http://code.google.com/p/corsix-th/issues/list + + + +--- Gameplay --- + +* Added: Radiators and other "edge tile" objects now occupy just one edge of + the tile, inline with the original game. As a result one tile corridors can + now be heated properly. An addition is that you can place many such objects + on a single tile as long as they face different directions. + +* Added: Possibility to play movies in-game. At the moment the intro movie, + advancement between levels and the win/lose movies has been added. + +* Added: The atom analyzer can now be built in the research department if it + is available on the map. + +* Added: User actions are no longer allowed by default (for new games) when + the game is paused. When trying this it might seem like it doesn't work + correctly, but we try to mimic the original as much as possible. This for + example means that a staff member being placed as you pause will disappear + from the cursor. We might change this behaviour in the future though. + +* Added: Some background sounds, coughs, phones ringing etc. + +* Change: Placing a member of staff inside a room that is already occupied + will now replace that person. + +* Fix: Earthquakes could be four times as severe as intended. Still todo: + A tremor before a coming big earthquake. + +* Fix: Crashes in certain situations involving receptionists and reception + desks. +* Fix: Patients being handled at a reception desk even if no receptionist + is present. +* Fix: Allow patients to be sent to the research room only if the corresponding + room is not yet researched (so not if it is researched but not built). +* Fix: Don't cancel a place staff action just because the player happens to + click on a door. +* Fix: The VIP would try to sit down if there was a queue for the reception desk. + The VIP will no longer ever try to sit down, and he will have priority in + the queue anyway. +* Fix: If a member of staff was done resting at the same time as he/she was + also finished using the pool table or the video game another object in the + room could get reserved indefinitely. + + + +--- User Interface --- + +* Added: You can now see in the bank statement which drug company a certain + drug was bought from. It has no effect on gameplay though. + +* Added: The adviser now tells you why the research screen can't be opened + before you have built a research department. + +* Added: The Town Map functionality has been extended inline with Theme + Hospital. For example, if you right-click somewhere in your hospital the + view will be moved there. + +* Added: Available options on open faxes now gets updated if for example a room + explodes or the player builds a research department. +* Added: Keyboard shortcuts F1 - F9 for the fullscreen windows. They are NOT the + same as in original TH but instead correspond to the order on the bottom panel. +* Added: Possibility to choose font file in the options dialog. +* Added: Player name is now customizable in the new game dialog. + +* Removed: Keyboard shortcuts F8 and F9 for debug fax and debug patients. +* Change: Don't require debug mode to be able to dump the gamelog. +* Change: The shortcut for dumping strings is now Ctrl+T instead of Ctrl+Shift+D. + +* Change: Restructured options window to make it more consistent, less clutter-y + and smaller. +* Change: It is now possible to concentrate research on operating theatre + diseases and redistribution of research is automatically done when + a category has been completely researched. +* Change: Add disease name to patients' treatment history when they are + diagnosed. +* Change: Buttons on the bottom panel for fullscreen windows are now + toggle buttons. +* Change: Reordered entries of graphs menu to correspond with order in + bottom panel. + +* Fix: Colour selection algorithm for freetype fonts resulted in unreadable text + on faxes for some languages. +* Fix: When an unanswered fax became meaningless (e.g. if you built the + required room), it was only removed if its message button was visible at the + bottom panel (not if it was queued because of 5 buttons being there already). +* Fix: Update the drug casebook if the last room of one kind explodes. +* Fix: The directory browser was not always shown if the chosen Theme Hospital + install directory was illegal. +* Fix: Settings changed in the game will be saved immediately so that they + persist to the next session regardless of how the game is shut down. +* Fix: The bottom panel is no longer always on top, making fullscreen + dialogs truly fullscreen on 640x480. +* Fix: Don't play any announcements if there is no receptionist to do it. +* Fix: The adviser would not idle again if a new message arrived as he was + idling from a previous message. +* Fix: While a player viewed the confirm dialog to delete a room he/she could + continue to edit the room and complete it again resulting in an inconsistent + game state. + + + +--- Graphics --- + +* Added: The graph dialog now actually displays graphs and statistics information. + +* Added: It is now possible to choose among three colour scales for warmth + level. Look in the top menu for this choice. + +* Added: Print some info in the command prompt when the user wants to take + a screenshot, so he can see if and why it failed. +* Added: Screenshot functionality for OpenGL version. +* Change: Screenshots get saved to a dedicated screenshot folder now, + which can be changed in the config. +* Fix: Loading a game on startup where a fullscreen window was open would + open with the font messed up. +* Fix: Taking a screenshot (Ctrl+S) is now possible under windows without + fiddling in a lua file. + + + +--- Translations --- + +* Added: The beginning of Brazilian Portuguese and Hungarian. +* Change: The "utf8" prefix has been obsolete for some time and has been + removed from all language files. + + + +--- When using Demo files --- + +* Fix: The game would crash if the player tried to open the staff management + dialog by clicking on a staff portrait in the staff dialog. + + + +------------------------------------------------------------------------------- +Version 0.11 - released 2012-11-17 +------------------------------------------------------------------------------- + +This is a bugfix release. For known issues etcetera, check out the +changelog for version 0.10 below. + + +-- Gameplay -- + +* Fix: Patients were not fully diagnosed according to settings + in the policy screen. +* Fix: The game now handles a player trying to cheat into an earthquake + on levels 1-4. +* Fix: It was not possible to sell equipment in rooms if you had a negative + balance. +* Fix: Handymen could not be placed inside rooms. +* Fix: Handymen would get called to clean soot in blown up rooms. +* Fix: Machines that need to be repaired will now cancel that request if + they are blown up. +* Fix: If a cured patient was leaving a room just as it crashed because + of an earthquake the game would throw an error. +* Fix: Alien DNA could under some circumstances not have the + "concentrate research" button clicked without triggering a crash. +* Fix: A crash occurring under some circumstances if the player picked + up a staff member. + + +-- User Interface -- + +* Enhancement: Since consultants are unable to learn new skills icons for + not yet fully learned skills are now removed when a doctor is promoted. +* Fix: Disabling background music no longer disables sound effects on Windows. +* Fix: Checking if a sound exists crashed the game if there was no sound + archive at all. +* Fix: If the player paused the game from the top menu bar while an earthquake + was active it would be impossible to scroll. + + +-- Graphics -- + +* Fix: On a few levels some sliding doors would not animate correctly. +* Fix: Vomiting standard males had the wrong animation. + + + +------------------------------------------------------------------------------- +Version 0.10 - released 2012-09-24 +------------------------------------------------------------------------------- + +-- How versions work -- + +If you have been wondering how the new version system works: +When major new features are added the second digit is increased. +When there are only fixes or smaller new features the third digit +is increased. + +In this version, for example, earthquakes have been added. + +-- Not Yet Implemented -- + +* Epidemics +* Rats +* Graphs +* Visual effects on patients with serious radiation and jellyitis. +* Fullscreen animations such as the level screen and winning letter. + +-- Known Issues -- + +* If the X-Ray Viewer is inaccessible in the Operating Theatre no image will + be shown on it. +* If the user exits the game via "the cross" when in windowed mode settings + are not saved. +* Radiators and other "edge tile" objects occupy a whole tile instead of + just one edge of the tile. + +-- Gameplay -- + +* Added: Earthquakes have recently been reported! +* Added: Handyman priorities have been added. They can also be told to stay + and respond to calls in one building (parcel) only. +* Added: Staff's happiness will change due to more environmental factors. + +* Change: The files containing dumped strings are now created alongside the + config file instead of in the installation directory. + +* Fix: Handymen will now meander inside a room until the machine which needs + repair is free for use. +* Fix: The URL in the config file pointing to better quality music was outdated. + Note that this only affects new installations. +* Fix: Two identical entries were shown in the drug casebook if a new disease + was discovered when it was open. +* Fix: Don't crash when a saved game with the town map open is loaded. +* Fix: Too large rooms could make them unusable. +* Some graphical glitches have been fixed. + +-- User Interface -- + +* Added: The Map Editor and Animation Viewer have new icons. +* Change: In debug mode all gamelog output is now also displayed in the + command prompt. +* Fix: Don't initiate a window move if it happens to be below a top menu + selection. +* Fix: Don't show the main menu under any circumstances when closing the + options menu in-game. + +-- Map Editor -- + +* Fix: The "Save" and "Save As" buttons now do what they should do. +* Fix: There were some strange log messages on opening the editor. +* Added: The arrow keys can now be used to scroll the map. +* Change: Removed a lot of tiles from the palette, since maps may not + work as intended if they would be used. + +------------------------------------------------------------------------------- +Version 0.01 - released 2012-03-24 +------------------------------------------------------------------------------- + +-- Not Yet Implemented -- + +* Earthquakes +* Epidemics +* Handyman priorities +* Rats +* Graphs +* Visual effects on patients with serious radiation and jellyitis. +* Fullscreen animations such as the level screen and winning letter. + +-- Known Issues -- + +* If the X-Ray Viewer is inaccessible in the Operating Theatre no image will + be shown on it. +* If the user exits the game via "the cross" when in windowed mode settings + are not saved. +* Radiators and other "edge tile" objects occupy a whole tile instead of + just one edge of the tile. + +-- Gameplay -- + +* Added: A host of awards given at year end. +* Added: A new mode: Free Build Mode. In this mode you don't have to worry + about money. All custom maps can be played in this mode. +* Added: Patient animations such as yawning and checking watch when waiting. + +* Change: The queue size for a room can be set to 0 to prevent patients + from going there. +* Change: Patients now spend some more time in the ward. + +* Fix: Crash when removing a room that has humanoids on their way to it. +* Fix: Patients sitting down, but about to get a soda got ordered to sit down again. +* Fix: A crash could occur if a new room was accepted when there were multiple types + of objects left to place. +* Fix: Emergencies with diseases not available on a level no longer happen. +* Fix: The VIP no longer makes staff be called to the rooms he visits. +* Fix: With multiple reception desks new patients now find their way to the + reception with the least queue size. +* Fix: The wrong amount of money was returned when selling a room. +* Fix: Aliens could not be cured on the last two levels. +* Fix: The transparent walls setting made new rooms remove outer walls. +* Fix: Sometimes patients who had left the hospital could still wait for a new room, + making said room impossible to build. +* Fix: A crash when the staff member left a room before the patient. +* Fix: Build cost of objects were not always correct. + +-- User Interface -- + +* Added: The save and load dialogs can now sort both ascending and descending + and are a little more spacy. +* Added: More messages in the progress report dialog. +* Added: More advice in different situations from the adviser. +* Added: Adviser messages now has priorities, making more important messages + appear faster. + +* Change: When the mouse cursor leaves the game window it will stop scrolling + the in-game world. +* Change: The message when a crash occurs is now a little more informative, and + humanoids no longer get stuck as easily. + +* Fix: The staff management window is now updated when staff is hired or + fired from outside the window itself. +* Fix: If the desired language cannot be loaded on startup the game now + reverts to English instead of crashing. +* Fix: The game could not autosave if the save or load dialog was open. + +* The auto-scroll setting is now saved between sessions. +* The adviser can now be turned off from the top menu. +* The game uses a new icon. + +-- Map Editor -- + +* Fix: The game no longer crash just because the map builder has not added any + access roads from the edge of the map. + +------------------------------------------------------------------------------- +Version Beta 8 - released 2011-09-24 +------------------------------------------------------------------------------- + +-- Gameplay -- + +* Fix: Patients should manage to use benches more often now. +* Fix: Staff will never have the "waiting for patient" mood when in a training + room or a staff room anymore. +* Change: Which diagnosis rooms different patients go to have been changed + to be more like the original game. +* Change: No patients will arrive until you have both a receptionist and a reception + desk. There will be no emergencies or VIP visits either until this criterion is met. +* Added: People may now puke or pee on the floor. +* Added: Various things such as litter and plants affect patient happiness. +* Added: A doctor may now get crazy if he is waaay too tired. +* Added: VIP visits. Watch out for those picky black suit visitors! +* Added: The "guess cure" fax message will now properly pop up. + +-- User Interface -- + +* Change: The save and load dialogs now look a little different. Autosaves are stored + in a separate folder and there can be up to 12 autosaves at the same time. One for + each month. The dialogs now show when a save was made, and the list can also be + sorted by this criterion. +* Added: It is now possible to cycle through owned machines by right-clicking + the machine name in the machine dialog. +* Added: Sound, announcement and music volumes and on/off settings are now + saved between sessions.s + +-- Graphics -- + +* Added: Waiting patients may sometimes check their watch or start to tap their foot. +* Added: Soda machines now sell more than soda cans. This can be seen through the + litter people throw on the floor after using said machines. +* Added: (Animation Viewer) A new export function has been added. Note that there + is currently no import equivalent, so it is mostly for people to try out and + see what graphics there are in the game. In the future we hope to make it possible + to import these graphics after changing them in your favourite graphics program. + +-- Translations -- + +New language: Polish + +------------------------------------------------------------------------------- +Version Beta 7 - released 2011-06-24 +------------------------------------------------------------------------------- + +-- Known Issues -- + +* If the X-Ray Viewer is inaccessible in the Operating Theatre the whole + room will be unusable. +* There are still many features which are not yet implemented including trash, + earthquakes, epidemics and awards. +* The graph window doesn't show any graphs. +* Handyman priorities are not yet fully implemented. + +-- Gameplay -- + +* Added: Staff severance pay. +* Added: Patients may die if they don't get treated in time. +* Added: Doctors slowly gain skill when working. +* Added: Extra objects and the number of trainees influence speed of training + in the training room. +* Added: Even with no research new machines will eventually become available. +* Added: Some patients have started littering your hospital with soda cans! + Make sure you have enough handymen to keep your hospital clean. +* Added: Modern heating systems aren't as reliable as they used to be. Prepare + for breakdowns now and then. + +* New disease: Alien DNA! Note that there are still a few glitches to fix + concerning this new disease. + +* Change: Vending maintenance costs have increased throughout the world and + as a result Sodas now cost $20, up from $15. +* Change: Heating costs are calculated on a per day basis, rather than per month. +* Change: Machine and drug improvements are now made evenly across all eligible + objects rather than maxing one at a time. +* Change: Humanoids never meander outside anymore. + +* Fix: Handymen no longer crash the game when trying to water an unreachable + plant. +* Fix: Staff resting in the staff room should keep their sofa until fully + rested if there's nothing else to do. +* Fix: The player can't hire new staff or pay bonuses without a positive balance. + +-- User Interface -- + +* Added: The graph window, no graphs yet though. +* Added: Right click menu in the queue dialog. +* Added: Confirmation dialog when about to fire a member of staff. + +* Fix: If there is only one person who is in an emergency, use the singular + form in the sentence. +* Fix: The pickup item button in the edit room dialog is now fully functional. +* Fix: The pointer should no longer jump around in Linux when using SDL. + +-- Graphics -- + +* Added: The scanner uses more than one animation. + +* Fix: Some objects were cut in half after a relocation. + +-- Translations -- + +* Change: If the specified language is not found, try to revert to English. +* Fix: Competitor names are now translatable. + +------------------------------------------------------------------------------- +Version Beta 6 - released 2011-03-24 +------------------------------------------------------------------------------- + +-- Gameplay -- + +* Feature: Staff speed! +* Added: All parts of research have been implemented, including + machine strength improvements, drug improvements and the + "concentrate research" button in the drug casebook. +* Added: Overdraft charges for having a negative balance. +* Fix: The length of a day was about half as long as it should be. +* Fix: A few occurrences of bone-idle patients have been resolved. +* Fix: Juniors were not correctly labeled as Doctors after promotion. +* Fix: Some crashes regarding receptionists. +* Fix: Never charge less than initial cost when reputation is below 500. +* Fix: Some repair animations were too short. +* Fix: Don't check winning and losing conditions so often. +* Fix: Taking loans can now make the player avoid losing. +* Fix: Level 7 had an emergency with an unavailable disease. +* Fix: Doctors on their way back to the research room or training room + will no longer answer to any calls. +* Fix: Don't crash if a patient in a machine is sent home. +* Fix: Various tweaks to the operating theatre logic. +* Fix: Don't crash if the staff window of a leaving staff member + is open when he/she leaves the world. +* Fix: Persistent data (salary, built rooms etc) are no longer lost + after restarting a level. + +-- User Interface -- + +* Feature: The drug casebook now shows if you can treat a disease or not, + and in the latter case the tooltip tells you what is missing. Actual + price is shown after some time, instead of charge %. +* Feature: Press and hold on value buttons will now make the value continue + to increase until the button is released again. +* Feature: The Theme Hospital installation path can be changed from the + options menu. +* Added: The adviser will help out in a few more situations. +* Fix: Mouse position events such as moving staff around didn't work + when scrolling using the arrow keys. +* Fix: Tooltips are now updated more frequently, + most evidently in the research pane. + +-- Translations -- + +* Feature: CorsixTH now supports TrueType fonts via FreeType2! +* Feature: To assist translators a new diff file is now created when you + choose the debug option "dump strings" (with languages other than English). + It contains those strings which are either found in English but not in + the given language, or found in the given language but not in English. + +* New languages: Traditional Chinese, Simplified Chinese, Russian. + +------------------------------------------------------------------------------- +Version Beta 5 - released 2010-12-24 +------------------------------------------------------------------------------- + +-- Gameplay -- + +* Feature: (Some) Cheats added. Type 24328 into the fax machine to get access to them. +* Feature: Custom map "Avatar" added. +* Feature: Player's "salary" (read: score) now increases over your level progress. +* Feature: Level based interest rate. +* Feature: Level based "starting staff" (e.g. original level 5). +* Feature: "No deaths" trophy added. +* Fix: Error could occur when losing a game. +* Fix: Multiple handymen watering the same plant at the same time. +* Fix: Some placements of opposite doors/objects were wrongly forbidden. +* Fix: Error could occur when building a surgery. +* Fix: Autopsy now has an appropriate impact on research. +* Fix: Salaries for doctors were too high. +* Fix: In some cases lose conditions were not triggered. +* Fix: Research room door could disappear after autopsy. + ... and various other bugs fixed. + +-- User Interface -- + +* Feature: The player is now told the reason why he lost, when he loses, instead of being left in the dark. +* Fix: Wrong winning faxes shown for levels 5-11. +* Fix: Weird scrolling behavior could occur after loading a game. +* Fix: No tutorial when playing with demo files. +* Fix: Adviser disappeared too quickly during tutorial. +* Some improvements to textboxes. +* Some improvements to windows. + ... and various other small improvements and fixes. + +-- Translations -- + +* Fix: Error caused by some winning faxes in Norwegian. + +------------------------------------------------------------------------------- +Version Beta 4 - released 2010-11-12 +------------------------------------------------------------------------------- + +-- Gameplay -- + +* Feature: The Research Department and research policy dialog. +* Feature: The Operating Theatre. +* Feature: Not all parcels are owned by the player from the beginning, but + can now be bought from the Town Map dialog. +* Feature: Calculate staff wages and properties for those for hire based + on the level files. + +* Added 7 new diseases related to the operating theatre. +* Added treatment room: Operating Theatre. + +* Fix: The adviser no longer complains about watering of plants all the time. +* Fix: Some crashes related to crashed rooms has been fixed. + + +-- User Interface -- + +* Feature: Possibility to choose difficulty level when starting a new game. +* Feature: Zooming (only when using DirectX or OpenGL). +* Feature: The Annual Report Dialog. + +* Graphics: Improved the main menu background. +* Fix: Solved issues with non-English keyboard layouts. + + +-- Translations -- + +* New languages: Finnish and Danish +* Fix: When playing the game in French it no longer crashes upon completion of a level. + + +------------------------------------------------------------------------------- +Version Beta 3 - released 2010-06-24 +------------------------------------------------------------------------------- + +-- Gameplay -- + +* Feature: Swing doors (used by new diagnosis room ward). +* Feature: Plants will now droop unless they are watered by a handyman. +* Feature: Adjustable handyman priorities. +* Feature: Existing rooms can now be edited and deleted. +* Feature: Watch for initial opening of hospital at start of each level. +* Feature: Each level has its own goals, shown at the beginning of the level and + in the new status dialog. When the goals have been achieved the player may go on + to the next one. +* Feature: Not all implemented rooms and diseases appear anymore in each level, but + only those defined by the level script. +* Feature: Support for custom levels with their own maps and level scripts. +* Feature: A heating system that depends on outside temperature, adjacent tiles + and radiators among other things. + +* Added 6 new diseases +* Added treatment rooms: Jelly Vat, Decontamination +* Added diagnosis rooms: Blood Machine, Ward, Scanner + +* Fix: Staff needed in rooms is handled much better. +* Fix: Objects retain their statistics when moved. +* Fix: A horde of other bugs have also been fixed. + + +-- User Interface -- + +* Feature: Savegames are no longer limited to 8 slots + autosave. +* Feature: Fullscreen mode, screen resolution and interface language can be changed + ingame. The changes are saved in the config file and preserved. +* Feature: Hovering the mouse over a room will mark all patients in queue for this room. +* Feature: Patients can be moved to the head/tail of queues in the corresponding dialog. + They can also be placed between other patients. +* New dialogs: Load Game, Save Game, Custom Level to cope with arbitrary number of + savegames/levels. +* New dialog: Options +* New dialog: Progress Report (Status) showing status of the current level's goals. +* Added all tooltips that were still missing. + + +-- Misc -- + +* Translations: Italian, Spanish and French: added new strings not available in vanilla TH, + Portuguese (WIP) and Dutch (WIP) +* The configuration file and saved games can now, if desired, also be stored in the user's + home directory or equivalent. + + +------------------------------------------------------------------------------- +Version Beta 2 - released 2010-03-24 +------------------------------------------------------------------------------- + +* Feature: Save / Load functionality. +* Feature: Patients and staff now have a need for heat (from radiators) in + order to stay happy. Patients will also get thirsty (build drinks machines) + and will need a bathroom sooner or later, and staff will ask for a salary + raise when unhappy. +* Feature: Machines will need repair now and then. A dialog that shows + necessarry information is displayed when the machine is clicked. +* Feature: Dynamic Information Bar in the bottom right corner of the UI added. + It shows information about entities beneath the mouse cursor. +* Feature: The training room can now be built, where doctors can increase + their skill and get additional traits if a consultant is present. +* Feature: When a patient cannot be cured or a room is missing a fax will + arrive and ask the player what to do. +* Feature: A new string system that allows us to add new (translatable) text + to the game, correct mistakes in existing languages and add new languages. +* Feature: A tutorial is offered to the player at the start of the game. +* Feature: Tooltips are displayed when hovering over buttons for some time. +* Feature: Emergencies may happen every now and then. +* Feature: Hospital reputation system. +* Feature: Humorous disease description faxes are now shown when a disease is + first diagnosed. +* Feature: Room blueprints can be resized during the build process. + +* New Dialogs: Hospital Policy, Drug Casebook, Bank Manager, Staff Management, + Town Map (work in progress), Main Menu +* Many new key shortcuts (see Hotkeys wiki page for full list). +* Dialogs can now be re-positioned by dragging them to where they are wanted. +* Added floating money signs to better indicate where money is coming from. +* Added comments from the advisor in more situations. + +* 10 new diseases. +* New treatment room: Hair Restorer +* Additional functional diagnosis rooms: General Diagnosis, Ultrascan, X-Ray +* Room queues should now re-balance themselves when new rooms are built. + +* Translation: Norwegian (bokml). + +A lot of other small improvements. +Also, a great number of bugs have been squashed. Most remaining bugs are no +longer fatal, and can be continued from. + + +------------------------------------------------------------------------------- +Version Beta 1 - released 2009-12-24 +------------------------------------------------------------------------------- + +Initial release diff -Nru corsix-th-0.30/CMake/CMakeFFmpegLibavMacros.cmake corsix-th-0.62/CMake/CMakeFFmpegLibavMacros.cmake --- corsix-th-0.30/CMake/CMakeFFmpegLibavMacros.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/CMakeFFmpegLibavMacros.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,65 @@ +#------------------------------------------------------------------- +# FindFFmpeg.cmake and FindLibAV.cmake are dependent on this file. +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file +# +#------------------------------------------------------------------- + +### Macro: set_component_found +# +# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present. +# +macro(set_component_found _component ) + if(${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) + # message(STATUS " - ${_component} found.") + set(${_component}_FOUND TRUE) + else() + # message(STATUS " - ${_component} not found.") + endif() +endmacro() + +# +### Macro: find_component +# +# Finds each component's library file and include directory, and sets +# *_LIBRARIES and *_INCLUDE_DIRS accordingly. Additionally detects each +# component's version and sets *_VERSION_STRING. +# +macro(find_component _component _library _header _version) + find_path(${_component}_INCLUDE_DIRS ${_header} + PATH_SUFFIXES + ffmpeg + libav + include + ) + + find_library(${_component}_LIBRARIES + NAMES ${_library} + PATH_SUFFIXES + lib + ) + + if(${_component}_INCLUDE_DIRS AND EXISTS "${${_component}_INCLUDE_DIRS}/${_version}") + file(STRINGS "${${_component}_INCLUDE_DIRS}/${_version}" ${_component}_VERSION_MAJOR_LINE REGEX "^#define[ \t]+LIB${_component}_VERSION_MAJOR[ \t]+[0-9]+$") + file(STRINGS "${${_component}_INCLUDE_DIRS}/${_version}" ${_component}_VERSION_MINOR_LINE REGEX "^#define[ \t]+LIB${_component}_VERSION_MINOR[ \t]+[0-9]+$") + file(STRINGS "${${_component}_INCLUDE_DIRS}/${_version}" ${_component}_VERSION_PATCH_LINE REGEX "^#define[ \t]+LIB${_component}_VERSION_MICRO[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+LIB${_component}_VERSION_MAJOR[ \t]+([0-9]+)$" "\\1" ${_component}_VERSION_MAJOR "${${_component}_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+LIB${_component}_VERSION_MINOR[ \t]+([0-9]+)$" "\\1" ${_component}_VERSION_MINOR "${${_component}_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+LIB${_component}_VERSION_MICRO[ \t]+([0-9]+)$" "\\1" ${_component}_VERSION_PATCH "${${_component}_VERSION_PATCH_LINE}") + set(${_component}_VERSION_STRING ${${_component}_VERSION_MAJOR}.${${_component}_VERSION_MINOR}.${${_component}_VERSION_PATCH}) + unset(${_component}_VERSION_MAJOR_LINE) + unset(${_component}_VERSION_MINOR_LINE) + unset(${_component}_VERSION_PATCH_LINE) + unset(${_component}_VERSION_MAJOR) + unset(${_component}_VERSION_MINOR) + unset(${_component}_VERSION_PATCH) + endif() + + find_package_handle_standard_args(${_component} + REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS + VERSION_VAR ${_component}_VERSION_STRING + ) + + set_component_found(${_component}) +endmacro() diff -Nru corsix-th-0.30/CMake/CopyVcpkgLua.cmake corsix-th-0.62/CMake/CopyVcpkgLua.cmake --- corsix-th-0.30/CMake/CopyVcpkgLua.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/CopyVcpkgLua.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,35 @@ +# Add an extra step to copy LUA files from vcpkg +add_custom_command(TARGET CorsixTH POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${VCPKG_INSTALLED_PATH}/share/lua" + $ +) + +add_custom_command(TARGET CorsixTH POST_BUILD + COMMAND ${CMAKE_COMMAND} -E remove + $/COPYRIGHT +) + +add_custom_command(TARGET CorsixTH POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${VCPKG_INSTALLED_PATH}/$<$:debug/>bin/lfs.dll" + $/lfs.dll +) + +add_custom_command(TARGET CorsixTH POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${VCPKG_INSTALLED_PATH}/$<$:debug/>bin/lpeg.dll" + $/lpeg.dll +) + +add_custom_command(TARGET CorsixTH POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${VCPKG_INSTALLED_PATH}/$<$:debug/>bin/mime/core.dll" + $/mime/core.dll +) + +add_custom_command(TARGET CorsixTH POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${VCPKG_INSTALLED_PATH}/$<$:debug/>bin/socket/core.dll" + $/socket/core.dll +) diff -Nru corsix-th-0.30/CMake/FindDirectX.cmake corsix-th-0.62/CMake/FindDirectX.cmake --- corsix-th-0.30/CMake/FindDirectX.cmake 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CMake/FindDirectX.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -#------------------------------------------------------------------- -# This file was taken from the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# ----------------------------------------------------------------------------- -# Find DirectX SDK -# Define: -# DirectX_FOUND -# DirectX_INCLUDE_DIR -# DirectX_LIBRARY -# DirectX_LIBRARY_DIR -# DirectX_ROOT_DIR - -if(WIN32) # The only platform it makes sense to check for DirectX SDK - include(FindPkgMacros) - findpkg_begin(DirectX) - - # Get path, convert backslashes as ${ENV_DXSDK_DIR} - getenv_path(DXSDK_DIR) - getenv_path(DIRECTX_HOME) - getenv_path(DIRECTX_ROOT) - getenv_path(DIRECTX_BASE) - - # construct search paths - set(DirectX_PREFIX_PATH - "${DXSDK_DIR}" "${ENV_DXSDK_DIR}" - "${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}" - "${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}" - "${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}" - "C:/apps_x86/Microsoft DirectX SDK*" - "C:/Program Files (x86)/Microsoft DirectX SDK*" - "C:/apps/Microsoft DirectX SDK*" - "C:/Program Files/Microsoft DirectX SDK*" - "$ENV{ProgramFiles}/Microsoft DirectX SDK*" - ) - - # Windows 8 SDK has custom layout - set(DirectX_INC_SEARCH_PATH - "C:/Program Files (x86)/Windows Kits/8.0/Include/shared" - "C:/Program Files (x86)/Windows Kits/8.0/Include/um" - ) - set(DirectX_LIB_SEARCH_PATH - "C:/Program Files (x86)/Windows Kits/8.0/Lib/win8/um" - ) - - create_search_paths(DirectX) - # redo search if prefix path changed - clear_if_changed(DirectX_PREFIX_PATH - DirectX_LIBRARY - DirectX_INCLUDE_DIR - ) - - find_path(DirectX_INCLUDE_DIR NAMES d3d9.h HINTS ${DirectX_INC_SEARCH_PATH}) - # dlls are in DirectX_ROOT_DIR/Developer Runtime/x64|x86 - # lib files are in DirectX_ROOT_DIR/Lib/x64|x86 - if(CMAKE_CL_64) - set(DirectX_LIBPATH_SUFFIX "x64") - else(CMAKE_CL_64) - set(DirectX_LIBPATH_SUFFIX "x86") - endif(CMAKE_CL_64) - find_library(DirectX_LIBRARY NAMES d3d9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) - find_library(DirectX_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) - find_library(DirectX_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) - find_library(DirectX_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) - - - # look for dxgi (needed by both 10 and 11) - find_library(DirectX_DXGI_LIBRARY NAMES dxgi HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) - - # look for d3dcompiler (needed by 11) - find_library(DirectX_D3DCOMPILER_LIBRARY NAMES d3dcompiler HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) - - findpkg_finish(DirectX) - set(DirectX_LIBRARIES ${DirectX_LIBRARIES} - ${DirectX_D3DX9_LIBRARY} - ${DirectX_DXERR_LIBRARY} - ${DirectX_DXGUID_LIBRARY} - ) - - mark_as_advanced(DirectX_D3DX9_LIBRARY DirectX_DXERR_LIBRARY DirectX_DXGUID_LIBRARY - DirectX_DXGI_LIBRARY DirectX_D3DCOMPILER_LIBRARY) - - - # look for D3D11 components - if (DirectX_FOUND) - find_path(DirectX_D3D11_INCLUDE_DIR NAMES D3D11Shader.h HINTS ${DirectX_INC_SEARCH_PATH}) - get_filename_component(DirectX_LIBRARY_DIR "${DirectX_LIBRARY}" PATH) - message(STATUS "DX lib dir: ${DirectX_LIBRARY_DIR}") - find_library(DirectX_D3D11_LIBRARY NAMES d3d11 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) - find_library(DirectX_D3DX11_LIBRARY NAMES d3dx11 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) - if (DirectX_D3D11_INCLUDE_DIR AND DirectX_D3D11_LIBRARY) - set(DirectX_D3D11_FOUND TRUE) - set(DirectX_D3D11_INCLUDE_DIR ${DirectX_D3D11_INCLUDE_DIR}) - set(DirectX_D3D11_LIBRARIES ${DirectX_D3D11_LIBRARIES} - ${DirectX_D3D11_LIBRARY} - ${DirectX_DXGI_LIBRARY} - ${DirectX_DXGUID_LIBRARY} - ${DirectX_D3DCOMPILER_LIBRARY} - ) - endif () - if (DirectX_D3DX11_LIBRARY) - set(DirectX_D3D11_LIBRARIES ${DirectX_D3D11_LIBRARIES} ${DirectX_D3DX11_LIBRARY}) - endif () - if (DirectX_DXERR_LIBRARY) - set(DirectX_D3D11_LIBRARIES ${DirectX_D3D11_LIBRARIES} ${DirectX_DXERR_LIBRARY}) - endif () - mark_as_advanced(DirectX_D3D11_INCLUDE_DIR DirectX_D3D11_LIBRARY DirectX_D3DX11_LIBRARY) - endif () - -endif(WIN32) diff -Nru corsix-th-0.30/CMake/FindFFmpeg.cmake corsix-th-0.62/CMake/FindFFmpeg.cmake --- corsix-th-0.30/CMake/FindFFmpeg.cmake 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CMake/FindFFmpeg.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -5,7 +5,6 @@ # FFMPEG_FOUND - System has the all required components. # FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. # FFMPEG_LIBRARIES - Link these to use the required ffmpeg components. -# FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components. # # For each of the components it will additionally set. # - AVCODEC @@ -16,130 +15,73 @@ # - SWSCALE # - SWRESAMPLE # the following variables will be defined -# _FOUND - System has -# _INCLUDE_DIRS - Include directory necessary for using the headers -# _LIBRARIES - Link these to use -# _DEFINITIONS - Compiler switches required for using -# _VERSION - The components version +# _FOUND - System has +# _INCLUDE_DIRS - Include directory necessary for using the headers +# _LIBRARIES - Link these to use +# _VERSION_STRING - The component's version # # Copyright (c) 2006, Matthias Kretz, # Copyright (c) 2008, Alexander Neundorf, # Copyright (c) 2011, Michael Jansen, # Copyright (c) 2013, Stephen Baker +# Copyright (c) 2015, Alexander Bessman # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. include(FindPackageHandleStandardArgs) +include(${CMAKE_CURRENT_LIST_DIR}/CMakeFFmpegLibavMacros.cmake) # The default components were taken from a survey over other FindFFMPEG.cmake files -if (NOT FFmpeg_FIND_COMPONENTS) +if(NOT FFmpeg_FIND_COMPONENTS) set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL) -endif () - -# -### Macro: set_component_found -# -# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present. -# -macro(set_component_found _component ) - if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) - # message(STATUS " - ${_component} found.") - set(${_component}_FOUND TRUE) - else () - # message(STATUS " - ${_component} not found.") - endif () -endmacro() - -# -### Macro: find_component -# -# Checks for the given component by invoking pkgconfig and then looking up the libraries and -# include directories. -# -macro(find_component _component _pkgconfig _library _header) - - if (NOT WIN32) - # use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(PC_${_component} ${_pkgconfig}) - endif () - endif (NOT WIN32) - - find_path(${_component}_INCLUDE_DIRS ${_header} - HINTS - ${PC_LIB${_component}_INCLUDEDIR} - ${PC_LIB${_component}_INCLUDE_DIRS} - PATH_SUFFIXES - ffmpeg - ) - - find_library(${_component}_LIBRARIES NAMES ${_library} - HINTS - ${PC_LIB${_component}_LIBDIR} - ${PC_LIB${_component}_LIBRARY_DIRS} - ) - - set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.") - set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.") - - set_component_found(${_component}) - -endmacro() - +endif() # Check for cached results. If there are skip the costly part. -if (NOT FFMPEG_LIBRARIES) +if(NOT FFMPEG_LIBRARIES) # Check for all possible component. - find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) - find_component(AVFORMAT libavformat avformat libavformat/avformat.h) - find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h) - find_component(AVUTIL libavutil avutil libavutil/avutil.h) - find_component(SWSCALE libswscale swscale libswscale/swscale.h) - find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h) - find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h) + find_component(AVCODEC avcodec libavcodec/avcodec.h libavcodec/version.h) + find_component(AVFORMAT avformat libavformat/avformat.h libavformat/version.h) + find_component(AVDEVICE avdevice libavdevice/avdevice.h libavdevice/version.h) + find_component(AVUTIL avutil libavutil/avutil.h libavutil/version.h) + find_component(SWSCALE swscale libswscale/swscale.h libswscale/version.h) + find_component(POSTPROC postproc libpostproc/postprocess.h libpostproc/version.h) + find_component(SWRESAMPLE swresample libswresample/swresample.h libswresample/version.h) # Check if the required components were found and add their stuff to the FFMPEG_* vars. - foreach (_component ${FFmpeg_FIND_COMPONENTS}) - if (${_component}_FOUND) + foreach(_component ${FFmpeg_FIND_COMPONENTS}) + if(${_component}_FOUND) # message(STATUS "Required component ${_component} present.") set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARIES}) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS}) list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) - else () + else() # message(STATUS "Required component ${_component} missing.") - endif () - endforeach () + endif() + endforeach() # Build the include path with duplicates removed. - if (FFMPEG_INCLUDE_DIRS) + if(FFMPEG_INCLUDE_DIRS) list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) - endif () + endif() # cache the vars. set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) - - mark_as_advanced(FFMPEG_INCLUDE_DIRS - FFMPEG_LIBRARIES - FFMPEG_DEFINITIONS) -endif () + mark_as_advanced(FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARIES) +endif() # Now set the noncached _FOUND vars for the components. -foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE SWRESAMPLE) +foreach(_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE SWRESAMPLE) set_component_found(${_component}) -endforeach () +endforeach() # Compile the list of required vars set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) -foreach (_component ${FFmpeg_FIND_COMPONENTS}) +foreach(_component ${FFmpeg_FIND_COMPONENTS}) list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS) -endforeach () +endforeach() # Give a nice error message if some of the required vars are missing. find_package_handle_standard_args(FFmpeg DEFAULT_MSG ${_FFmpeg_REQUIRED_VARS}) diff -Nru corsix-th-0.30/CMake/FindLibAV.cmake corsix-th-0.62/CMake/FindLibAV.cmake --- corsix-th-0.30/CMake/FindLibAV.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/FindLibAV.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,87 @@ +# vim: ts=2 sw=2 +# - Try to find the required libav components(default: AVFORMAT, AVUTIL, AVCODEC) +# +# Once done this will define +# LIBAV_FOUND - System has the all required components. +# LIBAV_INCLUDE_DIRS - Include directory necessary for using the required components headers. +# LIBAV_LIBRARIES - Link these to use the required libav components. +# +# For each of the components it will additionally set. +# - AVCODEC +# - AVDEVICE +# - AVFILTER +# - AVFORMAT +# - AVRESAMPLE +# - AVUTIL +# - SWSCALE +# the following variables will be defined +# _FOUND - System has +# _INCLUDE_DIRS - Include directory necessary for using the headers +# _LIBRARIES - Link these to use +# _VERSION_STRING - The component's version +# +# Copyright (c) 2006, Matthias Kretz, +# Copyright (c) 2008, Alexander Neundorf, +# Copyright (c) 2011, Michael Jansen, +# Copyright (c) 2013,2015 Stephen Baker +# Copyright (c) 2015, Alexander Bessman +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +include(FindPackageHandleStandardArgs) +include(${CMAKE_CURRENT_LIST_DIR}/CMakeFFmpegLibavMacros.cmake) + +# The default components were taken from a survey over other FindLIBAV.cmake files +if(NOT LibAV_FIND_COMPONENTS) + set(LibAV_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL) +endif() + +# Check for cached results. If there are skip the costly part. +if(NOT LIBAV_LIBRARIES) + + # Check for all possible component. + find_component(AVCODEC avcodec libavcodec/avcodec.h libavcodec/version.h) + find_component(AVFORMAT avformat libavformat/avformat.h libavformat/version.h) + find_component(AVDEVICE avdevice libavdevice/avdevice.h libavdevice/version.h) + find_component(AVFILTER avfilter libavfilter/avfilter.h libavfilter/version.h) + find_component(AVRESAMPLE avresample libavresample/avresample.h libavresample/version.h) + find_component(AVUTIL avutil libavutil/avutil.h libavutil/version.h) + find_component(SWSCALE swscale libswscale/swscale.h libswscale/version.h) + + # Check if the required components were found and add their stuff to the LIBAV_* vars. + foreach(_component ${LibAV_FIND_COMPONENTS}) + if(${_component}_FOUND) + # message(STATUS "Required component ${_component} present.") + set(LIBAV_LIBRARIES ${LIBAV_LIBRARIES} ${${_component}_LIBRARIES}) + list(APPEND LIBAV_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) + else() + # message(STATUS "Required component ${_component} missing.") + endif() + endforeach() + + # Build the include path with duplicates removed. + if(LIBAV_INCLUDE_DIRS) + list(REMOVE_DUPLICATES LIBAV_INCLUDE_DIRS) + endif() + + # cache the vars. + set(LIBAV_INCLUDE_DIRS ${LIBAV_INCLUDE_DIRS} CACHE STRING "The LibAV include directories." FORCE) + set(LIBAV_LIBRARIES ${LIBAV_LIBRARIES} CACHE STRING "The LibAV libraries." FORCE) + + mark_as_advanced(LIBAV_INCLUDE_DIRS LIBAV_LIBRARIES) +endif() + +# Now set the noncached _FOUND vars for the components. +foreach(_component AVCODEC AVDEVICE AVFILTER AVFORMAT AVRESAMPLE AVUTIL SWSCALE) + set_component_found(${_component}) +endforeach() + +# Compile the list of required vars +set(_LibAV_REQUIRED_VARS LIBAV_LIBRARIES LIBAV_INCLUDE_DIRS) +foreach(_component ${LibAV_FIND_COMPONENTS}) + list(APPEND _LibAV_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS) +endforeach() + +# Give a nice error message if some of the required vars are missing. +find_package_handle_standard_args(LibAV DEFAULT_MSG ${_LibAV_REQUIRED_VARS}) diff -Nru corsix-th-0.30/CMake/FindLua.cmake corsix-th-0.62/CMake/FindLua.cmake --- corsix-th-0.30/CMake/FindLua.cmake 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CMake/FindLua.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -# Copyright (c) 2013 Martin Felis <martin@fysx.org> -# License: Public Domain (Unlicense: http://unlicense.org/) -# Modified by Edvin "Lego3" Linge for the CorsixTH project. -# -# Try to find Lua or LuaJIT depending on the variable WITH_LUAJIT. -# Sets the following variables: -# Lua_FOUND -# LUA_INCLUDE_DIR -# LUA_LIBRARY -# -# Use it in a CMakeLists.txt script as: -# -# OPTION (WITH_LUAJIT "Use LuaJIT instead of default Lua" OFF) -# UNSET(Lua_FOUND CACHE) -# UNSET(LUA_INCLUDE_DIR CACHE) -# UNSET(LUA_LIBRARY CACHE) -# FIND_PACKAGE (Lua REQUIRED) - -SET (Lua_FOUND FALSE) - -SET (LUA_INTERPRETER_TYPE "") - -IF (WITH_LUAJIT) - SET (LUA_INTERPRETER_TYPE "LuaJIT") - SET (LUA_LIBRARY_NAME luajit-5.1) - SET (LUA_INCLUDE_DIRS include/luajit-2.0 include) -ELSE (WITH_LUAJIT) - SET (LUA_INTERPRETER_TYPE "Lua") - SET (LUA_LIBRARY_NAME lua5.1 lua51 lua lua-5.1) - SET (LUA_INCLUDE_DIRS include/lua5.1 include/lua51 include/lua include/lua-5.1 include) -ENDIF(WITH_LUAJIT) - -FIND_PATH (LUA_INCLUDE_DIR lua.h - HINTS - ENV LUA_DIR - PATH_SUFFIXES ${LUA_INCLUDE_DIRS} - PATHS - /opt/local - /usr/local - /usr - /opt - /sw - ~/Library/Frameworks - /Library/Frameworks -) -FIND_LIBRARY (LUA_LIBRARY NAMES ${LUA_LIBRARY_NAME} - HINTS - ENV LUA_DIR - PATH_SUFFIXES lib - PATHS - /usr - /usr/local - /opt/ocal - /opt - /sw - ~/Library/Frameworks - /Library/Frameworks -) - -IF (LUA_INCLUDE_DIR AND LUA_LIBRARY) - SET (Lua_FOUND TRUE) -ENDIF (LUA_INCLUDE_DIR AND LUA_LIBRARY) - -IF (Lua_FOUND) - IF (NOT Lua_FIND_QUIETLY) - MESSAGE(STATUS "Found ${LUA_INTERPRETER_TYPE} library: ${LUA_LIBRARY}") - ENDIF (NOT Lua_FIND_QUIETLY) -ELSE (Lua_FOUND) - IF (Lua_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find ${LUA_INTERPRETER_TYPE}") - ENDIF (Lua_FIND_REQUIRED) -ENDIF (Lua_FOUND) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua DEFAULT_MSG LUA_LIBRARY LUA_INCLUDE_DIR) - -MARK_AS_ADVANCED ( LUA_INCLUDE_DIR LUA_LIBRARY) diff -Nru corsix-th-0.30/CMake/FindPkgMacros.cmake corsix-th-0.62/CMake/FindPkgMacros.cmake --- corsix-th-0.30/CMake/FindPkgMacros.cmake 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CMake/FindPkgMacros.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -#------------------------------------------------------------------- -# This file was taken from the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -# -# FindDirectX.cmake is dependant on this file. -#------------------------------------------------------------------- - -################################################################## -# Provides some common functionality for the FindPackage modules -################################################################## - -# Begin processing of package -macro(findpkg_begin PREFIX) - if (NOT ${PREFIX}_FIND_QUIETLY) - message(STATUS "Looking for ${PREFIX}...") - endif () -endmacro(findpkg_begin) - -# Display a status message unless FIND_QUIETLY is set -macro(pkg_message PREFIX) - if (NOT ${PREFIX}_FIND_QUIETLY) - message(STATUS ${ARGN}) - endif () -endmacro(pkg_message) - -# Get environment variable, define it as ENV_$var and make sure backslashes are converted to forward slashes -macro(getenv_path VAR) - set(ENV_${VAR} $ENV{${VAR}}) - # replace won't work if var is blank - if (ENV_${VAR}) - string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} ) - endif () -endmacro(getenv_path) - -# Construct search paths for includes and libraries from a PREFIX_PATH -macro(create_search_paths PREFIX) - foreach(dir ${${PREFIX}_PREFIX_PATH}) - set(${PREFIX}_INC_SEARCH_PATH ${${PREFIX}_INC_SEARCH_PATH} - ${dir}/include ${dir}/Include ${dir}/include/${PREFIX} ${dir}/Headers) - set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH} - ${dir}/lib ${dir}/Lib ${dir}/lib/${PREFIX} ${dir}/Libs) - set(${PREFIX}_BIN_SEARCH_PATH ${${PREFIX}_BIN_SEARCH_PATH} - ${dir}/bin) - endforeach(dir) - set(${PREFIX}_FRAMEWORK_SEARCH_PATH ${${PREFIX}_PREFIX_PATH}) -endmacro(create_search_paths) - -# clear cache variables if a certain variable changed -macro(clear_if_changed TESTVAR) - # test against internal check variable - # HACK: Apparently, adding a variable to the cache cleans up the list - # a bit. We need to also remove any empty strings from the list, but - # at the same time ensure that we are actually dealing with a list. - list(APPEND ${TESTVAR} "") - list(REMOVE_ITEM ${TESTVAR} "") - if (NOT "${${TESTVAR}}" STREQUAL "${${TESTVAR}_INT_CHECK}") - message(STATUS "${TESTVAR} changed.") - foreach(var ${ARGN}) - set(${var} "NOTFOUND" CACHE STRING "x" FORCE) - endforeach(var) - endif () - set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE) -endmacro(clear_if_changed) - -# Try to get some hints from pkg-config, if available -macro(use_pkgconfig PREFIX PKGNAME) - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(${PREFIX} ${PKGNAME}) - endif () -endmacro (use_pkgconfig) - -# Couple a set of release AND debug libraries (or frameworks) -macro(make_library_set PREFIX) - if (${PREFIX}_FWK) - set(${PREFIX} ${${PREFIX}_FWK}) - elseif (${PREFIX}_REL AND ${PREFIX}_DBG) - set(${PREFIX} optimized ${${PREFIX}_REL} debug ${${PREFIX}_DBG}) - elseif (${PREFIX}_REL) - set(${PREFIX} ${${PREFIX}_REL}) - elseif (${PREFIX}_DBG) - set(${PREFIX} ${${PREFIX}_DBG}) - endif () -endmacro(make_library_set) - -# Generate debug names from given release names -macro(get_debug_names PREFIX) - foreach(i ${${PREFIX}}) - set(${PREFIX}_DBG ${${PREFIX}_DBG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i}) - endforeach(i) -endmacro(get_debug_names) - -# Add the parent dir from DIR to VAR -macro(add_parent_dir VAR DIR) - get_filename_component(${DIR}_TEMP "${${DIR}}/.." ABSOLUTE) - set(${VAR} ${${VAR}} ${${DIR}_TEMP}) -endmacro(add_parent_dir) - -# Do the final processing for the package find. -macro(findpkg_finish PREFIX) - # skip if already processed during this run - if (NOT ${PREFIX}_FOUND) - if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) - set(${PREFIX}_FOUND TRUE) - set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) - set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) - if (NOT ${PREFIX}_FIND_QUIETLY) - message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}") - endif () - else () - if (NOT ${PREFIX}_FIND_QUIETLY) - message(STATUS "Could not locate ${PREFIX}") - endif () - if (${PREFIX}_FIND_REQUIRED) - message(FATAL_ERROR "Required library ${PREFIX} not found! Install the library (including dev packages) and try again. If the library is already installed, set the missing variables manually in cmake.") - endif () - endif () - - mark_as_advanced(${PREFIX}_INCLUDE_DIR ${PREFIX}_LIBRARY ${PREFIX}_LIBRARY_REL ${PREFIX}_LIBRARY_DBG ${PREFIX}_LIBRARY_FWK) - endif () -endmacro(findpkg_finish) - - -# Slightly customised framework finder -macro(findpkg_framework fwk) - if(APPLE) - set(${fwk}_FRAMEWORK_PATH - ${${fwk}_FRAMEWORK_SEARCH_PATH} - ${CMAKE_FRAMEWORK_PATH} - ~/Library/Frameworks - /Library/Frameworks - /System/Library/Frameworks - /Network/Library/Frameworks - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Release - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug - ) - # These could be arrays of paths, add each individually to the search paths - foreach(i ${OGRE_PREFIX_PATH}) - set(${fwk}_FRAMEWORK_PATH ${${fwk}_FRAMEWORK_PATH} ${i}/lib/Release ${i}/lib/Debug) - endforeach(i) - - foreach(i ${OGRE_PREFIX_BUILD}) - set(${fwk}_FRAMEWORK_PATH ${${fwk}_FRAMEWORK_PATH} ${i}/lib/Release ${i}/lib/Debug) - endforeach(i) - - foreach(dir ${${fwk}_FRAMEWORK_PATH}) - set(fwkpath ${dir}/${fwk}.framework) - if(EXISTS ${fwkpath}) - set(${fwk}_FRAMEWORK_INCLUDES ${${fwk}_FRAMEWORK_INCLUDES} - ${fwkpath}/Headers ${fwkpath}/PrivateHeaders) - set(${fwk}_FRAMEWORK_PATH ${dir}) - if (NOT ${fwk}_LIBRARY_FWK) - set(${fwk}_LIBRARY_FWK "-framework ${fwk}") - endif () - endif(EXISTS ${fwkpath}) - endforeach(dir) - endif(APPLE) -endmacro(findpkg_framework) diff -Nru corsix-th-0.30/CMake/FindSDL2.cmake corsix-th-0.62/CMake/FindSDL2.cmake --- corsix-th-0.30/CMake/FindSDL2.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/FindSDL2.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,158 @@ +# - Locate SDL2 library +# This module defines +# SDL_LIBRARY, the name of the library to link against +# SDL_FOUND, if false, do not try to link to SDL +# SDL_INCLUDE_DIR, where to find SDL.h +# SDL_VERSION_STRING, human-readable string containing the version of SDL +# +# This module responds to the the flag: +# SDL_BUILDING_LIBRARY +# If this is defined, then no SDL_main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL_LIBRARY variable. +# +# Don't forget to include SDL_main.h and SDLmain.m your project for the +# OS X framework based version. (Other versions link to -lSDLmain which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL_LIBRARY_TEMP in your configuration +# and no SDL_LIBRARY, it means CMake did not find your SDL library +# (SDL2.dll, libSDL2.so, SDL2.framework, etc). +# Set SDL_LIBRARY_TEMP to point to your SDL library, and configure again. +# Similarly, if you see an empty SDLMAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL_LIBRARY +# variable, but when these values are unset, SDL_LIBRARY does not get created. +# +# +# $SDLDIR is an environment variable that would +# correspond to the ./configure --prefix=$SDLDIR +# used in building SDL. +# l.e.galup 9-20-02 + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# Copyright 2012 Benjamin Eikel +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +find_path(SDL_INCLUDE_DIR SDL.h + HINTS + ENV SDLDIR + PATH_SUFFIXES include/SDL2 include +) + +find_library(SDL_LIBRARY_TEMP + NAMES SDL2 + HINTS + ENV SDLDIR + PATH_SUFFIXES lib +) + +if(NOT SDL_BUILDING_LIBRARY) + if(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + find_library(SDLMAIN_LIBRARY + NAMES SDL2main + HINTS + ENV SDLDIR + PATH_SUFFIXES lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) + endif() +endif() + +# SDL may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +if(NOT APPLE) + find_package(Threads) +endif() + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +if(MINGW) + set(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +endif() + +if(SDL_LIBRARY_TEMP) + # For SDL2main + if(SDLMAIN_LIBRARY AND NOT SDL_BUILDING_LIBRARY) + list(FIND SDL_LIBRARY_TEMP "${SDLMAIN_LIBRARY}" _SDL_MAIN_INDEX) + if(_SDL_MAIN_INDEX EQUAL -1) + set(SDL_LIBRARY_TEMP "${SDLMAIN_LIBRARY}" ${SDL_LIBRARY_TEMP}) + endif() + unset(_SDL_MAIN_INDEX) + endif() + + # For OS X, SDL uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + if(APPLE) + set(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} "-framework Cocoa") + endif() + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + if(NOT APPLE) + set(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + endif() + + # For MinGW library + if(MINGW) + set(SDL_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL_LIBRARY_TEMP}) + endif() + + # Set the final string here so the GUI reflects the final state. + set(SDL_LIBRARY ${SDL_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + set(SDL_LIBRARY_TEMP "${SDL_LIBRARY_TEMP}" CACHE INTERNAL "") +endif() + +if(SDL_INCLUDE_DIR AND EXISTS "${SDL_INCLUDE_DIR}/SDL_version.h") + file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_VERSION_MAJOR "${SDL_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_VERSION_MINOR "${SDL_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_VERSION_PATCH "${SDL_VERSION_PATCH_LINE}") + set(SDL_VERSION_STRING ${SDL_VERSION_MAJOR}.${SDL_VERSION_MINOR}.${SDL_VERSION_PATCH}) + unset(SDL_VERSION_MAJOR_LINE) + unset(SDL_VERSION_MINOR_LINE) + unset(SDL_VERSION_PATCH_LINE) + unset(SDL_VERSION_MAJOR) + unset(SDL_VERSION_MINOR) + unset(SDL_VERSION_PATCH) +endif() + +#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(SDL + REQUIRED_VARS SDL_LIBRARY SDL_INCLUDE_DIR + VERSION_VAR SDL_VERSION_STRING +) diff -Nru corsix-th-0.30/CMake/FindSDL2_mixer.cmake corsix-th-0.62/CMake/FindSDL2_mixer.cmake --- corsix-th-0.30/CMake/FindSDL2_mixer.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/FindSDL2_mixer.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,89 @@ +# - Locate SDL_mixer library +# This module defines: +# SDL_MIXER_LIBRARIES, the name of the library to link against +# SDL_MIXER_INCLUDE_DIRS, where to find the headers +# SDL_MIXER_FOUND, if false, do not try to link against +# SDL_MIXER_VERSION_STRING - human-readable string containing the version of SDL_mixer +# +# For backward compatibility the following variables are also set: +# SDLMIXER_LIBRARY (same value as SDL_MIXER_LIBRARIES) +# SDLMIXER_INCLUDE_DIR (same value as SDL_MIXER_INCLUDE_DIRS) +# SDLMIXER_FOUND (same value as SDL_MIXER_FOUND) +# +# $SDLDIR is an environment variable that would +# correspond to the ./configure --prefix=$SDLDIR +# used in building SDL. +# +# Created by Eric Wing. This was influenced by the FindSDL.cmake +# module, but with modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). + +#============================================================================= +# Copyright 2005-2009 Kitware, Inc. +# Copyright 2012 Benjamin Eikel +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if(NOT SDL_MIXER_INCLUDE_DIR AND SDLMIXER_INCLUDE_DIR) + set(SDL_MIXER_INCLUDE_DIR ${SDLMIXER_INCLUDE_DIR} CACHE PATH "directory cache +entry initialized from old variable name") +endif() +find_path(SDL_MIXER_INCLUDE_DIR SDL_mixer.h + HINTS + ENV SDLMIXERDIR + ENV SDLDIR + PATH_SUFFIXES include/SDL2 include +) + +if(NOT SDL_MIXER_LIBRARY AND SDLMIXER_LIBRARY) + set(SDL_MIXER_LIBRARY ${SDLMIXER_LIBRARY} CACHE FILEPATH "file cache entry +initialized from old variable name") +endif() +find_library(SDL_MIXER_LIBRARY + NAMES SDL2_mixer + HINTS + ENV SDLMIXERDIR + ENV SDLDIR + PATH_SUFFIXES lib +) + +if(SDL_MIXER_INCLUDE_DIR AND EXISTS "${SDL_MIXER_INCLUDE_DIR}/SDL_mixer.h") + file(STRINGS "${SDL_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL_MIXER_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL_MIXER_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL_MIXER_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_MAJOR "${SDL_MIXER_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_MINOR "${SDL_MIXER_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_PATCH "${SDL_MIXER_VERSION_PATCH_LINE}") + set(SDL_MIXER_VERSION_STRING ${SDL_MIXER_VERSION_MAJOR}.${SDL_MIXER_VERSION_MINOR}.${SDL_MIXER_VERSION_PATCH}) + unset(SDL_MIXER_VERSION_MAJOR_LINE) + unset(SDL_MIXER_VERSION_MINOR_LINE) + unset(SDL_MIXER_VERSION_PATCH_LINE) + unset(SDL_MIXER_VERSION_MAJOR) + unset(SDL_MIXER_VERSION_MINOR) + unset(SDL_MIXER_VERSION_PATCH) +endif() + +set(SDL_MIXER_LIBRARIES ${SDL_MIXER_LIBRARY}) +set(SDL_MIXER_INCLUDE_DIRS ${SDL_MIXER_INCLUDE_DIR}) + +#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(SDL_mixer + REQUIRED_VARS SDL_MIXER_LIBRARIES SDL_MIXER_INCLUDE_DIRS + VERSION_VAR SDL_MIXER_VERSION_STRING +) + +# for backward compatibility +set(SDLMIXER_LIBRARY ${SDL_MIXER_LIBRARIES}) +set(SDLMIXER_INCLUDE_DIR ${SDL_MIXER_INCLUDE_DIRS}) +set(SDLMIXER_FOUND ${SDL_MIXER_FOUND}) + diff -Nru corsix-th-0.30/CMake/FindVLD.cmake corsix-th-0.62/CMake/FindVLD.cmake --- corsix-th-0.30/CMake/FindVLD.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/FindVLD.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,49 @@ +## Try to find Visual Leak Debugger library (VDL) +## http://vld.codeplex.com +## +## Sets the following variables: +## VLD_FOUND +## VLD_INCLUDE_DIR +## VLD_LIBRARY +## +## Stephen E. Baker 2014 +set(VLD_FOUND FALSE) + +if(${CMAKE_SIZEOF_VOID_P} MATCHES 8) + set (VLD_LIB_SUBDIRS lib/Win64 lib) +else() + set (VLD_LIB_SUBDIRS lib/Win32 lib) +endif() + +set(PROG_FILES_X86_ENV "PROGRAMFILES(X86)") +set(PROG_FILES_ENV "PROGRAMFILES") + +find_path(VLD_INCLUDE_DIR vld.h + HINTS + ENV VLD_HOME + PATH_SUFFIXES include + PATHS + "$ENV{${PROG_FILES_X86_ENV}}/Visual Leak Detector" + "$ENV{${PROG_FILES_ENV}}/Visual Leak Detector" +) + +find_library(VLD_LIBRARY NAMES vld + HINTS + ENV VLD_HOME + PATH_SUFFIXES ${VLD_LIB_SUBDIRS} + PATHS + "$ENV{${PROG_FILES_X86_ENV}}/Visual Leak Detector" + "$ENV{${PROG_FILES_ENV}}/Visual Leak Detector" +) + +if(VLD_INCLUDE_DIR AND VLD_LIBRARY) + set(VLD_FOUND TRUE) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(VLD DEFAULT_MSG VLD_LIBRARY VLD_INCLUDE_DIR) + +mark_as_advanced( + VLD_INCLUDE_DIR + VLD_LIBRARY +) diff -Nru corsix-th-0.30/CMake/GenerateDoc.cmake corsix-th-0.62/CMake/GenerateDoc.cmake --- corsix-th-0.30/CMake/GenerateDoc.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/GenerateDoc.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,85 @@ +# Find doxygen. +find_package(Doxygen) + +# Generate build targets and the doc/index.html file. +if(DOXYGEN_FOUND OR LUA_PROGRAM_FOUND) + add_custom_target(doc) +else() + message("Cannot locate Doxygen or lua, 'doc' target is not available") +endif() + +# Add sub-targets of the 'doc' target. +if(DOXYGEN_FOUND) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DoxyGen/animview.doxygen.in + ${CMAKE_CURRENT_BINARY_DIR}/DoxyGen/animview.doxygen @ONLY) + + add_custom_target(doc_animview + ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/DoxyGen/animview.doxygen + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc + COMMENT "Generating API documentation for AnimView" VERBATIM + ) + add_dependencies(doc doc_animview) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DoxyGen/leveledit.doxygen.in + ${CMAKE_CURRENT_BINARY_DIR}/DoxyGen/leveledit.doxygen @ONLY) + + add_custom_target(doc_leveledit + ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/DoxyGen/leveledit.doxygen + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc + COMMENT "Generating API documentation for LevelEdit" VERBATIM + ) + add_dependencies(doc doc_leveledit) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DoxyGen/corsixth_engine.doxygen.in + ${CMAKE_CURRENT_BINARY_DIR}/DoxyGen/corsixth_engine.doxygen @ONLY) + + add_custom_target(doc_corsixth_engine + ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/DoxyGen/corsixth_engine.doxygen + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc + COMMENT "Generating API documentation for corsixth_engine" VERBATIM + ) + add_dependencies(doc doc_corsixth_engine) +endif() + +if(LUA_PROGRAM_FOUND) + add_custom_target(doc_corsixth_lua + ${LUA_PROGRAM_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/LDocGen/main.lua + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/LDocGen/output/corner_right.gif ${CMAKE_CURRENT_BINARY_DIR}/doc/corsixth_lua + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/LDocGen/output/logo.png ${CMAKE_CURRENT_BINARY_DIR}/doc/corsixth_lua + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/LDocGen/output/main.css ${CMAKE_CURRENT_BINARY_DIR}/doc/corsixth_lua + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc + COMMENT "Generating API documentation for corsixth_lua" VERBATIM + ) + add_dependencies(doc doc_corsixth_lua) +endif() + +# Generate doc/index.html file. +if(DOXYGEN_FOUND OR LUA_PROGRAM_FOUND) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "CorsixTH source code documentation\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "

CorsixTH main program source code documentation

\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "
    \n") +endif() + +if(DOXYGEN_FOUND) + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "
  • CorsixTH engine documentation\n") +endif() + +if(LUA_PROGRAM_FOUND) + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "
  • CorsixTH Lua documentation\n") +endif() + +if(DOXYGEN_FOUND) + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "
\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "

CorsixTH helper programs source code documentation

\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "
    \n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "
  • Animation viewer documentation\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "
  • Level editor documentation\n") +endif() + +if(DOXYGEN_FOUND OR LUA_PROGRAM_FOUND) + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "
\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/index.html "\n") +endif() diff -Nru corsix-th-0.30/CMake/PrecompiledDeps.cmake corsix-th-0.62/CMake/PrecompiledDeps.cmake --- corsix-th-0.30/CMake/PrecompiledDeps.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/PrecompiledDeps.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,105 @@ +# Copyright (c) 2017 David Fairbrother +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Clones and sets any dependencies up +include(ExternalProject) + +# Inform CMake about the external project +set(_DEPS_PROJECT_NAME PrecompiledDependencies) + +# Place files into ./precompiled_deps folder +set(PRECOMPILED_DEPS_BASE_DIR ${PROJECT_SOURCE_DIR}/PrecompiledDeps CACHE PATH "Destination for pre-built dependencies") +set(_DEPS_GIT_URL "https://github.com/CorsixTH/deps.git") +# Select the optimal dependencies commit regardless where master is. +set(_DEPS_GIT_SHA "a23eb28bb8998b93215eccf805ee5462d75a57f2") + +ExternalProject_Add(${_DEPS_PROJECT_NAME} + PREFIX ${PRECOMPILED_DEPS_BASE_DIR} + GIT_REPOSITORY ${_DEPS_GIT_URL} + GIT_TAG ${_DEPS_GIT_SHA} + # As the deps are already build we can skip these + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) + +unset(_DEPS_GIT_URL) +unset(_DEPS_GIT_SHA) + +# Make sure the final make file / solution does not attempt to build +# the dependencies target +set_target_properties(${_DEPS_PROJECT_NAME} PROPERTIES + EXCLUDE_FROM_ALL 1 + EXCLUDE_FROM_DEFAULT_BUILD 1 +) + +set(_DEPS_TMP_PATH ${PRECOMPILED_DEPS_BASE_DIR}/tmp) +set(_DEPS_MODULES_TEMPLATE_NAME ${_DEPS_TMP_PATH}/${_DEPS_PROJECT_NAME}) + +# Clone if we don't have the deps +if(NOT EXISTS ${PRECOMPILED_DEPS_BASE_DIR}/src/${_DEPS_PROJECT_NAME}/.git) + message(STATUS "Getting Precompiled Dependencies...") + execute_process(COMMAND ${CMAKE_COMMAND} ARGS -P + ${_DEPS_MODULES_TEMPLATE_NAME}-gitclone.cmake + RESULT_VARIABLE return_value + ) + if(return_value) + message(FATAL_ERROR "Failed to clone precompiled dependencies.") + endif() + +# Deps exist, check for updates and checkout the correct tag +else() + message(STATUS "Checking for Precompiled Dependency Updates...") + execute_process(COMMAND ${CMAKE_COMMAND} ARGS -P + ${_DEPS_MODULES_TEMPLATE_NAME}-gitupdate.cmake + RESULT_VARIABLE return_value + ) + if(return_value) + message(FATAL_ERROR "Failed to update precompiled dependencies.") + endif() +endif() + +# We can dispose of tmp and modules template name afterwards +unset(_DEPS_TMP_PATH) +unset(_DEPS_MODULES_TEMPLATE_NAME) + +# Determine the appropriate libs to use for this compiler +if(UNIX AND CMAKE_COMPILER_IS_GNU) + # We need user to choose which arch they are intending to compile for + set(DEPS_ARCH "x86" CACHE STRING "Architecture of precompiled dependencies to use.") + set_property(CACHE DEPS_ARCH + PROPERTY STRINGS "x86" "x64" + ) + # Generate the folder to use + set(_DEPS_FOLDER_NAME "gnu-linux-" + ${DEPS_ARCH}) +else() + message(FATAL_ERROR "Precompiled dependencies do not exist for this platform / compiler combination yet.") +endif() + +set(_DEPS_PATH ${PRECOMPILED_DEPS_BASE_DIR}/src/${_DEPS_PROJECT_NAME}/${_DEPS_FOLDER_NAME}) + +# Update the prefix path - this refers to the base directory that find_xx +# commands use. For example using find_include would automatically append +# the 'include' subdirectory in. +set(CMAKE_PREFIX_PATH ${_DEPS_PATH}) + +unset(_DEPS_FOLDER_NAME) +unset(_DEPS_PATH) diff -Nru corsix-th-0.30/CMake/VcpkgDeps.cmake corsix-th-0.62/CMake/VcpkgDeps.cmake --- corsix-th-0.30/CMake/VcpkgDeps.cmake 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CMake/VcpkgDeps.cmake 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,62 @@ +# Copyright (c) 2017 David Fairbrother +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +set(VCPKG_COMMIT_SHA "98f9c98f8e16beb48df802549a14df997bd38198") + +# Setup the various paths we are using +set(_VCPKG_SCRIPT_NAME "build_vcpkg_deps.ps1") +set(_SCRIPT_DIR ${CMAKE_SOURCE_DIR}/scripts) +# By default place VCPKG into root folder +set(VCPKG_PARENT_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Destination for vcpkg dependencies") + +# Determine the args to use +if(VCPKG_TARGET_TRIPLET) + set(_VCPKG_TARGET_TRIPLET ${VCPKG_TARGET_TRIPLET}) +elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Xx]64$" OR CMAKE_GENERATOR MATCHES "Win64$") + set(_VCPKG_TARGET_TRIPLET "x64-windows") +elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Aa][Rr][Mm]$" OR CMAKE_GENERATOR MATCHES "ARM$") + set(_VCPKG_TARGET_TRIPLET "arm-windows") +else() + set(_VCPKG_TARGET_TRIPLET "x86-windows") +endif() + +set(_VCPKG_ARGS "-VcpkgTriplet " ${_VCPKG_TARGET_TRIPLET}) + +if(BUILD_ANIMVIEWER) + string(CONCAT _VCPKG_ARGS ${_VCPKG_ARGS} " -BuildAnimView $True") +else() + string(CONCAT _VCPKG_ARGS ${_VCPKG_ARGS} " -BuildAnimView $False") +endif() + +string(CONCAT _VCPKG_ARGS ${_VCPKG_ARGS} " -VcpkgCommitSha " ${VCPKG_COMMIT_SHA} " ") + +# Run the build script +set(_SCRIPT_COMMAND powershell ${_SCRIPT_DIR}/${_VCPKG_SCRIPT_NAME}) +execute_process(WORKING_DIRECTORY ${VCPKG_PARENT_DIR} + COMMAND ${_SCRIPT_COMMAND} ${_VCPKG_ARGS} + RESULT_VARIABLE err_val +) +if(err_val) + message(FATAL_ERROR "Failed to build vcpkg dependencies. " + "\nIf this error persists try deleting the 'vcpkg' folder.\n") +endif() + +set(VCPKG_INSTALLED_PATH ${VCPKG_PARENT_DIR}/vcpkg/installed/${_VCPKG_TARGET_TRIPLET}) +set(CMAKE_TOOLCHAIN_FILE ${VCPKG_PARENT_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake) diff -Nru corsix-th-0.30/CMakeLists.txt corsix-th-0.62/CMakeLists.txt --- corsix-th-0.30/CMakeLists.txt 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CMakeLists.txt 2018-07-21 11:13:17.000000000 +0000 @@ -2,110 +2,122 @@ # OPTIONS AVAILABLE: # At most, one of the following: # - WITH_SDL : Activate SDL Renderer (default) -# - WITH_OPENGL : Activate OpenGL Renderer -# - WITH_DIRECTX : Activate DirectX Renderer (Windows only) # Any of the following: # - WITH_AUDIO : Activate Sound (enabled by default) # - WITH_FREETYPE2 # - WITH_MOVIES : Activate movies (requires Sound) # - BUILD_ANIMVIEWER -# - BUILD_MAPEDITOR # - WITH_LUAJIT : Whether to use LuaJIT 2 instead of Lua51 (default is LuaJIT 2) +# - WITH_LIBAV : Whether to use LibAV (as opposed to FFMEPG) when building movies +# - WITH_VLD : Build with Visual Leak Detector (requires Visual Studio) -PROJECT(CorsixTH_Top_Level) -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMake) -IF(MSVC) - SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "/INCREMENTAL" CACHE STRING "Linker flags for release" FORCE) - SET(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "/INCREMENTAL" CACHE STRING "Linker flags for minsizerel" FORCE) -ENDIF(MSVC) -INCLUDE(CheckIncludeFiles) -SET(CORSIX_TH_DONE_TOP_LEVEL_CMAKE ON) - -IF (APPLE) - SET(CMAKE_OSX_DEPLOYMENT_TARGET 10.5) -ENDIF() +cmake_minimum_required(VERSION 3.2) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMake) + +if(CMAKE_GENERATOR MATCHES "^Visual Studio 14 2015" OR CMAKE_GENERATOR MATCHES "^Visual Studio 15 2017") + option(USE_VCPKG_DEPS "Build vcpkg dependencies locally" OFF) +endif() + +if(USE_VCPKG_DEPS) + message("Note: Using locally built vcpkg dependencies.") + include(VcpkgDeps) +endif() + +project(CorsixTH_Top_Level) + +include(CheckCXXCompilerFlag) +check_cxx_compiler_flag("-std=c++11" COMPILER_SUPPORTS_CXX11) +check_cxx_compiler_flag("-std=c++0x" COMPILER_SUPPORTS_CXX0X) +if(COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +elseif(COMPILER_SUPPORTS_CXX0X) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +endif() + +if(MINGW) + set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++") +endif() + +include(CheckIncludeFiles) + +set(CORSIX_TH_DONE_TOP_LEVEL_CMAKE ON) + +# Dependency management +if(UNIX AND CMAKE_COMPILER_IS_GNU) + option(USE_PRECOMPILED_DEPS "Use Precompiled Dependencies" OFF) # Make *nix systems opt in +endif() # Define our options -OPTION(WITH_OPENGL "Activate OpenGL Renderer" OFF) -OPTION(WITH_DIRECTX "Activate DirectX Renderer" OFF) -OPTION(WITH_SDL "Activate SDL Renderer" ON) # our default option -OPTION(WITH_AUDIO "Activate Sound" ON) # enabled by default -OPTION(WITH_MOVIES "Activate in game movies" ON) -OPTION(WITH_FREETYPE2 "Enhanced Font Support" ON) -OPTION(WITH_LUAJIT "Use LuaJIT instead of Lua" ON) -OPTION(BUILD_ANIMVIEWER "Build the animation viewer as part of the build process" OFF) -OPTION(BUILD_MAPEDITOR "Build the map editor as part of the build process" OFF) - -# Option handling -IF(WITH_OPENGL) - SET(CORSIX_TH_USE_DX9_RENDERER OFF) - SET(CORSIX_TH_USE_SDL_RENDERER OFF) - SET(CORSIX_TH_USE_OGL_RENDERER ON) - MESSAGE("Note: Using OpenGL as renderer") -ENDIF(WITH_OPENGL) - -IF(WITH_DIRECTX) -# DirectX will only work with win32. If we're not win32, we use OpenGL instead -IF(WIN32) - SET(CORSIX_TH_USE_DX9_RENDERER ON) - SET(CORSIX_TH_USE_SDL_RENDERER OFF) - SET(CORSIX_TH_USE_OGL_RENDERER OFF) - MESSAGE("Note: Using DirectX as renderer") -ELSE() - SET(CORSIX_TH_USE_DX9_RENDERER OFF) - SET(CORSIX_TH_USE_SDL_RENDERER OFF) - SET(CORSIX_TH_USE_OGL_RENDERER ON) - MESSAGE("Note: Cannot use DirectX due to OS, using OpenGL instead") -ENDIF(WIN32) -ENDIF(WITH_DIRECTX) - -IF(NOT WITH_OPENGL) -IF(NOT WITH_DIRECTX) -IF(WITH_SDL) - SET(CORSIX_TH_USE_DX9_RENDERER OFF) - SET(CORSIX_TH_USE_SDL_RENDERER ON) - SET(CORSIX_TH_USE_OGL_RENDERER OFF) - MESSAGE("Note: Using SDL as renderer (default)") -ENDIF(WITH_SDL) -ENDIF(NOT WITH_DIRECTX) -ENDIF(NOT WITH_OPENGL) - -IF(WITH_AUDIO) - SET(CORSIX_TH_USE_SDL_MIXER ON) - MESSAGE("Note: SDL audio is enabled (default)") -ELSE() - SET(CORSIX_TH_USE_SDL_MIXER OFF) - MESSAGE("Note: SDL audio is disabled") -ENDIF(WITH_AUDIO) - -IF(WITH_MOVIES) - IF(WITH_AUDIO) - SET(CORSIX_TH_USE_FFMPEG ON) - MESSAGE("Note: FFMPEG video is enabled (default)") - ELSE() - SET(CORSIX_TH_USE_FFMPEG OFF) - MESSAGE("Note: FFMPEG video disabled since it requires SDL audio.") - ENDIF(WITH_AUDIO) -ELSE() - SET(CORSIX_TH_USE_FFMPEG OFF) - MESSAGE("Note: FFMPEG video is disabled") -ENDIF(WITH_MOVIES) - -IF(WITH_FREETYPE2) - SET(CORSIX_TH_USE_FREETYPE2 ON) - MESSAGE("Note: FreeType2 is enabled (default)") -ELSE() - SET(CORSIX_TH_USE_FREETYPE2 OFF) - MESSAGE("Note: FreeType2 is disabled") -ENDIF(WITH_FREETYPE2) - -# Environment handling - -CHECK_INCLUDE_FILES(stdint.h CORSIX_TH_HAS_STDINT_H) -CHECK_INCLUDE_FILES(malloc.h CORSIX_TH_HAS_MALLOC_H) -CHECK_INCLUDE_FILES(alloca.h CORSIX_TH_HAS_ALLOCA_H) -CHECK_INCLUDE_FILES(inttypes.h CORSIX_TH_HAS_INTTYPES_H) +option(USE_SOURCE_DATADIRS "Use the source directory for loading resources. Incompatible with the install target" OFF) +option(WITH_SDL "Activate SDL Renderer" ON) # our default option +option(WITH_AUDIO "Activate Sound" ON) # enabled by default +option(WITH_MOVIES "Activate in game movies" ON) +option(WITH_FREETYPE2 "Enhanced Font Support" ON) +option(WITH_LUAJIT "Use LuaJIT instead of Lua" OFF) +option(WITH_LIBAV "Use LibAV instead of FFmpeg" OFF) +option(BUILD_ANIMVIEWER "Build the animation viewer as part of the build process" OFF) +if(MSVC) + option(WITH_VLD "Build with Visual Leak Detector for Visual Studio" OFF) +endif() + +if(WITH_AUDIO) + set(CORSIX_TH_USE_SDL_MIXER ON) + message("Note: SDL audio is enabled (default)") +else() + set(CORSIX_TH_USE_SDL_MIXER OFF) + message("Note: SDL audio is disabled") +endif() + +if(WITH_MOVIES) + if(WITH_AUDIO) + if(WITH_LIBAV) + set(CORSIX_TH_USE_FFMPEG OFF) + set(CORSIX_TH_USE_LIBAV ON) + message("Note: LibAV video is enabled") + else() + set(CORSIX_TH_USE_FFMPEG ON) + set(CORSIX_TH_USE_LIBAV OFF) + message("Note: FFMPEG video is enabled (default)") + endif() + else() + set(CORSIX_TH_USE_FFMPEG OFF) + set(CORSIX_TH_USE_LIBAV OFF) + message("Note: FFMPEG video disabled since it requires SDL audio.") + endif() +else() + set(CORSIX_TH_USE_FFMPEG OFF) + set(CORSIX_TH_USE_LIBAV OFF) + message("Note: FFMPEG video is disabled") +endif() + +if(WITH_FREETYPE2) + set(CORSIX_TH_USE_FREETYPE2 ON) + message("Note: FreeType2 is enabled (default)") +else() + set(CORSIX_TH_USE_FREETYPE2 OFF) + message("Note: FreeType2 is disabled") +endif() + +if(MSVC) + if(WITH_VLD) + set(CORSIX_TH_USE_VLD ON) + message("Note: Visual Leak Detector is enabled") + else() + set(CORSIX_TH_USE_VLD OFF) + message("Note: Visual Leak Detector is disabled (default)") + endif() +else() + set(CORSIX_TH_USE_VLD OFF) +endif() + +# Get precompiled dependencies before running the various find modules +if(USE_PRECOMPILED_DEPS) + message("Note: Using precompiled dependencies.") + include(PrecompiledDeps) +endif() + +include(GNUInstallDirs) # Include individual projects message("") @@ -113,16 +125,34 @@ message("Building CorsixTH") add_subdirectory(CorsixTH) -IF(BUILD_ANIMVIEWER) +if(BUILD_ANIMVIEWER) message("Building AnimView") add_subdirectory(AnimView) -ENDIF(BUILD_ANIMVIEWER) +endif() + +# Documentation generation, construct 'doc' target (or a message it is disabled). + +# Try to find 'lua' +if(WITH_LUAJIT) + set(LUA_PROGRAM_NAMES luajit-2.0.3 luajit) +else() + set(LUA_PROGRAM_NAMES lua53 lua5.3 lua-5.3 lua52 lua5.2 lua-5.2 lua51 lua5.1 lua-5.1 lua) +endif() + +find_program(LUA_PROGRAM_PATH ${LUA_PROGRAM_NAMES} + PATHS + ENV LUA_DIR + /opt + /opt/local + ~ + ~/Library/Frameworks + /Library/Frameworks +) + +if(LUA_PROGRAM_PATH) + set(LUA_PROGRAM_FOUND TRUE) +else() + set(LUA_PROGRAM_FOUND FALSE) +endif() -IF(BUILD_MAPEDITOR) - IF(WITH_OPENGL) - message("Building MapEdit") - add_subdirectory(MapEdit) - ELSE(WITH_OPENGL) - message(FATAL_ERROR "The map editor can only be built when using OpenGL as renderer") - ENDIF(WITH_OPENGL) -ENDIF(BUILD_MAPEDITOR) +include(GenerateDoc) diff -Nru corsix-th-0.30/common/rnc.cpp corsix-th-0.62/common/rnc.cpp --- corsix-th-0.30/common/rnc.cpp 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/common/rnc.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,485 @@ +/* +Copyright (c) 1997 Simon Tatham + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + Original code was from http://www.yoda.arachsys.com/dk/utils.html. While + that site and the original code do not state copyright or license, email + communication releaved the original author, and they agreed to releasing it + under the MIT license (above). + + Modifications made to the original code include: + * Const correctness + * Prebuilt CRC table + * Lua interface + * Indentation and code style + * Bit stream pointers to data + * Fix bit operations near end of stream + * Style changes to conform to CorsixTH +*/ + +#include "rnc.h" +#include +#include +#include + +static const std::uint32_t rnc_signature = 0x524E4301; /*!< "RNC\001" */ + +static const std::uint16_t rnc_crc_table[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, +}; + +struct bit_stream +{ + std::uint32_t bitbuf; ///< holds between 16 and 32 bits. + int bitcount; ///< how many bits does bitbuf hold? + const std::uint8_t* endpos; ///< pointer past the readable data + const std::uint8_t* p; ///< pointer in data that stream is reading. +}; + +struct huf_table +{ + int num; ///< number of nodes in the tree. + struct + { + std::uint32_t code; + int codelen; + int value; + } table[32]; +}; + +//! Calculate a CRC, the RNC way. +/*! + @param data data for which to calculate the CRC + @param len length of the data in bytes +*/ +static std::uint16_t rnc_crc(const std::uint8_t* data, std::size_t len) +{ + std::uint16_t val = 0; + + while(len--) + { + val = static_cast(val ^ *data++); + val = static_cast((val >> 8) ^ rnc_crc_table[val & 0xFF]); + } + + return val; +} + + +//! Return the big-endian 32 bit word at p. +/*! + @param p Pointer to data containing the word +*/ +static std::uint32_t blong (const std::uint8_t *p) +{ + std::uint32_t n; + n = p[0]; + n = (n << 8) + p[1]; + n = (n << 8) + p[2]; + n = (n << 8) + p[3]; + return n; +} + +//! Return the big-endian 16 bit word at p. +/*! + @param p Pointer to data containing the word +*/ +static std::uint32_t bword (const std::uint8_t *p) +{ + std::uint32_t n; + n = p[0]; + n = (n << 8) + p[1]; + return n; +} + +//! Return the little-endian 16 bit word at p. +/*! + @param p Pointer to data containing the word + */ +static std::uint32_t lword (const std::uint8_t *p) +{ + std::uint32_t n; + n = p[1]; + n = (n << 8) + p[0]; + return n; +} + +//! Mirror the bottom n bits of x. +/*! + @param x + @param n +*/ +static std::uint32_t mirror (std::uint32_t x, int n) +{ + std::uint32_t top = 1 << (n-1), bottom = 1; + while (top > bottom) + { + std::uint32_t mask = top | bottom; + std::uint32_t masked = x & mask; + if (masked != 0 && masked != mask) + { + x ^= mask; + } + top >>= 1; + bottom <<= 1; + } + return x; +} + + +//! Initialises a bit stream with the first two bytes of the packed +//! data. +/*! + @param bs Bit stream to be initialized + @param p Pointer to start of memory block the bitstream is to + traverse + @param endpos Pointer to byte after the last memory block the bitstream is + to traverse +*/ +static void bitread_init (bit_stream *bs, const std::uint8_t *p, const std::uint8_t* endpos) +{ + bs->bitbuf = lword(p); + bs->bitcount = 16; + bs->p = p; + bs->endpos = endpos; +} + +//! Fixes up a bit stream after literals have been read out of the +//! data stream and the pointer has been moved. +/*! + @param bs Bit stream to correct +*/ +static void bitread_fix (bit_stream *bs) +{ + // Remove the top 16 bits + bs->bitcount -= 16; + bs->bitbuf &= (1<bitcount)-1; + + // Replace with what is in the new current location + // in the bit stream + if(bs->p < bs->endpos - 1) + { + bs->bitbuf |= (lword(bs->p)<bitcount); + bs->bitcount += 16; + } else if (bs->p == bs->endpos - 1) { + bs->bitbuf |= (*(bs->p)<bitcount); + bs->bitcount += 16; + } +} + +//! Return a word consisting of the specified bits without advancing +//! the bit stream. +/*! + @param bs Bit stream from which to peek + @param mask A 32 bit bit mask specifying which bits to peek +*/ +static std::uint32_t bit_peek (bit_stream *bs, const std::uint32_t mask) +{ + return bs->bitbuf & mask; +} + +//! Advances the bit stream. +/*! + @param bs Bit stream to advance + @param n Number of bits to advance the stream. Must be + between 0 and 16 +*/ +static void bit_advance (bit_stream *bs, int n) +{ + bs->bitbuf >>= n; + bs->bitcount -= n; + + if (bs->bitcount < 16) + { + // At this point it is possible for bs->p to advance past + // the end of the data. In that case we simply do not read + // anything more into the buffer. If we are on the last + // byte the lword matches what is in that byte. + bs->p += 2; + + if (bs->p < (bs->endpos - 1)) + { + bs->bitbuf |= (lword(bs->p)<bitcount); + bs->bitcount += 16; + } else if (bs->p < bs->endpos) { + bs->bitbuf |= (*(bs->p)<bitcount); + bs->bitcount += 16; + } + } +} + +//! Returns bits from the bit stream matching the mask and advances it +//! n places. +/*! + @param bs Bit stream to read + @param mask A 32 bit bit mask specifying which bits to read + @param n Number of bits to advance the stream. Must be + between 0 and 16 +*/ +static std::uint32_t bit_read (bit_stream *bs, std::uint32_t mask, int n) +{ + std::uint32_t result = bit_peek(bs, mask); + bit_advance(bs, n); + return result; +} + +//! Read a Huffman table out of the bit stream given. +/*! + @param h huf_table structure to populate + @param bs Bit stream pointing to the start of the Huffman table + description +*/ +static void read_huftable(huf_table *h, bit_stream *bs) +{ + int i, j, k, num; + int leaflen[32]; + int leafmax; + std::uint32_t codeb; /* big-endian form of code. */ + + num = bit_read(bs, 0x1F, 5); + + if(num == 0) + { + return; + } + + leafmax = 1; + for(i = 0; i < num; i++) + { + leaflen[i] = bit_read(bs, 0x0F, 4); + if (leafmax < leaflen[i]) + { + leafmax = leaflen[i]; + } + } + + codeb = 0L; + k = 0; + for(i = 1; i <= leafmax; i++) + { + for(j = 0; j < num; j++) + { + if(leaflen[j] == i) + { + h->table[k].code = mirror(codeb, i); + h->table[k].codelen = i; + h->table[k].value = j; + codeb++; + k++; + } + } + codeb <<= 1; + } + h->num = k; +} + +//! Read a value out of the bit stream using the given Huffman table. +/*! + @param h Huffman table to transcribe from + @param bs bit stream + @param p input data + @return The value from the table with the matching bits, or -1 if none found. +*/ +static std::uint32_t huf_read(huf_table *h, bit_stream *bs, const std::uint8_t **p) +{ + int i; + std::uint32_t val; + std::uint32_t mask; + + // Find the current bits in the table + for (i = 0; i < h->num; i++) + { + mask = (1 << h->table[i].codelen) - 1; + if(bit_peek(bs, mask) == h->table[i].code) + { + break; + } + } + + // No match found in table (error) + if(i == h->num) + { + return -1; + } + + bit_advance(bs, h->table[i].codelen); + + val = h->table[i].value; + if (val >= 2) + { + val = 1 << (val-1); + val |= bit_read(bs, val-1, h->table[i].value - 1); + } + return val; +} + +std::size_t rnc_output_size(const std::uint8_t* input) +{ + return static_cast(blong(input + 4)); +} + +std::size_t rnc_input_size(const std::uint8_t* input) +{ + return static_cast(blong(input + 8) + rnc_header_size); +} + +//! Decompresses RNC data +/*! + @param input Pointer to compressed RNC data + @param output Pointer to allocated memory region to hold uncompressed + data. The size of output must match the value specified in the + 4 byte segment of the input header starting at the 4th byte + in Big-endian. +*/ +rnc_status rnc_unpack(const std::uint8_t* input, std::uint8_t* output) +{ + const std::uint8_t *inputend; + std::uint8_t *outputend; + bit_stream input_bs; + huf_table raw = {0}, dist = {0}, len = {0}; + std::uint32_t ch_count; + std::uint32_t ret_len; + std::uint32_t out_crc; + if(blong(input) != rnc_signature) + { + return rnc_status::file_is_not_rnc; + } + ret_len = blong(input + 4); + outputend = output + ret_len; + inputend = input + 18 + blong(input + 8); + + //skip header + input += 18; + + // Check the packed-data CRC. Also save the unpacked-data CRC + // for later. + if (rnc_crc(input, inputend - input) != bword(input - 4)) + { + return rnc_status::packed_crc_error; + } + out_crc = bword(input - 6); + + //initialize the bitstream to the input and advance past the + //first two bits as they don't have any understood use. + bitread_init(&input_bs, input, inputend); + bit_advance(&input_bs, 2); + + //process chunks + while (output < outputend) + { + read_huftable(&raw, &input_bs); //raw byte length table + read_huftable(&dist, &input_bs); //distance prior to copy table + read_huftable(&len, &input_bs); //length bytes to copy table + ch_count = bit_read(&input_bs, 0xFFFF, 16); + + while(true) + { + long length, posn; + + // Copy bit pattern to output based on lookup + // of bytes from input. + length = huf_read(&raw, &input_bs, &input); + if(length == -1) + { + return rnc_status::huf_decode_error; + } + if(length) + { + while(length--) + { + *output++ = *(input_bs.p++); + } + bitread_fix(&input_bs); + } + if(--ch_count <= 0) + { + break; + } + + // Read position to copy output to + posn = huf_read(&dist, &input_bs, &input); + if(posn == -1) + { + return rnc_status::huf_decode_error; + } + posn += 1; + + // Read length of output to copy back + length = huf_read(&len, &input_bs, &input); + if(length == -1) + { + return rnc_status::huf_decode_error; + } + length += 2; + + // Copy length bytes from output back posn + while (length > 0) + { + length--; + *output = output[-posn]; + output++; + } + } + } + + if(outputend != output) + { + return rnc_status::file_size_mismatch; + } + + // Check the unpacked-data CRC. + if (rnc_crc(outputend - ret_len, ret_len) != out_crc) + { + return rnc_status::unpacked_crc_error; + } + + return rnc_status::ok; +} diff -Nru corsix-th-0.30/common/rnc.h corsix-th-0.62/common/rnc.h --- corsix-th-0.30/common/rnc.h 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/common/rnc.h 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,48 @@ +/* +Copyright (c) 2009 Peter "Corsix" Cawley + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef CORSIX_TH_RNC_H_ +#define CORSIX_TH_RNC_H_ + +#include +#include + +/*! Result status values from #rnc_inpack. */ +enum class rnc_status +{ + ok, ///< Everything is fine + file_is_not_rnc, ///< The file does not begin with an RNC signature + huf_decode_error, ///< Error decoding the file + file_size_mismatch, ///< The file size does not match the header + packed_crc_error, ///< The compressed file does not match its checksum + unpacked_crc_error ///< The uncompressed file does not match its checksum +}; + +const std::size_t rnc_header_size = 18; + +std::size_t rnc_output_size(const std::uint8_t* input); + +std::size_t rnc_input_size(const std::uint8_t* input); + +rnc_status rnc_unpack(const std::uint8_t* input, std::uint8_t* output); + +#endif // CORSIX_TH_RNC_H_ diff -Nru corsix-th-0.30/CONTRIBUTING.txt corsix-th-0.62/CONTRIBUTING.txt --- corsix-th-0.30/CONTRIBUTING.txt 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CONTRIBUTING.txt 2018-07-21 11:13:17.000000000 +0000 @@ -1,39 +1,17 @@ -ISSUE REPORTING: +TELL OTHER DEVS WHAT YOU ARE WORKING ON -GitHub currently doesn't support automatic issue templates, so follow the -instructions below when you want to make a suggestion, bug report, or pull -request. - -Please report only one bug, suggestion or pull request per issue, - -BUG REPORT - -Please answer the questions below when you want to report a bug. A bug could -be for example an error crash, graphical glitch or unexpected behavior. Please -copy the questions below to your issue and answer them when you want to report -a bug: - -What steps will reproduce the problem? -1. -2. -3. - -What is the expected output? What do you see instead? - -What version of CorsixTH are you using (e.g. "0.30", "4c66e39985")? - -What operating system / compile settings are you using? - -What level was this on (e.g. "Demo level", "Full game level 12")? - -Upload a saved game file (preferably an autosave from before the error) if you -have one and it is relevant. Look at HOW TO UPLOAD GAMELOG AND/OR SAVES for how -to do this. - -If possible, also upload the gamelog. Look at HOW TO UPLOAD GAMELOG AND/OR -SAVES for how to do this. - -Please provide any additional information below. +When you start working on a fix/enhancement for an open issue please always +post a comment in this issue's discussion to tell other devs that you have +started working on it so that they won't waste any of their free time by +working on their own fix/enhancement for it. + +If there isn't an open issue discussion for a bug fix/enhancement you want +to work on please check that there isn't a closed discussion for it because +a previous developer of it didn't finish their work which you could finish. + +And if there is no existing issue discussion for what you want to work on +please open a new issue for it and tell other devs here that your going to/ +have started working on it. SUGGESTION @@ -50,48 +28,44 @@ changes from the request. If your pull request relates to any existing issues, include those issues in the description. e.g. "Fixes issue #1" -HOW TO UPLOAD GAMELOG AND/OR SAVES - -As GitHub currently only supports uploading of images, you will have to upload -your gamelog(.txt) and your savegames to an another source such as Google -Drive, Dropbox, or SkyDrive/OneDrive. Add the link to the file to your issue -and make the file(s) public, so we can access your gamelog or savegame. The -most important thing is to not remove these files after you uploaded them! - -Also make sure you don't use a file hosting service which will automatically -delete your file after a time. - CONTRIBUTING CODE: First Time 1. Ensure you have a GitHub account (https://github.com/signup/free) 2. Fork CorsixTH\CorsixTH (https://github.com/CorsixTH/CorsixTH/fork) -3. Ensure you have a git client. (http://windows.github.com or -http://mac.github.com) +3. Ensure you have a git client. (http://desktop.github.com) 4. Clone your fork to your computer - - If using github client, run Git Shell - - git clone https://github.com/mygithubuser/CorsixTH.git + - If using github client, run Git Shell + - git clone https://github.com/mygithubuser/CorsixTH.git 5. Add upstream remote - - git remote add upstream https://github.com/CorsixTH/CorsixTH.git + - git remote add upstream https://github.com/CorsixTH/CorsixTH.git Every Time 6. Sync your master branch with the CorisxTH repository's master branch - git fetch upstream - git rebase upstream/master -7. Create feature branch - - git branch myfeature upstream/master -8. Checkout your feature branch - - git checkout myfeature -9. Make your changes -10. Review your changes +7. Make sure no one is already working on the issue you want to work on. +8. Tell other developers that you've started/will start working on this issue +by posting a comment in its existing issue discussion or if there's no existing +discussion for it then please open a new issue discussion for it and tell other +devs here that your working on it. +9. Create feature branch + - git branch myfeature upstream/master +10. Checkout your feature branch + - git checkout myfeature +11. Make your changes +12. Unittest continuously, see README.txt in CorsixTH/Luatest for more info +13. Review your changes - git diff (each file) - git add + - git diff --check + Check there's no white spaces. - git commit Write an informative commit message and save -11. Push your changes to your fork +14. Push your changes to your fork - git push origin myfeature -12. Create a pull request +15. Create a pull request (https://github.com/mygithubuser/CorsixTH/compare/CorsixTH:master...myfeature) Now watch to see if your feature is accepted. @@ -107,8 +81,8 @@ there might be other important changes other people are making to CorsixTH. It is a good idea to make sure your code will still operate correctly with the latest changes. To do this: - - git fetch upstream - - git rebase upstream/master + - git fetch upstream + - git rebase upstream/master What this does is downloads all the changes from CorsixTH\CorsixTH since you started, and pretends that all your changes were made after them. If there are conflicts, for example if someone else changed the same line in the same file Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/flags32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/flags32.png differ diff -Nru corsix-th-0.30/CorsixTH/Bitmap/mkbootstrap.lua corsix-th-0.62/CorsixTH/Bitmap/mkbootstrap.lua --- corsix-th-0.30/CorsixTH/Bitmap/mkbootstrap.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Bitmap/mkbootstrap.lua 2018-07-21 11:13:17.000000000 +0000 @@ -47,9 +47,9 @@ l = f(s, l) lines[#lines + 1] = l until l == "/* Start autogenerated content */" -merge("bootstrap_font.tab", "g_aBootstrapFontTab") -merge("bootstrap_font.dat", "g_aBootstrapFontDat") -merge("bootstrap_font.pal", "g_aBootstrapFontPal") +merge("bootstrap_font.tab", "bootstrap_font_tab") +merge("bootstrap_font.dat", "bootstrap_font_dat") +merge("bootstrap_font.pal", "bootstrap_font_pal") while l ~= "/* End autogenerated content */" do l = f(s, l) end diff -Nru corsix-th-0.30/CorsixTH/Bitmap/mkfont.lua corsix-th-0.62/CorsixTH/Bitmap/mkfont.lua --- corsix-th-0.30/CorsixTH/Bitmap/mkfont.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Bitmap/mkfont.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,8 +29,8 @@ package.path = (debug.getinfo(1, "S").source:match("@(.*[" .. package.config :sub(1, 1) .. "])") or "") .. "lib_" .. package.config:sub(5, 5) .. ".lua" .. package.config:sub(3, 3) .. package.path -require "bmp" -require "spritesheet" +require("bmp") +require("spritesheet") local bitmap_name, cell_width, cell_height, space_width = ... cell_width = assert(tonumber(cell_width), "cell width must be a number") diff -Nru corsix-th-0.30/CorsixTH/Bitmap/mkraw.lua corsix-th-0.62/CorsixTH/Bitmap/mkraw.lua --- corsix-th-0.30/CorsixTH/Bitmap/mkraw.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Bitmap/mkraw.lua 2018-07-21 11:13:17.000000000 +0000 @@ -27,7 +27,7 @@ package.path = (debug.getinfo(1, "S").source:match("@(.*[" .. package.config :sub(1, 1) .. "])") or "") .. "lib_" .. package.config:sub(5, 5) .. ".lua" .. package.config:sub(3, 3) .. package.path -require "bmp" +require("bmp") local filename = ... if not filename:match("%.bmp$") then diff -Nru corsix-th-0.30/CorsixTH/Bitmap/mksheet.lua corsix-th-0.62/CorsixTH/Bitmap/mksheet.lua --- corsix-th-0.30/CorsixTH/Bitmap/mksheet.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Bitmap/mksheet.lua 2018-07-21 11:13:17.000000000 +0000 @@ -27,8 +27,8 @@ package.path = (debug.getinfo(1, "S").source:match("@(.*[" .. package.config :sub(1, 1) .. "])") or "") .. "lib_" .. package.config:sub(5, 5) .. ".lua" .. package.config:sub(3, 3) .. package.path -require "bmp" -require "spritesheet" +require("bmp") +require("spritesheet") local specfile = ... specfile = assert(loadfile(specfile)) Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/new32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/new32.png differ Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/open32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/open32.png differ Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/parcels32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/parcels32.png differ Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/positions32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/positions32.png differ Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/redo32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/redo32.png differ Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/save32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/save32.png differ Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/transparent_walls32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/transparent_walls32.png differ Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Bitmap/undo32.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Bitmap/undo32.png differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/ChrizmanTV.campaign corsix-th-0.62/CorsixTH/Campaigns/ChrizmanTV.campaign --- corsix-th-0.30/CorsixTH/Campaigns/ChrizmanTV.campaign 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/ChrizmanTV.campaign 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,46 @@ +--[[ Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.--]] + +name = "ChrizmanTV and beyond" + +description = "Hello and welcome to the first CorsixTH Custom Campaign, created by Chris Wilkinson! " + .. "Do not lose your patients as you play through 12 levels of hospital hysteria and " + .. "comedic challenges. Starting at Coffalot, you will be introduced to the basic " + .. "functionality of CorsixTH before finally progressing to the last challenge " + .. "at Royal Hospital. The Ministry of Health will be monitoring you along the way, " + .. "as you will be met with bizarre illnesses and a multitude of sick patients who need " + .. "your attention. Have fun!" + +levels = { + "coffalot.level", + "holby.level", + "writhe.level", + "greyhamgardens.level", + "snuffitsands.level", + "upperpukington.level", + "fourcorners.level", + "wishinwell.level", + "hoppalong.level", + "tufflook.level", + "dethsdaw.level", + "royalhospital.level", +} + +winning_text = "Exceptional work! You have made it to the top! The mansion is yours, and public money galore is flowing into your Swiss bank account as we speak. Now you can relax - your days of running hospitals is finally over. Thanks for playing!" diff -Nru corsix-th-0.30/CorsixTH/Campaigns/coffalot.level corsix-th-0.62/CorsixTH/Campaigns/coffalot.level --- corsix-th-0.30/CorsixTH/Campaigns/coffalot.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/coffalot.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,223 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------------- General Information ------------------------- +%Name = "Coffalot" +%MapFile = "Coffalot.map" + +%LevelBriefing = "In the cosy town of Coffalot, some very ill patients are in need of medical attention. Luckily, you have been recruited by the Ministry of Health to operate a chain of hospitals in the nation. You have the job of running this quaint clinic on their behalf. To win the level, cure 50 patients, have a bank balance of $25,000, treat 50% of your visitors and have a hospital worth $50,000. We wish you the best of luck!" + +%LevelDebriefing = "Good work! The Ministry of Health thinks that you have done extremely well in handling your first hospital, but now, a managerial position has opened up at a new location. + +Would you be interested in running Holby Hospital?" + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 30000 300 + +-------------------- Disease Configuration ------------------------- + +When a drug is researched, what effectiveness does it have +#gbv.StartRating 100 + +The following table contains all diagnoses and treatments that shows up inte drug casebook +in the game. Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 GENERAL_PRACTICE +#expertise[2].Known.RschReqd 0 40000 BLOATY_HEAD +#expertise[3].Known.RschReqd 0 40000 HAIRYITUS +#expertise[4].Known.RschReqd 0 60000 ELVIS +#expertise[5].Known.RschReqd 0 60000 INVIS +#expertise[6].Known.RschReqd 0 60000 RADIATION +#expertise[7].Known.RschReqd 0 40000 SLACK_TONGUE +#expertise[8].Known.RschReqd 0 60000 ALIEN +#expertise[9].Known.RschReqd 0 20000 BROKEN_BONES +#expertise[10].Known.RschReqd 0 40000 BALDNESS +#expertise[11].Known.RschReqd 0 40000 DISCRETE_ITCHING +#expertise[12].Known.RschReqd 0 40000 JELLYITUS +#expertise[13].Known.RschReqd 0 40000 SLEEPING_ILLNESS +#expertise[14].Known.RschReqd 0 30000 PREGNANT +#expertise[15].Known.RschReqd 0 40000 TRANSPARENCY +#expertise[16].Known.RschReqd 0 20000 UNCOMMON_COLD +#expertise[17].Known.RschReqd 0 60000 BROKEN_WIND +#expertise[18].Known.RschReqd 0 20000 SPARE_RIBS +#expertise[19].Known.RschReqd 0 20000 KIDNEY_BEANS +#expertise[20].Known.RschReqd 0 20000 BROKEN_HEART +#expertise[21].Known.RschReqd 0 20000 RUPTURED_NODULES +#expertise[22].Known.RschReqd 0 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].Known.RschReqd 0 60000 INFECTIOUS_LAUGHTER +#expertise[24].Known.RschReqd 0 40000 CORRUGATED_ANKLES +#expertise[25].Known.RschReqd 1 40000 CHRONIC_NOSEHAIR +#expertise[26].Known.RschReqd 0 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].Known.RschReqd 0 40000 FAKE_BLOOD +#expertise[28].Known.RschReqd 0 40000 GASTRIC_EJECTIONS +#expertise[29].Known.RschReqd 0 20000 THE_SQUITS +#expertise[30].Known.RschReqd 0 20000 IRON_LUNGS +#expertise[31].Known.RschReqd 1 40000 SWEATY_PALMS +#expertise[32].Known.RschReqd 1 20000 HEAPED_PILES +#expertise[33].Known.RschReqd 0 20000 GUT_ROT +#expertise[34].Known.RschReqd 0 20000 GOLF_STONES +#expertise[35].Known.RschReqd 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 40000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 0 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 30000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 0 13 0 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 0 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 0 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 0 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 0 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 0 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 0 10 0 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 0 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 0 12 0 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 0 0 0 Projector +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 0 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 0 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 0 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 0 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 0 10 0 Autopsy Research Machine + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 0 I_HAIRYITUS +#visuals[2] 0 I_ELVIS +#visuals[3] 0 I_INVIS +#visuals[4] 0 I_RADIATION +#visuals[5] 0 I_SLACK_TONGUE +#visuals[6] 0 I_ALIEN +#visuals[7] 0 I_BROKEN_BONES +#visuals[8] 0 I_BALDNESS +#visuals[9] 1 I_DISCRETE_ITCHING +#visuals[10] 0 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 0 I_PREGNANT +#visuals[13] 0 I_TRANSPARENCY +#non_visuals[0] 1 I_UNCOMMON_COLD +#non_visuals[1] 1 I_BROKEN_WIND +#non_visuals[2] 0 I_SPARE_RIBS +#non_visuals[3] 0 I_KIDNEY_BEANS +#non_visuals[4] 0 I_BROKEN_HEART +#non_visuals[5] 0 I_RUPTURED_NODULES +#non_visuals[6] 1 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 1 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 0 I_CORRUGATED_ANKLES +#non_visuals[9] 1 I_CHRONIC_NOSEHAIR +#non_visuals[10] 0 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 0 I_FAKE_BLOOD +#non_visuals[12] 1 I_GASTRIC_EJECTIONS +#non_visuals[13] 1 I_THE_SQUITS +#non_visuals[14] 0 I_IRON_LUNGS +#non_visuals[15] 1 I_SWEATY_PALMS +#non_visuals[16] 1 I_HEAPED_PILES +#non_visuals[17] 0 I_GUT_ROT +#non_visuals[18] 0 I_GOLF_STONES +#non_visuals[19] 0 I_UNEXPECTED_SWELLING + + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 30 Handyman +#staff[3].MinSalary 30 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 50 Surgeon +#gbv.SalaryAdd[6] 40 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 10 + +#gbv.TrainingRate 50 +#gbv.AbilityThreshold[0] 80 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 50 Researcher +#gbv.TrainingValue[0] 30 Projector +#gbv.TrainingValue[1] 30 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +#quake_control[0].StartMonth.EndMonth.Severity 18 20 1 +#quake_control[1].StartMonth.EndMonth.Severity 30 32 2 +#quake_control[2].StartMonth.EndMonth.Severity 42 44 3 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 5 + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + +------------------ Winning and Losing Conditions ------------------- +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 2 1 25000 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 3 1 50 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 4 1 50 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 6 1 50000 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#win_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 5 1 50 1 0 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[3].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 CORSIX +#computer[13].Playing 1 ROUJIN +#computer[14].Playing 1 EDVIN Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Coffalot.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Coffalot.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/dethsdaw.level corsix-th-0.62/CorsixTH/Campaigns/dethsdaw.level --- corsix-th-0.30/CorsixTH/Campaigns/dethsdaw.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/dethsdaw.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,299 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General ------------------------- + +%Name = "Dethsdaw" +%MapFile = "Dethsdaw.map" + +%LevelBriefing = "The end is almost in sight, but first, some of the residents of Dethsdaw are coming down with a wobbly kind of illness. As always, the pinnacle of medical technologies are available to you as top scientists have created a new invention called the Atom Analyser. To move on to the final level, we want 900 cures, 90% treated, $450,000 in the bank, $750,000 worth of hospital and a reputation of 900. The Ministry expects total perfection!" + +%LevelDebriefing = "Exemplary! On the eve of your final mission, you've received a note from the Ministry of Health saying that they're putting you in charge of the largest and most complex hospital of them all! + +A country mansion awaits you... after you've finished Royal Hospital." + +#town.StartCash.InterestRate 80000 1400 + +#gbv.StartRating 70 When a drug is researched, what effectiveness does it have +#gbv.DrugImproveRate 5 +#gbv.StartCost 100 +#gbv.MinDrugCost 50 +#gbv.LandCostPerTile 45 Cost to buy a single map square +#gbv.RschImproveCostPercent 10 How many percent of the original research points that are required to improve the machine. +#gbv.RschImproveIncrementPercent 10 How many additional percentage points are added to the above value for each upgrade. +#gbv.MaxObjectStrength 20 Maximum strength value an object can be improved to (by research) +#gbv.ResearchIncrement 2 Increase object strength by this amount when researching +#gbv.AutopsyRschPercent 33 % of research completed for an autopsy +#gbv.AutopsyRepHitPercent 25 % rep hit for discovered autopsy + + +---------------------- Diseases ------------------------- + +The following table contains all diagnoses and treatments that shows up in the drug casebook in the game. Known specifies whether it should show up from the beginning of the level and RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 +#expertise[2].Known.RschReqd 1 40000 +#expertise[3].Known.RschReqd 1 40000 +#expertise[4].Known.RschReqd 1 60000 +#expertise[5].Known.RschReqd 1 60000 +#expertise[6].Known.RschReqd 0 60000 +#expertise[7].Known.RschReqd 1 40000 +#expertise[8].Known.RschReqd 0 60000 +#expertise[9].Known.RschReqd 1 20000 +#expertise[10].Known.RschReqd 1 40000 +#expertise[11].Known.RschReqd 1 40000 +#expertise[12].Known.RschReqd 0 40000 +#expertise[13].Known.RschReqd 1 40000 +#expertise[14].Known.RschReqd 1 30000 +#expertise[15].Known.RschReqd 1 40000 +#expertise[16].Known.RschReqd 1 20000 +#expertise[17].Known.RschReqd 1 60000 +#expertise[18].Known.RschReqd 1 20000 +#expertise[19].Known.RschReqd 1 20000 +#expertise[20].Known.RschReqd 1 20000 +#expertise[21].Known.RschReqd 1 20000 +#expertise[22].Known.RschReqd 1 40000 +#expertise[23].Known.RschReqd 1 60000 +#expertise[24].Known.RschReqd 1 40000 +#expertise[25].Known.RschReqd 1 40000 +#expertise[26].Known.RschReqd 1 40000 +#expertise[27].Known.RschReqd 1 40000 +#expertise[28].Known.RschReqd 1 40000 +#expertise[29].Known.RschReqd 1 20000 +#expertise[30].Known.RschReqd 1 20000 +#expertise[31].Known.RschReqd 1 40000 +#expertise[32].Known.RschReqd 1 20000 +#expertise[33].Known.RschReqd 1 20000 +#expertise[34].Known.RschReqd 1 20000 +#expertise[35].Known.RschReqd 1 20000 +#expertise[36].Known.RschReqd 0 40000 +#expertise[37].Known.RschReqd 0 50000 +#expertise[38].Known.RschReqd 1 20000 +#expertise[39].Known.RschReqd 0 30000 +#expertise[40].Known.RschReqd 0 60000 +#expertise[41].Known.RschReqd 1 20000 +#expertise[42].Known.RschReqd 1 20000 +#expertise[43].Known.RschReqd 1 20000 +#expertise[44].Known.RschReqd 0 0 +#expertise[45].Known.RschReqd 0 0 +#expertise[46].Known.RschReqd 0 0 + + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 +#visuals[1] 1 +#visuals[2] 1 +#visuals[3] 1 +#visuals[4] 1 +#visuals[5] 1 +#visuals[6] 0 +#visuals[7] 1 +#visuals[8] 1 +#visuals[9] 1 +#visuals[10] 1 +#visuals[11] 1 +#visuals[12] 1 +#visuals[13] 1 +#non_visuals[0] 1 +#non_visuals[1] 1 +#non_visuals[2] 1 +#non_visuals[3] 1 +#non_visuals[4] 1 +#non_visuals[5] 1 +#non_visuals[6] 1 +#non_visuals[7] 1 +#non_visuals[8] 1 +#non_visuals[9] 1 +#non_visuals[10] 1 +#non_visuals[11] 1 +#non_visuals[12] 1 +#non_visuals[13] 1 +#non_visuals[14] 1 +#non_visuals[15] 1 +#non_visuals[16] 1 +#non_visuals[17] 1 +#non_visuals[18] 1 +#non_visuals[19] 1 + + +#visuals_available[0] 0 +#visuals_available[1] 12 +#visuals_available[2] 3 +#visuals_available[3] 12 +#visuals_available[4] 18 +#visuals_available[5] 6 +#visuals_available[6] 0 +#visuals_available[7] 6 +#visuals_available[8] 12 +#visuals_available[9] 0 +#visuals_available[10] 18 +#visuals_available[11] 0 +#visuals_available[12] 0 +#visuals_available[13] 6 + + +---------------------- Objects ------------------------- + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[1].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[2].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[3].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[4].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[5].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[6].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[7].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[8].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[9].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 8 1 40000 +#objects[10].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[11].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[12].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[13].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 13 1 20000 +#objects[14].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 12 1 40000 +#objects[15].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[16].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[17].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[18].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[19].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[20].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[21].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[22].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 9 1 60000 +#objects[23].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 7 0 60000 +#objects[24].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 11 1 20000 +#objects[25].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 8 1 40000 +#objects[26].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 40000 +#objects[27].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 12 1 30000 +#objects[28].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[29].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[30].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 12 1 20000 +#objects[31].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[32].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[33].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[34].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[35].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[36].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[37].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 0 1 20000 +#objects[38].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[39].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[40].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 1 1 30000 +#objects[41].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 1 1 30000 +#objects[42].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 50000 +#objects[43].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[44].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[45].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[46].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 8 1 40000 +#objects[47].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 7 1 40000 +#objects[48].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[49].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[50].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[51].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[52].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[53].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[54].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 60000 +#objects[55].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[56].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[57].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 57 1 0 +#objects[58].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[59].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[60].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[61].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 + + +---------------------- Staff Configuration ------------------------- + + + +The minimum salary for each staff type +#staff[0].MinSalary 60 +#staff[1].MinSalary 75 +#staff[2].MinSalary 30 +#staff[3].MinSalary 30 + + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 +#gbv.SalaryAdd[4] 25 +#gbv.SalaryAdd[5] 75 +#gbv.SalaryAdd[6] 50 +#gbv.SalaryAdd[7] 120 +#gbv.SalaryAdd[8] 30 + + +Each entry states how many staff members of each category are available a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 0 8 8 3 2 10 10 10 10 3 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 3 7 5 5 3 10 10 10 10 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 5 5 8 7 4 10 10 10 10 3 + + +#gbv.TrainingRate 45 +#gbv.AbilityThreshold[0] 75 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 45 Researcher +#gbv.TrainingValue[0] 10 Projector +#gbv.TrainingValue[1] 25 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].Random 0 + + +----------------------- Quake Control -------------------------- + +#quake_control[0].StartMonth.EndMonth.Severity 10 12 6 +#quake_control[1].StartMonth.EndMonth.Severity 22 24 7 +#quake_control[2].StartMonth.EndMonth.Severity 34 36 8 +#quake_control[3].StartMonth.EndMonth.Severity 46 48 7 +#quake_control[4].StartMonth.EndMonth.Severity 58 60 6 +#quake_control[5].StartMonth.EndMonth.Severity 70 72 6 + + +----------------------- Population Growth ---------------------------- + +#popn[0].Month.Change 0 4 +#popn[1].Month.Change 1 1 + + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + + +------------------ Winning and Losing Conditions ------------------- + +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Cure count +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 900 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 450000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 90 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 900 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 750000 1 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 450 1 500 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 0 -40000 2 -20000 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 5 1 20 3 10 Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Dethsdaw.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Dethsdaw.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/example.campaign corsix-th-0.62/CorsixTH/Campaigns/example.campaign --- corsix-th-0.30/CorsixTH/Campaigns/example.campaign 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/example.campaign 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,13 @@ +name = "Example campaign" + +description = "This is an example campaign where you get the chance to play " .. + "through some of the levels shipped with CorsixTH. Happy gaming!" + +levels = { + "finisham.level", + "avatar.level", + "confined_v5.level", + "st.peter's.level", +} + +winning_text = "Congratulations! You have successfully completed all the levels." diff -Nru corsix-th-0.30/CorsixTH/Campaigns/fourcorners.level corsix-th-0.62/CorsixTH/Campaigns/fourcorners.level --- corsix-th-0.30/CorsixTH/Campaigns/fourcorners.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/fourcorners.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,225 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General Information ------------------------- +%Name = "Four Corners" +%MapFile = "Four Corners.map" + +%LevelBriefing = "New advances in technology has allowed for improved research - you now have access to the Computer. Also, there is a tragic new condition involving gleaming foreheads and a new piece of diagnosis equipment to research. Your hospital, too, is strange since it is made up of nine cubes, so you will have to deal with it as best you can. Cure 600 people, treat 75% of them, have $200,000 in the bank, have a hospital worth $300,000 and a reputation of 750 to win." + +%LevelDebriefing = "Spectacular! The Ministry of Health is in good standing with the public thanks to you, but they feel as though one hospital is not moving forward enough. + +There is a hair-raisingly good opportunity available to you at Hoppalong Hospital, will you take the offer?" + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 50000 1000 + +-------------------- Disease Configuration ------------------------- + +When a drug is researched, what effectiveness does it have +#gbv.StartRating 80 + +The following table contains all diagnoses and treatments that shows up inte drug casebook +in the game. Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 GENERAL_PRACTICE +#expertise[2].Known.RschReqd 1 40000 BLOATY_HEAD +#expertise[3].Known.RschReqd 0 40000 HAIRYITUS +#expertise[4].Known.RschReqd 0 60000 ELVIS +#expertise[5].Known.RschReqd 1 60000 INVIS +#expertise[6].Known.RschReqd 0 60000 RADIATION +#expertise[7].Known.RschReqd 0 40000 SLACK_TONGUE +#expertise[8].Known.RschReqd 0 60000 ALIEN +#expertise[9].Known.RschReqd 0 20000 BROKEN_BONES +#expertise[10].Known.RschReqd 0 40000 BALDNESS +#expertise[11].Known.RschReqd 1 40000 DISCRETE_ITCHING +#expertise[12].Known.RschReqd 0 40000 JELLYITUS +#expertise[13].Known.RschReqd 1 40000 SLEEPING_ILLNESS +#expertise[14].Known.RschReqd 0 30000 PREGNANT +#expertise[15].Known.RschReqd 0 40000 TRANSPARENCY +#expertise[16].Known.RschReqd 1 20000 UNCOMMON_COLD +#expertise[17].Known.RschReqd 1 60000 BROKEN_WIND +#expertise[18].Known.RschReqd 1 20000 SPARE_RIBS +#expertise[19].Known.RschReqd 1 20000 KIDNEY_BEANS +#expertise[20].Known.RschReqd 0 20000 BROKEN_HEART +#expertise[21].Known.RschReqd 0 20000 RUPTURED_NODULES +#expertise[22].Known.RschReqd 1 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].Known.RschReqd 1 60000 INFECTIOUS_LAUGHTER +#expertise[24].Known.RschReqd 1 40000 CORRUGATED_ANKLES +#expertise[25].Known.RschReqd 1 40000 CHRONIC_NOSEHAIR +#expertise[26].Known.RschReqd 1 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].Known.RschReqd 1 40000 FAKE_BLOOD +#expertise[28].Known.RschReqd 1 40000 GASTRIC_EJECTIONS +#expertise[29].Known.RschReqd 1 20000 THE_SQUITS +#expertise[30].Known.RschReqd 0 20000 IRON_LUNGS +#expertise[31].Known.RschReqd 1 40000 SWEATY_PALMS +#expertise[32].Known.RschReqd 1 20000 HEAPED_PILES +#expertise[33].Known.RschReqd 1 20000 GUT_ROT +#expertise[34].Known.RschReqd 1 20000 GOLF_STONES +#expertise[35].Known.RschReqd 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 40000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 1 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 30000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 1 13 1 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 1 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 0 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 0 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 1 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 1 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 0 10 1 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 1 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 1 12 1 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 1 0 1 Projector +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 1 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 0 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 0 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 0 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 1 10 1 Autopsy Research Machine + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 0 I_HAIRYITUS +#visuals[2] 1 I_ELVIS +#visuals[3] 1 I_INVIS +#visuals[4] 0 I_RADIATION +#visuals[5] 1 I_SLACK_TONGUE +#visuals[6] 0 I_ALIEN +#visuals[7] 1 I_BROKEN_BONES +#visuals[8] 1 I_BALDNESS +#visuals[9] 1 I_DISCRETE_ITCHING +#visuals[10] 0 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 0 I_PREGNANT +#visuals[13] 0 I_TRANSPARENCY +#non_visuals[0] 1 I_UNCOMMON_COLD +#non_visuals[1] 1 I_BROKEN_WIND +#non_visuals[2] 1 I_SPARE_RIBS +#non_visuals[3] 1 I_KIDNEY_BEANS +#non_visuals[4] 1 I_BROKEN_HEART +#non_visuals[5] 1 I_RUPTURED_NODULES +#non_visuals[6] 1 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 1 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 1 I_CORRUGATED_ANKLES +#non_visuals[9] 1 I_CHRONIC_NOSEHAIR +#non_visuals[10] 1 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 1 I_FAKE_BLOOD +#non_visuals[12] 1 I_GASTRIC_EJECTIONS +#non_visuals[13] 1 I_THE_SQUITS +#non_visuals[14] 1 I_IRON_LUNGS +#non_visuals[15] 1 I_SWEATY_PALMS +#non_visuals[16] 1 I_HEAPED_PILES +#non_visuals[17] 1 I_GUT_ROT +#non_visuals[18] 1 I_GOLF_STONES +#non_visuals[19] 1 I_UNEXPECTED_SWELLING + + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 30 Handyman +#staff[3].MinSalary 30 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 50 Surgeon +#gbv.SalaryAdd[6] 40 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 30 + +#gbv.TrainingRate 50 +#gbv.AbilityThreshold[0] 80 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 50 Researcher +#gbv.TrainingValue[0] 30 Projector +#gbv.TrainingValue[1] 30 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +#quake_control[0].StartMonth.EndMonth.Severity 10 12 4 +#quake_control[1].StartMonth.EndMonth.Severity 22 24 5 +#quake_control[2].StartMonth.EndMonth.Severity 34 36 6 +#quake_control[3].StartMonth.EndMonth.Severity 46 48 5 +#quake_control[4].StartMonth.EndMonth.Severity 58 60 4 +#quake_control[5].StartMonth.EndMonth.Severity 70 72 4 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 5 + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + +------------------ Winning and Losing Conditions ------------------- +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 750 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 200000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 75 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 600 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 300000 1 0 +#win_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 400 1 450 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 5 1 25 2 0 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[3].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 CORSIX +#computer[13].Playing 1 ROUJIN +#computer[14].Playing 1 EDVIN Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Four Corners.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Four Corners.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/greyhamgardens.level corsix-th-0.62/CorsixTH/Campaigns/greyhamgardens.level --- corsix-th-0.30/CorsixTH/Campaigns/greyhamgardens.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/greyhamgardens.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,231 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General Information ------------------------- +%Name = "Greyham Gardens" +%MapFile = "Greyham Gardens.map" + +%LevelBriefing = "Dr Greybags, a local scientist, has invested his time and effort in researching new machinery to combat the strange new afflictions in this rural area. He has kindly donated his expertise to you in the hope that you can cure more people. You now have access to the research room and training, among other rooms. Victory shall be yours if you cure 250 patients, amass $100,000, treat 60% of patients and have $125,000 worth of hospital value. We are confident you can do it!" + +%LevelDebriefing = "Brilliant! In an ever changing world of comical afflictions, the Ministry of Health deems you a valued employee. You now get to go to the beach... to run your next hospital. + +Will you fill the job vacancy going at Snuffit Sands Hospital?" + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 40000 600 + +-------------------- Disease Configuration ------------------------- + +When a drug is researched, what effectiveness does it have +#gbv.StartRating 95 + +The following table contains all diagnoses and treatments that shows up inte drug casebook +in the game. Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 GENERAL_PRACTICE +#expertise[2].Known.RschReqd 0 40000 BLOATY_HEAD +#expertise[3].Known.RschReqd 0 40000 HAIRYITUS +#expertise[4].Known.RschReqd 0 60000 ELVIS +#expertise[5].Known.RschReqd 0 60000 INVIS +#expertise[6].Known.RschReqd 0 60000 RADIATION +#expertise[7].Known.RschReqd 0 40000 SLACK_TONGUE +#expertise[8].Known.RschReqd 0 60000 ALIEN +#expertise[9].Known.RschReqd 0 20000 BROKEN_BONES +#expertise[10].Known.RschReqd 0 40000 BALDNESS +#expertise[11].Known.RschReqd 1 40000 DISCRETE_ITCHING +#expertise[12].Known.RschReqd 0 40000 JELLYITUS +#expertise[13].Known.RschReqd 1 40000 SLEEPING_ILLNESS +#expertise[14].Known.RschReqd 0 30000 PREGNANT +#expertise[15].Known.RschReqd 0 40000 TRANSPARENCY +#expertise[16].Known.RschReqd 1 20000 UNCOMMON_COLD +#expertise[17].Known.RschReqd 1 60000 BROKEN_WIND +#expertise[18].Known.RschReqd 0 20000 SPARE_RIBS +#expertise[19].Known.RschReqd 0 20000 KIDNEY_BEANS +#expertise[20].Known.RschReqd 0 20000 BROKEN_HEART +#expertise[21].Known.RschReqd 0 20000 RUPTURED_NODULES +#expertise[22].Known.RschReqd 0 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].Known.RschReqd 1 60000 INFECTIOUS_LAUGHTER +#expertise[24].Known.RschReqd 0 40000 CORRUGATED_ANKLES +#expertise[25].Known.RschReqd 1 40000 CHRONIC_NOSEHAIR +#expertise[26].Known.RschReqd 0 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].Known.RschReqd 0 40000 FAKE_BLOOD +#expertise[28].Known.RschReqd 0 40000 GASTRIC_EJECTIONS +#expertise[29].Known.RschReqd 1 20000 THE_SQUITS +#expertise[30].Known.RschReqd 0 20000 IRON_LUNGS +#expertise[31].Known.RschReqd 1 40000 SWEATY_PALMS +#expertise[32].Known.RschReqd 1 20000 HEAPED_PILES +#expertise[33].Known.RschReqd 0 20000 GUT_ROT +#expertise[34].Known.RschReqd 0 20000 GOLF_STONES +#expertise[35].Known.RschReqd 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 40000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 1 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 30000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 1 13 1 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 0 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 0 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 0 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 0 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 0 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 0 10 0 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 1 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 1 12 1 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 1 0 1 Projector +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 0 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 0 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 0 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 0 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 1 10 1 Autopsy Research Machine + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 0 I_HAIRYITUS +#visuals[2] 0 I_ELVIS +#visuals[3] 1 I_INVIS +#visuals[4] 0 I_RADIATION +#visuals[5] 0 I_SLACK_TONGUE +#visuals[6] 0 I_ALIEN +#visuals[7] 0 I_BROKEN_BONES +#visuals[8] 0 I_BALDNESS +#visuals[9] 1 I_DISCRETE_ITCHING +#visuals[10] 0 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 0 I_PREGNANT +#visuals[13] 0 I_TRANSPARENCY +#non_visuals[0] 1 I_UNCOMMON_COLD +#non_visuals[1] 1 I_BROKEN_WIND +#non_visuals[2] 1 I_SPARE_RIBS +#non_visuals[3] 1 I_KIDNEY_BEANS +#non_visuals[4] 0 I_BROKEN_HEART +#non_visuals[5] 0 I_RUPTURED_NODULES +#non_visuals[6] 1 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 1 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 1 I_CORRUGATED_ANKLES +#non_visuals[9] 1 I_CHRONIC_NOSEHAIR +#non_visuals[10] 1 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 1 I_FAKE_BLOOD +#non_visuals[12] 1 I_GASTRIC_EJECTIONS +#non_visuals[13] 1 I_THE_SQUITS +#non_visuals[14] 0 I_IRON_LUNGS +#non_visuals[15] 1 I_SWEATY_PALMS +#non_visuals[16] 1 I_HEAPED_PILES +#non_visuals[17] 1 I_GUT_ROT +#non_visuals[18] 1 I_GOLF_STONES +#non_visuals[19] 0 I_UNEXPECTED_SWELLING + + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 30 Handyman +#staff[3].MinSalary 30 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 50 Surgeon +#gbv.SalaryAdd[6] 40 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 20 + +#gbv.TrainingRate 50 +#gbv.AbilityThreshold[0] 80 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 50 Researcher +#gbv.TrainingValue[0] 30 Projector +#gbv.TrainingValue[1] 30 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +#quake_control[0].StartMonth.EndMonth.Severity 18 20 2 +#quake_control[1].StartMonth.EndMonth.Severity 30 32 3 +#quake_control[2].StartMonth.EndMonth.Severity 42 44 4 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 5 + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + +------------------ Winning and Losing Conditions ------------------- +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 2 1 100000 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 3 1 60 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 4 1 250 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 6 1 125000 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#win_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 5 1 40 1 0 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[3].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 CORSIX +#computer[13].Playing 1 ROUJIN +#computer[14].Playing 1 EDVIN + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 4 6 3 5 16 60 1000 +#emergency_control[1].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 8 10 4 6 32 60 1500 +#emergency_control[2].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 12 14 4 6 11 60 2000 +#emergency_control[3].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 16 18 4 6 13 60 2000 +#emergency_control[4].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 20 22 4 6 23 60 2000 +#emergency_control[5].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 24 26 4 6 25 60 2000 \ No newline at end of file Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Greyham Gardens.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Greyham Gardens.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/holby.level corsix-th-0.62/CorsixTH/Campaigns/holby.level --- corsix-th-0.30/CorsixTH/Campaigns/holby.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/holby.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,228 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General Information ------------------------- +%Name = "Holby" +%MapFile = "Holby.map" + +%LevelBriefing = "Your next mission is to treat the City of Holby. The odd diseases are travelling fast and it is up to you to cure 100 people, stockpile $50,000 in the bank, look after 50% of patients and have a hospital worth $75,000. You have been given a hospital which has the ability to be expanded in size, so use this to your advantage. Efficient planning and a well-run clinic will help in the event of an emergency. Make us proud at the Ministry!" + +%LevelDebriefing = "Great job! Now that you have your own office, the Ministry of Health is expecting bigger and better things. It's just a shame you're not getting any bigger and better cash bonuses to quench your lavish tastes. + +Will you be able to cope at Writhe Hospital?" + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 30000 400 + +-------------------- Disease Configuration ------------------------- + +When a drug is researched, what effectiveness does it have +#gbv.StartRating 100 + +The following table contains all diagnoses and treatments that shows up inte drug casebook +in the game. Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 GENERAL_PRACTICE +#expertise[2].Known.RschReqd 0 40000 BLOATY_HEAD +#expertise[3].Known.RschReqd 0 40000 HAIRYITUS +#expertise[4].Known.RschReqd 0 60000 ELVIS +#expertise[5].Known.RschReqd 0 60000 INVIS +#expertise[6].Known.RschReqd 0 60000 RADIATION +#expertise[7].Known.RschReqd 0 40000 SLACK_TONGUE +#expertise[8].Known.RschReqd 0 60000 ALIEN +#expertise[9].Known.RschReqd 0 20000 BROKEN_BONES +#expertise[10].Known.RschReqd 0 40000 BALDNESS +#expertise[11].Known.RschReqd 0 40000 DISCRETE_ITCHING +#expertise[12].Known.RschReqd 0 40000 JELLYITUS +#expertise[13].Known.RschReqd 0 40000 SLEEPING_ILLNESS +#expertise[14].Known.RschReqd 0 30000 PREGNANT +#expertise[15].Known.RschReqd 0 40000 TRANSPARENCY +#expertise[16].Known.RschReqd 1 20000 UNCOMMON_COLD +#expertise[17].Known.RschReqd 1 60000 BROKEN_WIND +#expertise[18].Known.RschReqd 0 20000 SPARE_RIBS +#expertise[19].Known.RschReqd 0 20000 KIDNEY_BEANS +#expertise[20].Known.RschReqd 0 20000 BROKEN_HEART +#expertise[21].Known.RschReqd 0 20000 RUPTURED_NODULES +#expertise[22].Known.RschReqd 0 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].Known.RschReqd 0 60000 INFECTIOUS_LAUGHTER +#expertise[24].Known.RschReqd 0 40000 CORRUGATED_ANKLES +#expertise[25].Known.RschReqd 1 40000 CHRONIC_NOSEHAIR +#expertise[26].Known.RschReqd 0 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].Known.RschReqd 0 40000 FAKE_BLOOD +#expertise[28].Known.RschReqd 0 40000 GASTRIC_EJECTIONS +#expertise[29].Known.RschReqd 0 20000 THE_SQUITS +#expertise[30].Known.RschReqd 0 20000 IRON_LUNGS +#expertise[31].Known.RschReqd 1 40000 SWEATY_PALMS +#expertise[32].Known.RschReqd 1 20000 HEAPED_PILES +#expertise[33].Known.RschReqd 0 20000 GUT_ROT +#expertise[34].Known.RschReqd 0 20000 GOLF_STONES +#expertise[35].Known.RschReqd 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 40000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 0 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 30000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 0 13 0 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 0 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 0 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 0 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 0 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 0 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 0 10 0 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 0 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 0 12 0 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 0 0 0 Projector +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 0 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 0 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 0 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 0 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 0 10 0 Autopsy Research Machine + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 0 I_HAIRYITUS +#visuals[2] 0 I_ELVIS +#visuals[3] 0 I_INVIS +#visuals[4] 0 I_RADIATION +#visuals[5] 0 I_SLACK_TONGUE +#visuals[6] 0 I_ALIEN +#visuals[7] 0 I_BROKEN_BONES +#visuals[8] 0 I_BALDNESS +#visuals[9] 1 I_DISCRETE_ITCHING +#visuals[10] 0 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 0 I_PREGNANT +#visuals[13] 0 I_TRANSPARENCY +#non_visuals[0] 1 I_UNCOMMON_COLD +#non_visuals[1] 1 I_BROKEN_WIND +#non_visuals[2] 0 I_SPARE_RIBS +#non_visuals[3] 0 I_KIDNEY_BEANS +#non_visuals[4] 0 I_BROKEN_HEART +#non_visuals[5] 0 I_RUPTURED_NODULES +#non_visuals[6] 1 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 1 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 1 I_CORRUGATED_ANKLES +#non_visuals[9] 1 I_CHRONIC_NOSEHAIR +#non_visuals[10] 0 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 0 I_FAKE_BLOOD +#non_visuals[12] 1 I_GASTRIC_EJECTIONS +#non_visuals[13] 1 I_THE_SQUITS +#non_visuals[14] 0 I_IRON_LUNGS +#non_visuals[15] 1 I_SWEATY_PALMS +#non_visuals[16] 1 I_HEAPED_PILES +#non_visuals[17] 1 I_GUT_ROT +#non_visuals[18] 0 I_GOLF_STONES +#non_visuals[19] 0 I_UNEXPECTED_SWELLING + + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 30 Handyman +#staff[3].MinSalary 30 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 50 Surgeon +#gbv.SalaryAdd[6] 40 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 10 + +#gbv.TrainingRate 50 +#gbv.AbilityThreshold[0] 80 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 50 Researcher +#gbv.TrainingValue[0] 30 Projector +#gbv.TrainingValue[1] 30 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +#quake_control[0].StartMonth.EndMonth.Severity 18 20 1 +#quake_control[1].StartMonth.EndMonth.Severity 30 32 2 +#quake_control[2].StartMonth.EndMonth.Severity 42 44 3 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 5 + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + +------------------ Winning and Losing Conditions ------------------- +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 2 1 50000 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 3 1 50 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 4 1 100 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 6 1 75000 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#win_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 5 1 50 1 0 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[3].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 CORSIX +#computer[13].Playing 1 ROUJIN +#computer[14].Playing 1 EDVIN + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 6 8 3 5 17 60 500 +#emergency_control[1].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 12 14 4 6 31 60 1000 +#emergency_control[2].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 18 20 4 6 16 60 1000 \ No newline at end of file Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Holby.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Holby.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/hoppalong.level corsix-th-0.62/CorsixTH/Campaigns/hoppalong.level --- corsix-th-0.30/CorsixTH/Campaigns/hoppalong.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/hoppalong.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,299 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General ------------------------- + +%Name = "Hoppalong" +%MapFile = "Hoppalong.map" + +%LevelBriefing = "A strange disease which makes people hairy is running rampant around the city of Wishinwell. According to our top scientists, it can only be removed by electroconvulsive therapy. Aside from that, you may find yourself out of room and out of cash, so plan ahead carefully. To win the level, cure 700 patients, treat 80% of visitors, amass $250,000 in the kitty, have a hospital worth $400,000 and gain a reputation of 800." + +%LevelDebriefing = "Perfect! Though you've done well here, a recent emergency has led to the creation of a makeshift hospital and your new boss, Mr B. Hind, is desperate for someone to run it. Don't let the public down! + +Will you take the challenge at Tufflook Hospital?" + +#town.StartCash.InterestRate 60000 1100 + +#gbv.StartRating 75 When a drug is researched, what effectiveness does it have +#gbv.DrugImproveRate 5 +#gbv.StartCost 100 +#gbv.MinDrugCost 50 +#gbv.LandCostPerTile 35 Cost to buy a single map square +#gbv.RschImproveCostPercent 10 How many percent of the original research points that are required to improve the machine. +#gbv.RschImproveIncrementPercent 10 How many additional percentage points are added to the above value for each upgrade. +#gbv.MaxObjectStrength 20 Maximum strength value an object can be improved to (by research) +#gbv.ResearchIncrement 2 Increase object strength by this amount when researching +#gbv.AutopsyRschPercent 33 % of research completed for an autopsy +#gbv.AutopsyRepHitPercent 25 % rep hit for discovered autopsy + + +---------------------- Diseases ------------------------- + +The following table contains all diagnoses and treatments that shows up in the drug casebook in the game. Known specifies whether it should show up from the beginning of the level and RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 +#expertise[2].Known.RschReqd 1 40000 +#expertise[3].Known.RschReqd 0 40000 +#expertise[4].Known.RschReqd 1 60000 +#expertise[5].Known.RschReqd 1 60000 +#expertise[6].Known.RschReqd 0 60000 +#expertise[7].Known.RschReqd 0 40000 +#expertise[8].Known.RschReqd 0 60000 +#expertise[9].Known.RschReqd 0 20000 +#expertise[10].Known.RschReqd 0 40000 +#expertise[11].Known.RschReqd 1 40000 +#expertise[12].Known.RschReqd 0 40000 +#expertise[13].Known.RschReqd 1 40000 +#expertise[14].Known.RschReqd 0 30000 +#expertise[15].Known.RschReqd 0 40000 +#expertise[16].Known.RschReqd 1 20000 +#expertise[17].Known.RschReqd 1 60000 +#expertise[18].Known.RschReqd 1 20000 +#expertise[19].Known.RschReqd 1 20000 +#expertise[20].Known.RschReqd 1 20000 +#expertise[21].Known.RschReqd 0 20000 +#expertise[22].Known.RschReqd 1 40000 +#expertise[23].Known.RschReqd 1 60000 +#expertise[24].Known.RschReqd 1 40000 +#expertise[25].Known.RschReqd 1 40000 +#expertise[26].Known.RschReqd 1 40000 +#expertise[27].Known.RschReqd 1 40000 +#expertise[28].Known.RschReqd 1 40000 +#expertise[29].Known.RschReqd 1 20000 +#expertise[30].Known.RschReqd 0 20000 +#expertise[31].Known.RschReqd 1 40000 +#expertise[32].Known.RschReqd 1 20000 +#expertise[33].Known.RschReqd 1 20000 +#expertise[34].Known.RschReqd 1 20000 +#expertise[35].Known.RschReqd 1 20000 +#expertise[36].Known.RschReqd 0 40000 +#expertise[37].Known.RschReqd 0 50000 +#expertise[38].Known.RschReqd 1 20000 +#expertise[39].Known.RschReqd 0 30000 +#expertise[40].Known.RschReqd 0 60000 +#expertise[41].Known.RschReqd 1 20000 +#expertise[42].Known.RschReqd 1 20000 +#expertise[43].Known.RschReqd 1 20000 +#expertise[44].Known.RschReqd 0 0 +#expertise[45].Known.RschReqd 0 0 +#expertise[46].Known.RschReqd 0 0 + + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 +#visuals[1] 1 +#visuals[2] 1 +#visuals[3] 1 +#visuals[4] 0 +#visuals[5] 1 +#visuals[6] 0 +#visuals[7] 1 +#visuals[8] 1 +#visuals[9] 1 +#visuals[10] 0 +#visuals[11] 1 +#visuals[12] 1 +#visuals[13] 1 +#non_visuals[0] 1 +#non_visuals[1] 1 +#non_visuals[2] 1 +#non_visuals[3] 1 +#non_visuals[4] 1 +#non_visuals[5] 1 +#non_visuals[6] 1 +#non_visuals[7] 1 +#non_visuals[8] 1 +#non_visuals[9] 1 +#non_visuals[10] 1 +#non_visuals[11] 1 +#non_visuals[12] 1 +#non_visuals[13] 1 +#non_visuals[14] 1 +#non_visuals[15] 1 +#non_visuals[16] 1 +#non_visuals[17] 1 +#non_visuals[18] 1 +#non_visuals[19] 1 + + +#visuals_available[0] 0 +#visuals_available[1] 12 +#visuals_available[2] 3 +#visuals_available[3] 12 +#visuals_available[4] 18 +#visuals_available[5] 6 +#visuals_available[6] 0 +#visuals_available[7] 6 +#visuals_available[8] 12 +#visuals_available[9] 0 +#visuals_available[10] 18 +#visuals_available[11] 0 +#visuals_available[12] 0 +#visuals_available[13] 6 + + +---------------------- Objects ------------------------- + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[1].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[2].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[3].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[4].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[5].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[6].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[7].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[8].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[9].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 8 1 40000 +#objects[10].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[11].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[12].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[13].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 13 1 20000 +#objects[14].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 12 1 40000 +#objects[15].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[16].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[17].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[18].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[19].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[20].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[21].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[22].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 9 0 60000 +#objects[23].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 7 0 60000 +#objects[24].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 11 1 20000 +#objects[25].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 8 1 40000 +#objects[26].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 40000 +#objects[27].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 12 1 30000 +#objects[28].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[29].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[30].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 12 1 20000 +#objects[31].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[32].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[33].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[34].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[35].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[36].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[37].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 0 1 20000 +#objects[38].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[39].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[40].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 30000 +#objects[41].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 0 30000 +#objects[42].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 50000 +#objects[43].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[44].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[45].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[46].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 8 1 40000 +#objects[47].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 7 0 40000 +#objects[48].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[49].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[50].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[51].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[52].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[53].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[54].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 0 60000 +#objects[55].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[56].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[57].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 0 +#objects[58].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[59].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[60].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[61].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 + + +---------------------- Staff Configuration ------------------------- + + + +The minimum salary for each staff type +#staff[0].MinSalary 60 +#staff[1].MinSalary 75 +#staff[2].MinSalary 30 +#staff[3].MinSalary 30 + + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 +#gbv.SalaryAdd[4] 30 +#gbv.SalaryAdd[5] 50 +#gbv.SalaryAdd[6] 40 +#gbv.SalaryAdd[7] 100 +#gbv.SalaryAdd[8] 20 + + +Each entry states how many staff members of each category are available a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 0 8 8 3 2 10 10 10 10 4 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 3 7 5 5 3 10 10 10 10 4 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 5 5 8 7 4 10 10 10 10 4 + + +#gbv.TrainingRate 45 +#gbv.AbilityThreshold[0] 75 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 45 Researcher +#gbv.TrainingValue[0] 10 Projector +#gbv.TrainingValue[1] 25 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].Random 0 + + +----------------------- Quake Control -------------------------- + +#quake_control[0].StartMonth.EndMonth.Severity 10 12 6 +#quake_control[1].StartMonth.EndMonth.Severity 22 24 7 +#quake_control[2].StartMonth.EndMonth.Severity 34 36 8 +#quake_control[3].StartMonth.EndMonth.Severity 46 48 7 +#quake_control[4].StartMonth.EndMonth.Severity 58 60 6 +#quake_control[5].StartMonth.EndMonth.Severity 70 72 6 + + +----------------------- Population Growth ---------------------------- + +#popn[0].Month.Change 0 4 +#popn[1].Month.Change 1 1 + + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + + +------------------ Winning and Losing Conditions ------------------- + +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Cure count +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 800 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 250000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 80 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 700 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 400000 1 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 400 1 450 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 0 -50000 2 -30000 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 5 1 25 3 10 Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Hoppalong.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Hoppalong.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/royalhospital.level corsix-th-0.62/CorsixTH/Campaigns/royalhospital.level --- corsix-th-0.30/CorsixTH/Campaigns/royalhospital.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/royalhospital.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,301 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General ------------------------- + +%Name = "Royal Hospital" +%MapFile = "Royal Hospital.map" + +%LevelBriefing = "This is your final assignment. The Ministry has granted you $100,000 to set up and operate the largest and most demanding hospital in the world. This is going to be a huge task, but we are certain that you'll succeed. We expect nothing less than perfection - gain a reputation of 950, amass $500,000 in the bank, have a hospital worth $1,000,000, treat 90% of all patients and cure 1000 visitors to finish. Good luck!" + +#town.StartCash.InterestRate 100000 1500 + +#gbv.StartRating 70 When a drug is researched, what effectiveness does it have +#gbv.DrugImproveRate 5 +#gbv.StartCost 100 +#gbv.MinDrugCost 50 +#gbv.LandCostPerTile 50 Cost to buy a single map square +#gbv.RschImproveCostPercent 10 How many percent of the original research points that are required to improve the machine. +#gbv.RschImproveIncrementPercent 10 How many additional percentage points are added to the above value for each upgrade. +#gbv.MaxObjectStrength 20 Maximum strength value an object can be improved to (by research) +#gbv.ResearchIncrement 2 Increase object strength by this amount when researching +#gbv.AutopsyRschPercent 33 % of research completed for an autopsy +#gbv.AutopsyRepHitPercent 25 % rep hit for discovered autopsy + + +---------------------- Diseases ------------------------- + +The following table contains all diagnoses and treatments that shows up in the drug casebook in the game. Known specifies whether it should show up from the beginning of the level and RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 +#expertise[2].Known.RschReqd 1 40000 +#expertise[3].Known.RschReqd 1 40000 +#expertise[4].Known.RschReqd 1 60000 +#expertise[5].Known.RschReqd 1 60000 +#expertise[6].Known.RschReqd 1 60000 +#expertise[7].Known.RschReqd 1 40000 +#expertise[8].Known.RschReqd 1 60000 +#expertise[9].Known.RschReqd 1 20000 +#expertise[10].Known.RschReqd 1 40000 +#expertise[11].Known.RschReqd 1 40000 +#expertise[12].Known.RschReqd 1 40000 +#expertise[13].Known.RschReqd 1 40000 +#expertise[14].Known.RschReqd 1 30000 +#expertise[15].Known.RschReqd 1 40000 +#expertise[16].Known.RschReqd 1 20000 +#expertise[17].Known.RschReqd 1 60000 +#expertise[18].Known.RschReqd 1 20000 +#expertise[19].Known.RschReqd 1 20000 +#expertise[20].Known.RschReqd 1 20000 +#expertise[21].Known.RschReqd 1 20000 +#expertise[22].Known.RschReqd 1 40000 +#expertise[23].Known.RschReqd 1 60000 +#expertise[24].Known.RschReqd 1 40000 +#expertise[25].Known.RschReqd 1 40000 +#expertise[26].Known.RschReqd 1 40000 +#expertise[27].Known.RschReqd 1 40000 +#expertise[28].Known.RschReqd 1 40000 +#expertise[29].Known.RschReqd 1 20000 +#expertise[30].Known.RschReqd 1 20000 +#expertise[31].Known.RschReqd 1 40000 +#expertise[32].Known.RschReqd 1 20000 +#expertise[33].Known.RschReqd 1 20000 +#expertise[34].Known.RschReqd 1 20000 +#expertise[35].Known.RschReqd 1 20000 +#expertise[36].Known.RschReqd 0 40000 +#expertise[37].Known.RschReqd 0 50000 +#expertise[38].Known.RschReqd 1 20000 +#expertise[39].Known.RschReqd 0 30000 +#expertise[40].Known.RschReqd 0 60000 +#expertise[41].Known.RschReqd 1 20000 +#expertise[42].Known.RschReqd 1 20000 +#expertise[43].Known.RschReqd 1 20000 +#expertise[44].Known.RschReqd 0 0 +#expertise[45].Known.RschReqd 0 0 +#expertise[46].Known.RschReqd 0 0 + + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 +#visuals[1] 1 +#visuals[2] 1 +#visuals[3] 1 +#visuals[4] 1 +#visuals[5] 1 +#visuals[6] 1 +#visuals[7] 1 +#visuals[8] 1 +#visuals[9] 1 +#visuals[10] 1 +#visuals[11] 1 +#visuals[12] 1 +#visuals[13] 1 +#non_visuals[0] 1 +#non_visuals[1] 1 +#non_visuals[2] 1 +#non_visuals[3] 1 +#non_visuals[4] 1 +#non_visuals[5] 1 +#non_visuals[6] 1 +#non_visuals[7] 1 +#non_visuals[8] 1 +#non_visuals[9] 1 +#non_visuals[10] 1 +#non_visuals[11] 1 +#non_visuals[12] 1 +#non_visuals[13] 1 +#non_visuals[14] 1 +#non_visuals[15] 1 +#non_visuals[16] 1 +#non_visuals[17] 1 +#non_visuals[18] 1 +#non_visuals[19] 1 + + +#visuals_available[0] 0 +#visuals_available[1] 12 +#visuals_available[2] 3 +#visuals_available[3] 12 +#visuals_available[4] 18 +#visuals_available[5] 6 +#visuals_available[6] 0 +#visuals_available[7] 6 +#visuals_available[8] 12 +#visuals_available[9] 0 +#visuals_available[10] 18 +#visuals_available[11] 0 +#visuals_available[12] 0 +#visuals_available[13] 6 + + +---------------------- Objects ------------------------- + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[1].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[2].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[3].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[4].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[5].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[6].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[7].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[8].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[9].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 8 1 40000 +#objects[10].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[11].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[12].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[13].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 13 1 20000 +#objects[14].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 12 1 40000 +#objects[15].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[16].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[17].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[18].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[19].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[20].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[21].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[22].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 9 1 60000 +#objects[23].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 7 1 60000 +#objects[24].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 11 1 20000 +#objects[25].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 8 1 40000 +#objects[26].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 40000 +#objects[27].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 12 1 30000 +#objects[28].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[29].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[30].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 12 1 20000 +#objects[31].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[32].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[33].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[34].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[35].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[36].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[37].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 0 1 20000 +#objects[38].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[39].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[40].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 1 1 30000 +#objects[41].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 1 1 30000 +#objects[42].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 50000 +#objects[43].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[44].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[45].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[46].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 8 1 40000 +#objects[47].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 7 1 40000 +#objects[48].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[49].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[50].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[51].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[52].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[53].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[54].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 60000 +#objects[55].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[56].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[57].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 57 1 0 +#objects[58].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[59].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[60].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[61].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 + + +---------------------- Staff Configuration ------------------------- + + + +The minimum salary for each staff type +#staff[0].MinSalary 60 +#staff[1].MinSalary 75 +#staff[2].MinSalary 25 +#staff[3].MinSalary 20 + + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 +#gbv.SalaryAdd[4] 30 +#gbv.SalaryAdd[5] 75 +#gbv.SalaryAdd[6] 50 +#gbv.SalaryAdd[7] 100 +#gbv.SalaryAdd[8] 25 + + +Each entry states how many staff members of each category are available a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 0 8 8 3 2 10 10 10 10 3 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 3 7 5 5 3 10 10 10 10 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 5 5 8 7 4 10 10 10 10 3 + + +#gbv.TrainingRate 45 +#gbv.AbilityThreshold[0] 75 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 45 Researcher +#gbv.TrainingValue[0] 10 Projector +#gbv.TrainingValue[1] 25 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].Random 0 + + +----------------------- Quake Control -------------------------- + +#quake_control[0].StartMonth.EndMonth.Severity 5 10 10 +#quake_control[1].StartMonth.EndMonth.Severity 15 20 10 +#quake_control[2].StartMonth.EndMonth.Severity 25 30 10 +#quake_control[3].StartMonth.EndMonth.Severity 35 40 10 +#quake_control[4].StartMonth.EndMonth.Severity 45 50 10 +#quake_control[5].StartMonth.EndMonth.Severity 55 60 10 +#quake_control[6].StartMonth.EndMonth.Severity 65 70 10 +#quake_control[7].StartMonth.EndMonth.Severity 75 80 10 +#quake_control[8].StartMonth.EndMonth.Severity 85 90 10 +#quake_control[9].StartMonth.EndMonth.Severity 95 100 10 +#quake_control[10].StartMonth.EndMonth.Severity 105 110 10 +#quake_control[11].StartMonth.EndMonth.Severity 125 130 10 + + +----------------------- Population Growth ---------------------------- + +#popn[0].Month.Change 0 4 +#popn[1].Month.Change 1 1 + + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + + +------------------ Winning and Losing Conditions ------------------- + +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Cure count +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 950 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 500000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 90 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 1000 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 1000000 1 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 450 1 500 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 0 -30000 2 -15000 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 5 1 20 3 10 Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Royal Hospital.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Royal Hospital.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/snuffitsands.level corsix-th-0.62/CorsixTH/Campaigns/snuffitsands.level --- corsix-th-0.30/CorsixTH/Campaigns/snuffitsands.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/snuffitsands.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,234 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General Information ------------------------- +%Name = "Snuffit Sands" +%MapFile = "Snuffit Sands.map" + +%LevelBriefing = "You are now highly regarded in the hospital community for your excellent services and care, so you now have a reputation to maintain as well. Also, your surgeons may see a couple of new merry maladies to take care of in the operating theatre. Hopefully, you can accomplish these goals for the cheery land of Snuffit Sands. Cure 300 patients, treat 70% of patients, accumulate $125,000 in the bank, have a hospital worth $150,000 and maintain a reputation of 600." + +%LevelDebriefing = "Wonderful! Things have become hectic since you've been away. The Ministry has immediately assigned you to your next task in a dilapidated old clinic, and watch out for the tongues! + +Can you help the sick people of Upper Pukington Hospital?" + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 45000 700 + +-------------------- Disease Configuration ------------------------- + +When a drug is researched, what effectiveness does it have +#gbv.StartRating 90 + +The following table contains all diagnoses and treatments that shows up inte drug casebook +in the game. Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 GENERAL_PRACTICE +#expertise[2].Known.RschReqd 1 40000 BLOATY_HEAD +#expertise[3].Known.RschReqd 0 40000 HAIRYITUS +#expertise[4].Known.RschReqd 0 60000 ELVIS +#expertise[5].Known.RschReqd 0 60000 INVIS +#expertise[6].Known.RschReqd 0 60000 RADIATION +#expertise[7].Known.RschReqd 0 40000 SLACK_TONGUE +#expertise[8].Known.RschReqd 0 60000 ALIEN +#expertise[9].Known.RschReqd 0 20000 BROKEN_BONES +#expertise[10].Known.RschReqd 0 40000 BALDNESS +#expertise[11].Known.RschReqd 1 40000 DISCRETE_ITCHING +#expertise[12].Known.RschReqd 0 40000 JELLYITUS +#expertise[13].Known.RschReqd 1 40000 SLEEPING_ILLNESS +#expertise[14].Known.RschReqd 0 30000 PREGNANT +#expertise[15].Known.RschReqd 0 40000 TRANSPARENCY +#expertise[16].Known.RschReqd 1 20000 UNCOMMON_COLD +#expertise[17].Known.RschReqd 1 60000 BROKEN_WIND +#expertise[18].Known.RschReqd 0 20000 SPARE_RIBS +#expertise[19].Known.RschReqd 0 20000 KIDNEY_BEANS +#expertise[20].Known.RschReqd 0 20000 BROKEN_HEART +#expertise[21].Known.RschReqd 0 20000 RUPTURED_NODULES +#expertise[22].Known.RschReqd 1 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].Known.RschReqd 1 60000 INFECTIOUS_LAUGHTER +#expertise[24].Known.RschReqd 0 40000 CORRUGATED_ANKLES +#expertise[25].Known.RschReqd 1 40000 CHRONIC_NOSEHAIR +#expertise[26].Known.RschReqd 0 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].Known.RschReqd 0 40000 FAKE_BLOOD +#expertise[28].Known.RschReqd 0 40000 GASTRIC_EJECTIONS +#expertise[29].Known.RschReqd 1 20000 THE_SQUITS +#expertise[30].Known.RschReqd 0 20000 IRON_LUNGS +#expertise[31].Known.RschReqd 1 40000 SWEATY_PALMS +#expertise[32].Known.RschReqd 1 20000 HEAPED_PILES +#expertise[33].Known.RschReqd 0 20000 GUT_ROT +#expertise[34].Known.RschReqd 0 20000 GOLF_STONES +#expertise[35].Known.RschReqd 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 40000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 1 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 30000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 1 13 1 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 0 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 0 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 0 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 0 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 0 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 0 10 0 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 1 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 1 12 1 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 1 0 1 Projector +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 0 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 0 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 0 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 0 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 1 10 1 Autopsy Research Machine + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 0 I_HAIRYITUS +#visuals[2] 1 I_ELVIS +#visuals[3] 1 I_INVIS +#visuals[4] 0 I_RADIATION +#visuals[5] 0 I_SLACK_TONGUE +#visuals[6] 0 I_ALIEN +#visuals[7] 0 I_BROKEN_BONES +#visuals[8] 0 I_BALDNESS +#visuals[9] 1 I_DISCRETE_ITCHING +#visuals[10] 0 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 0 I_PREGNANT +#visuals[13] 0 I_TRANSPARENCY +#non_visuals[0] 1 I_UNCOMMON_COLD +#non_visuals[1] 1 I_BROKEN_WIND +#non_visuals[2] 1 I_SPARE_RIBS +#non_visuals[3] 1 I_KIDNEY_BEANS +#non_visuals[4] 1 I_BROKEN_HEART +#non_visuals[5] 0 I_RUPTURED_NODULES +#non_visuals[6] 1 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 1 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 1 I_CORRUGATED_ANKLES +#non_visuals[9] 1 I_CHRONIC_NOSEHAIR +#non_visuals[10] 1 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 1 I_FAKE_BLOOD +#non_visuals[12] 1 I_GASTRIC_EJECTIONS +#non_visuals[13] 1 I_THE_SQUITS +#non_visuals[14] 0 I_IRON_LUNGS +#non_visuals[15] 1 I_SWEATY_PALMS +#non_visuals[16] 1 I_HEAPED_PILES +#non_visuals[17] 1 I_GUT_ROT +#non_visuals[18] 1 I_GOLF_STONES +#non_visuals[19] 1 I_UNEXPECTED_SWELLING + + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 30 Handyman +#staff[3].MinSalary 30 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 50 Surgeon +#gbv.SalaryAdd[6] 40 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 25 + +#gbv.TrainingRate 50 +#gbv.AbilityThreshold[0] 80 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 50 Researcher +#gbv.TrainingValue[0] 30 Projector +#gbv.TrainingValue[1] 30 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +#quake_control[0].StartMonth.EndMonth.Severity 18 20 3 +#quake_control[1].StartMonth.EndMonth.Severity 30 32 4 +#quake_control[2].StartMonth.EndMonth.Severity 42 44 5 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 5 + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + +------------------ Winning and Losing Conditions ------------------- +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 600 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 125000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 70 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 300 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 150000 1 0 +#win_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 400 1 450 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 5 1 30 2 0 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[3].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 CORSIX +#computer[13].Playing 1 ROUJIN +#computer[14].Playing 1 EDVIN + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 4 6 4 6 2 70 1000 +#emergency_control[1].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 8 10 5 8 16 70 2000 +#emergency_control[2].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 12 14 5 8 22 70 2500 +#emergency_control[3].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 16 18 5 8 13 70 2500 +#emergency_control[4].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 20 22 5 8 23 70 2500 +#emergency_control[5].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 24 26 5 8 29 70 2500 +#emergency_control[6].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 28 30 5 8 17 70 2500 +#emergency_control[7].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 32 34 5 8 11 70 2500 +#emergency_control[8].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 36 38 5 8 4 70 2500 \ No newline at end of file Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Snuffit Sands.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Snuffit Sands.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/tufflook.level corsix-th-0.62/CorsixTH/Campaigns/tufflook.level --- corsix-th-0.30/CorsixTH/Campaigns/tufflook.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/tufflook.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,299 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General ------------------------- + +%Name = "Tufflook" +%MapFile = "Tufflook.map" + +%LevelBriefing = "Disaster! A nuclear meltdown at the local power station has rendered a curious new form of radiation sickness to develop within the city. The Ministry has set up this hospital, filled with all the latest equipment, to help you cure them of their ailments. To succeed, cure 800 and treat at least 80% of patients, gather $300,000 in your account, construct a hospital worth $500,000 and gain a sterling reputation of 850. We are confident you can do it!" + +%LevelDebriefing = "Marvellous! You've come a long way since your humble beginnings, but the Ministry thinks that it is time to bring you back to earth and back to work. There's a job with a jelly... sorry, jolly good salary for you at Dethsdaw Hospital. + +Will you go for it?" + +#town.StartCash.InterestRate 70000 1250 + +#gbv.StartRating 75 When a drug is researched, what effectiveness does it have +#gbv.DrugImproveRate 5 +#gbv.StartCost 100 +#gbv.MinDrugCost 50 +#gbv.LandCostPerTile 40 Cost to buy a single map square +#gbv.RschImproveCostPercent 10 How many percent of the original research points that are required to improve the machine. +#gbv.RschImproveIncrementPercent 10 How many additional percentage points are added to the above value for each upgrade. +#gbv.MaxObjectStrength 20 Maximum strength value an object can be improved to (by research) +#gbv.ResearchIncrement 2 Increase object strength by this amount when researching +#gbv.AutopsyRschPercent 33 % of research completed for an autopsy +#gbv.AutopsyRepHitPercent 25 % rep hit for discovered autopsy + + +---------------------- Diseases ------------------------- + +The following table contains all diagnoses and treatments that shows up in the drug casebook in the game. Known specifies whether it should show up from the beginning of the level and RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 +#expertise[2].Known.RschReqd 1 40000 +#expertise[3].Known.RschReqd 0 40000 +#expertise[4].Known.RschReqd 1 60000 +#expertise[5].Known.RschReqd 1 60000 +#expertise[6].Known.RschReqd 0 60000 +#expertise[7].Known.RschReqd 1 40000 +#expertise[8].Known.RschReqd 0 60000 +#expertise[9].Known.RschReqd 0 20000 +#expertise[10].Known.RschReqd 0 40000 +#expertise[11].Known.RschReqd 1 40000 +#expertise[12].Known.RschReqd 0 40000 +#expertise[13].Known.RschReqd 1 40000 +#expertise[14].Known.RschReqd 1 30000 +#expertise[15].Known.RschReqd 0 40000 +#expertise[16].Known.RschReqd 1 20000 +#expertise[17].Known.RschReqd 1 60000 +#expertise[18].Known.RschReqd 1 20000 +#expertise[19].Known.RschReqd 1 20000 +#expertise[20].Known.RschReqd 1 20000 +#expertise[21].Known.RschReqd 1 20000 +#expertise[22].Known.RschReqd 1 40000 +#expertise[23].Known.RschReqd 1 60000 +#expertise[24].Known.RschReqd 1 40000 +#expertise[25].Known.RschReqd 1 40000 +#expertise[26].Known.RschReqd 1 40000 +#expertise[27].Known.RschReqd 1 40000 +#expertise[28].Known.RschReqd 1 40000 +#expertise[29].Known.RschReqd 1 20000 +#expertise[30].Known.RschReqd 1 20000 +#expertise[31].Known.RschReqd 1 40000 +#expertise[32].Known.RschReqd 1 20000 +#expertise[33].Known.RschReqd 1 20000 +#expertise[34].Known.RschReqd 1 20000 +#expertise[35].Known.RschReqd 1 20000 +#expertise[36].Known.RschReqd 0 40000 +#expertise[37].Known.RschReqd 0 50000 +#expertise[38].Known.RschReqd 1 20000 +#expertise[39].Known.RschReqd 0 30000 +#expertise[40].Known.RschReqd 0 60000 +#expertise[41].Known.RschReqd 1 20000 +#expertise[42].Known.RschReqd 1 20000 +#expertise[43].Known.RschReqd 1 20000 +#expertise[44].Known.RschReqd 0 0 +#expertise[45].Known.RschReqd 0 0 +#expertise[46].Known.RschReqd 0 0 + + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 +#visuals[1] 1 +#visuals[2] 1 +#visuals[3] 1 +#visuals[4] 1 +#visuals[5] 1 +#visuals[6] 0 +#visuals[7] 1 +#visuals[8] 1 +#visuals[9] 1 +#visuals[10] 0 +#visuals[11] 1 +#visuals[12] 1 +#visuals[13] 1 +#non_visuals[0] 1 +#non_visuals[1] 1 +#non_visuals[2] 1 +#non_visuals[3] 1 +#non_visuals[4] 1 +#non_visuals[5] 1 +#non_visuals[6] 1 +#non_visuals[7] 1 +#non_visuals[8] 1 +#non_visuals[9] 1 +#non_visuals[10] 1 +#non_visuals[11] 1 +#non_visuals[12] 1 +#non_visuals[13] 1 +#non_visuals[14] 1 +#non_visuals[15] 1 +#non_visuals[16] 1 +#non_visuals[17] 1 +#non_visuals[18] 1 +#non_visuals[19] 1 + + +#visuals_available[0] 0 +#visuals_available[1] 12 +#visuals_available[2] 3 +#visuals_available[3] 12 +#visuals_available[4] 18 +#visuals_available[5] 6 +#visuals_available[6] 0 +#visuals_available[7] 6 +#visuals_available[8] 12 +#visuals_available[9] 0 +#visuals_available[10] 18 +#visuals_available[11] 0 +#visuals_available[12] 0 +#visuals_available[13] 6 + + +---------------------- Objects ------------------------- + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[1].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[2].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[3].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[4].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[5].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[6].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[7].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[8].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[9].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 8 1 40000 +#objects[10].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[11].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[12].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[13].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 13 1 20000 +#objects[14].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 12 1 40000 +#objects[15].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[16].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[17].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[18].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[19].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[20].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[21].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[22].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 9 1 60000 +#objects[23].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 7 0 60000 +#objects[24].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 11 1 20000 +#objects[25].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 8 1 40000 +#objects[26].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 40000 +#objects[27].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 12 1 30000 +#objects[28].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[29].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[30].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 12 1 20000 +#objects[31].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[32].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[33].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[34].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[35].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[36].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[37].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 0 1 20000 +#objects[38].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[39].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 20000 +#objects[40].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 30000 +#objects[41].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 0 30000 +#objects[42].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 50000 +#objects[43].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[44].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[45].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[46].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 8 1 40000 +#objects[47].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 7 0 40000 +#objects[48].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[49].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[50].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[51].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[52].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[53].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[54].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 60000 +#objects[55].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[56].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[57].StartAvail.StartStrength.AvailableForLevel.RschReqd 0 10 1 0 +#objects[58].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[59].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[60].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 +#objects[61].StartAvail.StartStrength.AvailableForLevel.RschReqd 1 10 1 0 + + +---------------------- Staff Configuration ------------------------- + + + +The minimum salary for each staff type +#staff[0].MinSalary 60 +#staff[1].MinSalary 75 +#staff[2].MinSalary 30 +#staff[3].MinSalary 30 + + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 +#gbv.SalaryAdd[4] 30 +#gbv.SalaryAdd[5] 50 +#gbv.SalaryAdd[6] 40 +#gbv.SalaryAdd[7] 100 +#gbv.SalaryAdd[8] 20 + + +Each entry states how many staff members of each category are available a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 0 8 8 3 2 10 10 10 10 4 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 3 7 5 5 3 10 10 10 10 4 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists.ShrkRate.SurgRate.RschRate.ConsRate.JrRate 5 5 8 7 4 10 10 10 10 4 + + +#gbv.TrainingRate 45 +#gbv.AbilityThreshold[0] 75 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 45 Researcher +#gbv.TrainingValue[0] 10 Projector +#gbv.TrainingValue[1] 25 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].Random 0 + + +----------------------- Quake Control -------------------------- + +#quake_control[0].StartMonth.EndMonth.Severity 10 12 7 +#quake_control[1].StartMonth.EndMonth.Severity 22 24 8 +#quake_control[2].StartMonth.EndMonth.Severity 34 36 9 +#quake_control[3].StartMonth.EndMonth.Severity 46 48 8 +#quake_control[4].StartMonth.EndMonth.Severity 58 60 7 +#quake_control[5].StartMonth.EndMonth.Severity 70 72 7 + + +----------------------- Population Growth ---------------------------- + +#popn[0].Month.Change 0 4 +#popn[1].Month.Change 1 1 + + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + + +------------------ Winning and Losing Conditions ------------------- + +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Cure count +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 850 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 300000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 80 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 800 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 500000 1 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 400 1 450 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 0 -50000 2 -30000 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 5 1 25 3 10 Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Tufflook.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Tufflook.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/upperpukington.level corsix-th-0.62/CorsixTH/Campaigns/upperpukington.level --- corsix-th-0.30/CorsixTH/Campaigns/upperpukington.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/upperpukington.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,225 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General Information ------------------------- +%Name = "Upper Pukington" +%MapFile = "Upper Pukington.map" + +%LevelBriefing = "The Ministry of Health has recently acquired this old hospital in Upper Pukington, but has found it to be unsatisfactory in standards. There is a new tongue swelling disorder going around too, so watch out! Whilst you will not be dealing with emergencies, the layout is somewhat archaic, but we are sure you can reach the targets of 400 cures, 70% patient treatment, $150,000 in the kitty, $200,000 hospital value and a reputation of 650. Good luck!" + +%LevelDebriefing = "Excellent! The Ministry sees that your climbing the ranks in this career, but watch you don't fall and break a leg! You wouldn't want to ruin your new Italian shoes now... + +so could you assist the ill patients in need of treatment at Wishinwell Hospital?" + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 45000 800 + +-------------------- Disease Configuration ------------------------- + +When a drug is researched, what effectiveness does it have +#gbv.StartRating 90 + +The following table contains all diagnoses and treatments that shows up inte drug casebook +in the game. Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 GENERAL_PRACTICE +#expertise[2].Known.RschReqd 1 40000 BLOATY_HEAD +#expertise[3].Known.RschReqd 0 40000 HAIRYITUS +#expertise[4].Known.RschReqd 0 60000 ELVIS +#expertise[5].Known.RschReqd 0 60000 INVIS +#expertise[6].Known.RschReqd 0 60000 RADIATION +#expertise[7].Known.RschReqd 0 40000 SLACK_TONGUE +#expertise[8].Known.RschReqd 0 60000 ALIEN +#expertise[9].Known.RschReqd 0 20000 BROKEN_BONES +#expertise[10].Known.RschReqd 0 40000 BALDNESS +#expertise[11].Known.RschReqd 1 40000 DISCRETE_ITCHING +#expertise[12].Known.RschReqd 0 40000 JELLYITUS +#expertise[13].Known.RschReqd 1 40000 SLEEPING_ILLNESS +#expertise[14].Known.RschReqd 0 30000 PREGNANT +#expertise[15].Known.RschReqd 0 40000 TRANSPARENCY +#expertise[16].Known.RschReqd 1 20000 UNCOMMON_COLD +#expertise[17].Known.RschReqd 1 60000 BROKEN_WIND +#expertise[18].Known.RschReqd 0 20000 SPARE_RIBS +#expertise[19].Known.RschReqd 0 20000 KIDNEY_BEANS +#expertise[20].Known.RschReqd 0 20000 BROKEN_HEART +#expertise[21].Known.RschReqd 0 20000 RUPTURED_NODULES +#expertise[22].Known.RschReqd 1 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].Known.RschReqd 1 60000 INFECTIOUS_LAUGHTER +#expertise[24].Known.RschReqd 1 40000 CORRUGATED_ANKLES +#expertise[25].Known.RschReqd 1 40000 CHRONIC_NOSEHAIR +#expertise[26].Known.RschReqd 0 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].Known.RschReqd 0 40000 FAKE_BLOOD +#expertise[28].Known.RschReqd 1 40000 GASTRIC_EJECTIONS +#expertise[29].Known.RschReqd 1 20000 THE_SQUITS +#expertise[30].Known.RschReqd 0 20000 IRON_LUNGS +#expertise[31].Known.RschReqd 1 40000 SWEATY_PALMS +#expertise[32].Known.RschReqd 1 20000 HEAPED_PILES +#expertise[33].Known.RschReqd 1 20000 GUT_ROT +#expertise[34].Known.RschReqd 0 20000 GOLF_STONES +#expertise[35].Known.RschReqd 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 40000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 1 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 30000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 1 13 1 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 1 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 0 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 0 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 0 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 0 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 0 10 1 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 1 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 1 12 1 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 1 0 1 Projector +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 0 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 0 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 0 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 0 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 1 10 1 Autopsy Research Machine + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 0 I_HAIRYITUS +#visuals[2] 1 I_ELVIS +#visuals[3] 1 I_INVIS +#visuals[4] 0 I_RADIATION +#visuals[5] 1 I_SLACK_TONGUE +#visuals[6] 0 I_ALIEN +#visuals[7] 0 I_BROKEN_BONES +#visuals[8] 0 I_BALDNESS +#visuals[9] 1 I_DISCRETE_ITCHING +#visuals[10] 0 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 0 I_PREGNANT +#visuals[13] 0 I_TRANSPARENCY +#non_visuals[0] 1 I_UNCOMMON_COLD +#non_visuals[1] 1 I_BROKEN_WIND +#non_visuals[2] 1 I_SPARE_RIBS +#non_visuals[3] 1 I_KIDNEY_BEANS +#non_visuals[4] 1 I_BROKEN_HEART +#non_visuals[5] 0 I_RUPTURED_NODULES +#non_visuals[6] 1 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 1 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 1 I_CORRUGATED_ANKLES +#non_visuals[9] 1 I_CHRONIC_NOSEHAIR +#non_visuals[10] 1 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 1 I_FAKE_BLOOD +#non_visuals[12] 1 I_GASTRIC_EJECTIONS +#non_visuals[13] 1 I_THE_SQUITS +#non_visuals[14] 0 I_IRON_LUNGS +#non_visuals[15] 1 I_SWEATY_PALMS +#non_visuals[16] 1 I_HEAPED_PILES +#non_visuals[17] 1 I_GUT_ROT +#non_visuals[18] 1 I_GOLF_STONES +#non_visuals[19] 1 I_UNEXPECTED_SWELLING + + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 30 Handyman +#staff[3].MinSalary 30 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 50 Surgeon +#gbv.SalaryAdd[6] 40 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 25 + +#gbv.TrainingRate 50 +#gbv.AbilityThreshold[0] 80 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 50 Researcher +#gbv.TrainingValue[0] 30 Projector +#gbv.TrainingValue[1] 30 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +#quake_control[0].StartMonth.EndMonth.Severity 10 12 3 +#quake_control[1].StartMonth.EndMonth.Severity 22 24 4 +#quake_control[2].StartMonth.EndMonth.Severity 34 36 5 +#quake_control[3].StartMonth.EndMonth.Severity 46 48 4 +#quake_control[4].StartMonth.EndMonth.Severity 58 60 3 +#quake_control[5].StartMonth.EndMonth.Severity 70 72 4 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 5 + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + +------------------ Winning and Losing Conditions ------------------- +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 650 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 150000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 70 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 400 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 200000 1 0 +#win_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 400 1 450 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 5 1 30 2 0 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[3].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 CORSIX +#computer[13].Playing 1 ROUJIN +#computer[14].Playing 1 EDVIN Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Upper Pukington.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Upper Pukington.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/wishinwell.level corsix-th-0.62/CorsixTH/Campaigns/wishinwell.level --- corsix-th-0.30/CorsixTH/Campaigns/wishinwell.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/wishinwell.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,237 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General Information ------------------------- +%Name = "Wishinwell" +%MapFile = "Wishinwell.map" + +%LevelBriefing = "There are a couple of new conditions in the town of Wishinwell which require your attention, and youll be dealing with broken bones, so do not forget to prioritise research to cure rooms. You will also be dealing with a fair share of emergencies too. To win, gain a reputation of 700, treat 500 patients, cure 75% of your visitors, amass $175,000 in the bank and have a hospital worth $250,000. We at the Ministry wish you the best of luck!" + +%LevelDebriefing = "Outstanding! Now that you're on first name terms with your new boss, Mr I. Leggitt, you've been given a new project. He has noticed that you constantly stare at all four walls of your office, + +so do you think you can operate Four Corners Hospital?" + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 50000 900 + +-------------------- Disease Configuration ------------------------- + +When a drug is researched, what effectiveness does it have +#gbv.StartRating 85 + +The following table contains all diagnoses and treatments that shows up inte drug casebook +in the game. Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 GENERAL_PRACTICE +#expertise[2].Known.RschReqd 1 40000 BLOATY_HEAD +#expertise[3].Known.RschReqd 0 40000 HAIRYITUS +#expertise[4].Known.RschReqd 0 60000 ELVIS +#expertise[5].Known.RschReqd 0 60000 INVIS +#expertise[6].Known.RschReqd 0 60000 RADIATION +#expertise[7].Known.RschReqd 0 40000 SLACK_TONGUE +#expertise[8].Known.RschReqd 0 60000 ALIEN +#expertise[9].Known.RschReqd 0 20000 BROKEN_BONES +#expertise[10].Known.RschReqd 0 40000 BALDNESS +#expertise[11].Known.RschReqd 1 40000 DISCRETE_ITCHING +#expertise[12].Known.RschReqd 0 40000 JELLYITUS +#expertise[13].Known.RschReqd 1 40000 SLEEPING_ILLNESS +#expertise[14].Known.RschReqd 0 30000 PREGNANT +#expertise[15].Known.RschReqd 0 40000 TRANSPARENCY +#expertise[16].Known.RschReqd 1 20000 UNCOMMON_COLD +#expertise[17].Known.RschReqd 1 60000 BROKEN_WIND +#expertise[18].Known.RschReqd 0 20000 SPARE_RIBS +#expertise[19].Known.RschReqd 0 20000 KIDNEY_BEANS +#expertise[20].Known.RschReqd 0 20000 BROKEN_HEART +#expertise[21].Known.RschReqd 0 20000 RUPTURED_NODULES +#expertise[22].Known.RschReqd 1 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].Known.RschReqd 1 60000 INFECTIOUS_LAUGHTER +#expertise[24].Known.RschReqd 1 40000 CORRUGATED_ANKLES +#expertise[25].Known.RschReqd 1 40000 CHRONIC_NOSEHAIR +#expertise[26].Known.RschReqd 1 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].Known.RschReqd 1 40000 FAKE_BLOOD +#expertise[28].Known.RschReqd 1 40000 GASTRIC_EJECTIONS +#expertise[29].Known.RschReqd 1 20000 THE_SQUITS +#expertise[30].Known.RschReqd 0 20000 IRON_LUNGS +#expertise[31].Known.RschReqd 1 40000 SWEATY_PALMS +#expertise[32].Known.RschReqd 1 20000 HEAPED_PILES +#expertise[33].Known.RschReqd 1 20000 GUT_ROT +#expertise[34].Known.RschReqd 0 20000 GOLF_STONES +#expertise[35].Known.RschReqd 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 40000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 1 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 30000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 1 13 1 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 1 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 0 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 0 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 1 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 1 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 1 10 1 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 1 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 1 12 1 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 1 0 1 Projector +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 1 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 0 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 0 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 0 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 1 10 1 Autopsy Research Machine + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 0 I_HAIRYITUS +#visuals[2] 1 I_ELVIS +#visuals[3] 1 I_INVIS +#visuals[4] 0 I_RADIATION +#visuals[5] 1 I_SLACK_TONGUE +#visuals[6] 0 I_ALIEN +#visuals[7] 1 I_BROKEN_BONES +#visuals[8] 1 I_BALDNESS +#visuals[9] 1 I_DISCRETE_ITCHING +#visuals[10] 0 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 0 I_PREGNANT +#visuals[13] 0 I_TRANSPARENCY +#non_visuals[0] 1 I_UNCOMMON_COLD +#non_visuals[1] 1 I_BROKEN_WIND +#non_visuals[2] 1 I_SPARE_RIBS +#non_visuals[3] 1 I_KIDNEY_BEANS +#non_visuals[4] 1 I_BROKEN_HEART +#non_visuals[5] 1 I_RUPTURED_NODULES +#non_visuals[6] 1 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 1 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 1 I_CORRUGATED_ANKLES +#non_visuals[9] 1 I_CHRONIC_NOSEHAIR +#non_visuals[10] 1 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 1 I_FAKE_BLOOD +#non_visuals[12] 1 I_GASTRIC_EJECTIONS +#non_visuals[13] 1 I_THE_SQUITS +#non_visuals[14] 1 I_IRON_LUNGS +#non_visuals[15] 1 I_SWEATY_PALMS +#non_visuals[16] 1 I_HEAPED_PILES +#non_visuals[17] 1 I_GUT_ROT +#non_visuals[18] 1 I_GOLF_STONES +#non_visuals[19] 1 I_UNEXPECTED_SWELLING + + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 30 Handyman +#staff[3].MinSalary 30 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 50 Surgeon +#gbv.SalaryAdd[6] 40 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 30 + +#gbv.TrainingRate 50 +#gbv.AbilityThreshold[0] 80 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 50 Researcher +#gbv.TrainingValue[0] 30 Projector +#gbv.TrainingValue[1] 30 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +#quake_control[0].StartMonth.EndMonth.Severity 10 12 4 +#quake_control[1].StartMonth.EndMonth.Severity 22 24 5 +#quake_control[2].StartMonth.EndMonth.Severity 34 36 6 +#quake_control[3].StartMonth.EndMonth.Severity 46 48 5 +#quake_control[4].StartMonth.EndMonth.Severity 58 60 4 +#quake_control[5].StartMonth.EndMonth.Severity 70 72 4 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 5 + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + +------------------ Winning and Losing Conditions ------------------- +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 700 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 175000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 75 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 500 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 250000 1 0 +#win_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 400 1 450 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 5 1 25 2 0 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[3].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 CORSIX +#computer[13].Playing 1 ROUJIN +#computer[14].Playing 1 EDVIN + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 4 6 4 6 2 80 2000 +#emergency_control[1].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 8 10 5 8 16 80 2500 +#emergency_control[2].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 12 14 5 8 22 80 3000 +#emergency_control[3].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 16 18 5 8 13 80 3000 +#emergency_control[4].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 20 22 5 8 23 80 3000 +#emergency_control[5].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 24 26 5 8 29 80 3000 +#emergency_control[6].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 28 30 5 8 17 80 3000 +#emergency_control[7].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 32 34 5 8 11 80 3000 +#emergency_control[8].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 36 38 5 8 4 80 3000 \ No newline at end of file Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Wishinwell.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Wishinwell.map differ diff -Nru corsix-th-0.30/CorsixTH/Campaigns/writhe.level corsix-th-0.62/CorsixTH/Campaigns/writhe.level --- corsix-th-0.30/CorsixTH/Campaigns/writhe.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Campaigns/writhe.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,231 @@ +Copyright (c) 2013 Chris "ChrizmanTV" Wilkinson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------- General Information ------------------------- +%Name = "Writhe" +%MapFile = "Writhe.map" + +%LevelBriefing = "The Ministry has, so far, been impressed by your hospital running abilities and has issued you another challenge. Here at Writhe, the citizens of this small town are in desperate need of a new, efficient hospital. There are a couple of new ailments that will require the attention of your psychiatrists, so keep your wits scalpel sharp! To succeed, cure 200 patients, accrue $75,000, see to 60% of your customers and have a $100,000 hospital value. We are counting on you!" + +%LevelDebriefing = "Superb! People at the Ministry speak glowingly of you now that Mr L. Bow, your boss, has promoted you. Just don't overdo the top hat and tails, the public need you! + +There's a job at Greyham Gardens Hospital with your name on it, will you accept?" + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 40000 500 + +-------------------- Disease Configuration ------------------------- + +When a drug is researched, what effectiveness does it have +#gbv.StartRating 100 + +The following table contains all diagnoses and treatments that shows up inte drug casebook +in the game. Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +#expertise[1].Known.RschReqd 1 0 GENERAL_PRACTICE +#expertise[2].Known.RschReqd 0 40000 BLOATY_HEAD +#expertise[3].Known.RschReqd 0 40000 HAIRYITUS +#expertise[4].Known.RschReqd 0 60000 ELVIS +#expertise[5].Known.RschReqd 0 60000 INVIS +#expertise[6].Known.RschReqd 0 60000 RADIATION +#expertise[7].Known.RschReqd 0 40000 SLACK_TONGUE +#expertise[8].Known.RschReqd 0 60000 ALIEN +#expertise[9].Known.RschReqd 0 20000 BROKEN_BONES +#expertise[10].Known.RschReqd 0 40000 BALDNESS +#expertise[11].Known.RschReqd 0 40000 DISCRETE_ITCHING +#expertise[12].Known.RschReqd 0 40000 JELLYITUS +#expertise[13].Known.RschReqd 0 40000 SLEEPING_ILLNESS +#expertise[14].Known.RschReqd 0 30000 PREGNANT +#expertise[15].Known.RschReqd 0 40000 TRANSPARENCY +#expertise[16].Known.RschReqd 1 20000 UNCOMMON_COLD +#expertise[17].Known.RschReqd 1 60000 BROKEN_WIND +#expertise[18].Known.RschReqd 0 20000 SPARE_RIBS +#expertise[19].Known.RschReqd 0 20000 KIDNEY_BEANS +#expertise[20].Known.RschReqd 0 20000 BROKEN_HEART +#expertise[21].Known.RschReqd 0 20000 RUPTURED_NODULES +#expertise[22].Known.RschReqd 0 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].Known.RschReqd 1 60000 INFECTIOUS_LAUGHTER +#expertise[24].Known.RschReqd 0 40000 CORRUGATED_ANKLES +#expertise[25].Known.RschReqd 1 40000 CHRONIC_NOSEHAIR +#expertise[26].Known.RschReqd 0 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].Known.RschReqd 0 40000 FAKE_BLOOD +#expertise[28].Known.RschReqd 0 40000 GASTRIC_EJECTIONS +#expertise[29].Known.RschReqd 1 20000 THE_SQUITS +#expertise[30].Known.RschReqd 0 20000 IRON_LUNGS +#expertise[31].Known.RschReqd 1 40000 SWEATY_PALMS +#expertise[32].Known.RschReqd 1 20000 HEAPED_PILES +#expertise[33].Known.RschReqd 0 20000 GUT_ROT +#expertise[34].Known.RschReqd 0 20000 GOLF_STONES +#expertise[35].Known.RschReqd 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 40000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 1 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 30000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 1 13 1 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 0 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 0 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 0 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 0 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 0 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 0 10 0 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 0 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 0 12 0 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 0 0 0 Projector +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 0 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 0 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 0 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 0 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 0 10 0 Autopsy Research Machine + +| Diseases available | Value property to be determined | Comment +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 0 I_HAIRYITUS +#visuals[2] 0 I_ELVIS +#visuals[3] 0 I_INVIS +#visuals[4] 0 I_RADIATION +#visuals[5] 0 I_SLACK_TONGUE +#visuals[6] 0 I_ALIEN +#visuals[7] 0 I_BROKEN_BONES +#visuals[8] 0 I_BALDNESS +#visuals[9] 1 I_DISCRETE_ITCHING +#visuals[10] 0 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 0 I_PREGNANT +#visuals[13] 0 I_TRANSPARENCY +#non_visuals[0] 1 I_UNCOMMON_COLD +#non_visuals[1] 1 I_BROKEN_WIND +#non_visuals[2] 0 I_SPARE_RIBS +#non_visuals[3] 0 I_KIDNEY_BEANS +#non_visuals[4] 0 I_BROKEN_HEART +#non_visuals[5] 0 I_RUPTURED_NODULES +#non_visuals[6] 1 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 1 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 1 I_CORRUGATED_ANKLES +#non_visuals[9] 1 I_CHRONIC_NOSEHAIR +#non_visuals[10] 1 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 1 I_FAKE_BLOOD +#non_visuals[12] 1 I_GASTRIC_EJECTIONS +#non_visuals[13] 1 I_THE_SQUITS +#non_visuals[14] 0 I_IRON_LUNGS +#non_visuals[15] 1 I_SWEATY_PALMS +#non_visuals[16] 1 I_HEAPED_PILES +#non_visuals[17] 1 I_GUT_ROT +#non_visuals[18] 0 I_GOLF_STONES +#non_visuals[19] 0 I_UNEXPECTED_SWELLING + + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 30 Handyman +#staff[3].MinSalary 30 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 50 Surgeon +#gbv.SalaryAdd[6] 40 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 10 + +#gbv.TrainingRate 50 +#gbv.AbilityThreshold[0] 80 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 50 Researcher +#gbv.TrainingValue[0] 30 Projector +#gbv.TrainingValue[1] 30 Skeleton +#gbv.TrainingValue[2] 30 Bookcase + +#quake_control[0].StartMonth.EndMonth.Severity 18 20 2 +#quake_control[1].StartMonth.EndMonth.Severity 30 32 3 +#quake_control[2].StartMonth.EndMonth.Severity 42 44 4 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 5 + +---------------------- Awards and Trophies ------------------------- + +#awards_trophies.CansofCoke 2500 +#awards_trophies.CansofCokeBonus 5000 +#awards_trophies.Reputation 2500 +#awards_trophies.TrophyReputationBonus 20000 +#awards_trophies.TrophyDeathBonus 10000 + +------------------ Winning and Losing Conditions ------------------- +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 2 1 75000 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 3 1 60 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 4 1 200 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 6 1 100000 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#win_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 5 1 50 1 0 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[3].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[4].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 +#lose_criteria[5].Criteria.MaxMin.Value.Group.Bound 0 0 0 0 0 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 CORSIX +#computer[13].Playing 1 ROUJIN +#computer[14].Playing 1 EDVIN + +----------------------- Emergency Control -------------------------- + +#emergency_control[0].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 4 6 3 5 17 60 1000 +#emergency_control[1].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 10 12 4 6 22 60 1500 +#emergency_control[2].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 16 18 4 6 24 60 2000 +#emergency_control[3].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 22 24 4 6 26 60 2000 +#emergency_control[4].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 28 30 4 6 31 60 2000 +#emergency_control[5].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 34 36 4 6 33 60 2000 \ No newline at end of file Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Campaigns/Writhe.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Campaigns/Writhe.map differ diff -Nru corsix-th-0.30/CorsixTH/changelog.txt corsix-th-0.62/CorsixTH/changelog.txt --- corsix-th-0.30/CorsixTH/changelog.txt 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/changelog.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,869 +0,0 @@ -------------------------------------------------------------------------------- -Version 0.30 - released November 2013 -------------------------------------------------------------------------------- - -This release contains a whole new Level Editor, which means that in combination -with the already existing Map Editor whole levels can now be created a lot -easier. Give it a try! We have also added many new options previously only -available by manually editing the config file to the options dialog. -Players will also notice that we have added an automatic update -check on game launch once we release the version after this one. -As usual there are of course also numerous minor tweaks here and there. - - - ---- Gameplay --- - -* Change: You can now build more than one desk in the ward. More nurses means - a slightly faster throughput. -* Change: Patients would previously queue outside toilets even though there were - free loos since it was dependant on number of people in the room. Now, as soon - as a loo becomes free another patient enters the room to use it, - even if there is a long queue for the sink). - If there is a queue for the sinks there is a chance the patient will leave - without washing their hands - but will not be happy about doing this. - -* Added: The ability to control alien behaviour - sitting, knocking doors, - only to be available through emergency or arrive like all other patients. -* Added: Winning fax opens automatically and pauses the game. -* Added: Option to automatically accept wage increase requests when they "time out". -* Added: A new option allows for your average build content for each type of room - to be remembered, so will be added for each new room built later. - -* Fix: Doctors should get stuck less often, and handymen should not crash the - game as frequently. -* Fix: It was not possible to replace a surgeon when a patient was in the room. -* Fix: Patients would sometimes get stuck inside a room when they should - have died. - - - ---- User Interface --- - -* Added: A new customization menu in the Options dialog. Most options from the - configuration file are now available for change in-game. -* Added: A new directory menu in the Options dialog. -* Added: The game does now check for a more recent version of itself when - launching. -* Added: A helpful message when the player puts more Researchers in the - research department than there are desks. -* Added: The game now does a small integrity check on the Theme Hospital - files to make sure that the most common corruptions are not present. -* Added: Confirm dialog to the quit/exit button on the main menu. - -* Fix: The tooltip for the tutorial button was incorrect since the dialog - has been visually changed. -* Fix: The announcer has had a few corrections made to his manuscripts. - He is very happy about this! - -* Removed: The settings menu is no longer available from within the game. - - - ---- Hotkeys --- - -Some hotkeys have been changed and/or added: - -* Alt + A = Toggle Announcements -* Alt + M = Toggle Music -* Alt + S = Toggle Sound Effects -* Shift and + to zoom in five steps and Shift and - to zoom out five steps at a time. - - - ---- Campaign levels --- - -* Fix: An error in level 8 made it possible to win without meeting the - reputation criterion. - - - ---- Custom levels --- - -* Change: For random emergencies each illness now has its own average number of - patients to spawn. Previously they were all the same. - -* Fix: Researching improvements was not really possible on some custom levels, - i.e. if the map creator had made it so there were no machines at the start. - - - ---- Demo files --- - -* Fix: When winning the demo level CorsixTH looked for another level to load, - showing the wrong fax options and eventually crashing. - - - ---- Languages --- - -* Added: Korean language. - -* Fix: It was not possible to dump strings for a language with unicode - characters in the name. - - - ---- Compiling --- - -* Fix: You could not compile the game with WITH_AUDIO=0 if SDL_mixer was - not present at all. -* Fix: WITH_AUDIO=OFF is now illegal in combination with WITH_MOVIES=ON. - - - -------------------------------------------------------------------------------- -Version 0.21 - released 2013-05-04 -------------------------------------------------------------------------------- - -This is mainly a bugfix release, but a few minor features are still also -introduced, see the changelog below. - - - ---- Gameplay --- - -* Fix: Staff would sometimes not go for a break. -* Fix: A few crashes related to Handymen. -* Fix: An error could occur if a fax message was removed just as it was animating - into view. -* Fix: Patients could sometimes be told to go home multiple times, - resulting in a crash. -* Fix: If a queueing patient was heading for a drinks machine just as the player - moved that machine the game would crash. - - - ---- User Interface --- - -* Added: Scrolling momentum when using the middle button. -* Added: There is now a clock in the right corner of the menu bar that - shows the real world time. It can be toggled between AM/PM and 24h - in the configuration file. - - - ---- Hotkeys --- - -* Added: Hotkeys for the Jukebox (J), Save game menu (Shift + S), - Load game menu (Shift + L), to restart the level (Shift + R) and finally - quit the current game and take you back to the opening screen (Shift + Q). - -* Change: Restart is now Shift + F10 instead of only F10. -* Change: Toggle adviser is now Shift + A instead of only A. -* Change: Key combinations will only trigger if that exact combination - is pressed. E.g. Ctrl + R will not trigger R too. -* Change: Alt + F4 is now the hotkey to quit CorsixTH. - -* Fix: Added a configuration option to have the possibility to use Shift + C - as hotkey to open the Drug casebook instead of C. This is to workaround - a bug that when you press on the volume down key on your keyboard - the Drug casebook would open. - - - ---- Map Editor --- - -* Added: Undo/Redo functionality. -* Added: Street lamps and the dead looking tree. - - - -------------------------------------------------------------------------------- -Version 0.20 - released 2013-03-24 -------------------------------------------------------------------------------- - -In this version major new features include in-game movies, objects that -occupy only the edge of a tile and the graph window. - - - ---- Main features not yet implemented --- - -* Epidemics. -* Rats (and the rat level). -* Insurance company graphs, illness graphs. -* Visual effects on patients with serious radiation and jellyitis. -* Some fullscreen animations such as the winning letter. -* Multiplayer support. - -For a (nearly) complete list, visit our Programming Ideas wiki page: -http://code.google.com/p/corsix-th/wiki/ProgrammingIdeas - - - ---- Known Issues --- - -* Emotion icons don't appear just above a humanoid's head at all times. -* Main menu/in-game may glitch when using the OpenGL version. - -For a complete list, visit the issue tracker: -http://code.google.com/p/corsix-th/issues/list - - - ---- Gameplay --- - -* Added: Radiators and other "edge tile" objects now occupy just one edge of - the tile, inline with the original game. As a result one tile corridors can - now be heated properly. An addition is that you can place many such objects - on a single tile as long as they face different directions. - -* Added: Possibility to play movies in-game. At the moment the intro movie, - advancement between levels and the win/lose movies has been added. - -* Added: The atom analyzer can now be built in the research department if it - is available on the map. - -* Added: User actions are no longer allowed by default (for new games) when - the game is paused. When trying this it might seem like it doesn't work - correctly, but we try to mimic the original as much as possible. This for - example means that a staff member being placed as you pause will disappear - from the cursor. We might change this behaviour in the future though. - -* Added: Some background sounds, coughs, phones ringing etc. - -* Change: Placing a member of staff inside a room that is already occupied - will now replace that person. - -* Fix: Earthquakes could be four times as severe as intended. Still todo: - A tremor before a coming big earthquake. - -* Fix: Crashes in certain situations involving receptionists and reception - desks. -* Fix: Patients being handled at a reception desk even if no receptionist - is present. -* Fix: Allow patients to be sent to the research room only if the corresponding - room is not yet researched (so not if it is researched but not built). -* Fix: Don't cancel a place staff action just because the player happens to - click on a door. -* Fix: The VIP would try to sit down if there was a queue for the reception desk. - The VIP will no longer ever try to sit down, and he will have priority in - the queue anyway. -* Fix: If a member of staff was done resting at the same time as he/she was - also finished using the pool table or the video game another object in the - room could get reserved indefinitely. - - - ---- User Interface --- - -* Added: You can now see in the bank statement which drug company a certain - drug was bought from. It has no effect on gameplay though. - -* Added: The adviser now tells you why the research screen can't be opened - before you have built a research department. - -* Added: The Town Map functionality has been extended inline with Theme - Hospital. For example, if you right-click somewhere in your hospital the - view will be moved there. - -* Added: Available options on open faxes now gets updated if for example a room - explodes or the player builds a research department. -* Added: Keyboard shortcuts F1 - F9 for the fullscreen windows. They are NOT the - same as in original TH but instead correspond to the order on the bottom panel. -* Added: Possibility to choose font file in the options dialog. -* Added: Player name is now customizable in the new game dialog. - -* Removed: Keyboard shortcuts F8 and F9 for debug fax and debug patients. -* Change: Don't require debug mode to be able to dump the gamelog. -* Change: The shortcut for dumping strings is now Ctrl+T instead of Ctrl+Shift+D. - -* Change: Restructured options window to make it more consistent, less clutter-y - and smaller. -* Change: It is now possible to concentrate research on operating theatre - diseases and redistribution of research is automatically done when - a category has been completely researched. -* Change: Add disease name to patients' treatment history when they are - diagnosed. -* Change: Buttons on the bottom panel for fullscreen windows are now - toggle buttons. -* Change: Reordered entries of graphs menu to correspond with order in - bottom panel. - -* Fix: Colour selection algorithm for freetype fonts resulted in unreadable text - on faxes for some languages. -* Fix: When an unanswered fax became meaningless (e.g. if you built the - required room), it was only removed if its message button was visible at the - bottom panel (not if it was queued because of 5 buttons being there already). -* Fix: Update the drug casebook if the last room of one kind explodes. -* Fix: The directory browser was not always shown if the chosen Theme Hospital - install directory was illegal. -* Fix: Settings changed in the game will be saved immediately so that they - persist to the next session regardless of how the game is shut down. -* Fix: The bottom panel is no longer always on top, making fullscreen - dialogs truly fullscreen on 640x480. -* Fix: Don't play any announcements if there is no receptionist to do it. -* Fix: The adviser would not idle again if a new message arrived as he was - idling from a previous message. -* Fix: While a player viewed the confirm dialog to delete a room he/she could - continue to edit the room and complete it again resulting in an inconsistent - game state. - - - ---- Graphics --- - -* Added: The graph dialog now actually displays graphs and statistics information. - -* Added: It is now possible to choose among three colour scales for warmth - level. Look in the top menu for this choice. - -* Added: Print some info in the command prompt when the user wants to take - a screenshot, so he can see if and why it failed. -* Added: Screenshot functionality for OpenGL version. -* Change: Screenshots get saved to a dedicated screenshot folder now, - which can be changed in the config. -* Fix: Loading a game on startup where a fullscreen window was open would - open with the font messed up. -* Fix: Taking a screenshot (Ctrl+S) is now possible under windows without - fiddling in a lua file. - - - ---- Translations --- - -* Added: The beginning of Brazilian Portuguese and Hungarian. -* Change: The "utf8" prefix has been obsolete for some time and has been - removed from all language files. - - - ---- When using Demo files --- - -* Fix: The game would crash if the player tried to open the staff management - dialog by clicking on a staff portrait in the staff dialog. - - - -------------------------------------------------------------------------------- -Version 0.11 - released 2012-11-17 -------------------------------------------------------------------------------- - -This is a bugfix release. For known issues etcetera, check out the -changelog for version 0.10 below. - - --- Gameplay -- - -* Fix: Patients were not fully diagnosed according to settings - in the policy screen. -* Fix: The game now handles a player trying to cheat into an earthquake - on levels 1-4. -* Fix: It was not possible to sell equipment in rooms if you had a negative - balance. -* Fix: Handymen could not be placed inside rooms. -* Fix: Handymen would get called to clean soot in blown up rooms. -* Fix: Machines that need to be repaired will now cancel that request if - they are blown up. -* Fix: If a cured patient was leaving a room just as it crashed because - of an earthquake the game would throw an error. -* Fix: Alien DNA could under some circumstances not have the - "concentrate research" button clicked without triggering a crash. -* Fix: A crash occurring under some circumstances if the player picked - up a staff member. - - --- User Interface -- - -* Enchancement: Since consultants are unable to learn new skills icons for - not yet fully learned skills are now removed when a doctor is promoted. -* Fix: Disabling background music no longer disables sound effects on Windows. -* Fix: Checking if a sound exists crashed the game if there was no sound - archive at all. -* Fix: If the player paused the game from the top menu bar while an earthquake - was active it would be impossible to scroll. - - --- Graphics -- - -* Fix: On a few levels some sliding doors would not animate correctly. -* Fix: Vomiting standard males had the wrong animation. - - - -------------------------------------------------------------------------------- -Version 0.10 - released 2012-09-24 -------------------------------------------------------------------------------- - --- How versions work -- - -If you have been wondering how the new version system works: -When major new features are added the second digit is increased. -When there are only fixes or smaller new features the third digit -is increased. - -In this version, for example, earthquakes have been added. - --- Not Yet Implemented -- - -* Epidemics -* Rats -* Graphs -* Visual effects on patients with serious radiation and jellyitis. -* Fullscreen animations such as the level screen and winning letter. - --- Known Issues -- - -* If the X-Ray Viewer is inaccessible in the Operating Theatre no image will - be shown on it. -* If the user exits the game via "the cross" when in windowed mode settings - are not saved. -* Radiators and other "edge tile" objects occupy a whole tile instead of - just one edge of the tile. - --- Gameplay -- - -* Added: Earthquakes have recently been reported! -* Added: Handyman priorities have been added. They can also be told to stay - and respond to calls in one building (parcel) only. -* Added: Staff's happiness will change due to more environmental factors. - -* Change: The files containing dumped strings are now created alongside the - config file instead of in the installation directory. - -* Fix: Handymen will now meander inside a room until the machine which needs - repair is free for use. -* Fix: The URL in the config file pointing to better quality music was outdated. - Note that this only affects new installations. -* Fix: Two identical entries were shown in the drug casebook if a new disease - was discovered when it was open. -* Fix: Don't crash when a saved game with the town map open is loaded. -* Fix: Too large rooms could make them unusable. -* Some graphical glitches have been fixed. - --- User Interface -- - -* Added: The Map Editor and Animation Viewer have new icons. -* Change: In debug mode all gamelog output is now also displayed in the - command prompt. -* Fix: Don't initiate a window move if it happens to be below a top menu - selection. -* Fix: Don't show the main menu under any circumstances when closing the - options menu in-game. - --- Map Editor -- - -* Fix: The "Save" and "Save As" buttons now do what they should do. -* Fix: There were some strange log messages on opening the editor. -* Added: The arrow keys can now be used to scroll the map. -* Change: Removed a lot of tiles from the palette, since maps may not - work as intended if they would be used. - -------------------------------------------------------------------------------- -Version 0.01 - released 2012-03-24 -------------------------------------------------------------------------------- - --- Not Yet Implemented -- - -* Earthquakes -* Epidemics -* Handyman priorities -* Rats -* Graphs -* Visual effects on patients with serious radiation and jellyitis. -* Fullscreen animations such as the level screen and winning letter. - --- Known Issues -- - -* If the X-Ray Viewer is inaccessible in the Operating Theatre no image will - be shown on it. -* If the user exits the game via "the cross" when in windowed mode settings - are not saved. -* Radiators and other "edge tile" objects occupy a whole tile instead of - just one edge of the tile. - --- Gameplay -- - -* Added: A host of awards given at year end. -* Added: A new mode: Free Build Mode. In this mode you don't have to worry - about money. All custom maps can be played in this mode. -* Added: Patient animations such as yawning and checking watch when waiting. - -* Change: The queue size for a room can be set to 0 to prevent patients - from going there. -* Change: Patients now spend some more time in the ward. - -* Fix: Crash when removing a room that has humanoids on their way to it. -* Fix: Patients sitting down, but about to get a soda got ordered to sit down again. -* Fix: A crash could occur if a new room was accepted when there were multiple types - of objects left to place. -* Fix: Emergencies with diseases not available on a level no longer happen. -* Fix: The VIP no longer makes staff be called to the rooms he visits. -* Fix: With multiple reception desks new patients now find their way to the - reception with the least queue size. -* Fix: The wrong amount of money was returned when selling a room. -* Fix: Aliens could not be cured on the last two levels. -* Fix: The transparent walls setting made new rooms remove outer walls. -* Fix: Sometimes patients who had left the hospital could still wait for a new room, - making said room impossible to build. -* Fix: A crash when the staff member left a room before the patient. -* Fix: Build cost of objects were not always correct. - --- User Interface -- - -* Added: The save and load dialogs can now sort both ascending and descending - and are a little more spacy. -* Added: More messages in the progress report dialog. -* Added: More advice in different situations from the adviser. -* Added: Adviser messages now has priorities, making more important messages - appear faster. - -* Change: When the mouse cursor leaves the game window it will stop scrolling - the in-game world. -* Change: The message when a crash occurs is now a little more informative, and - humanoids no longer get stuck as easily. - -* Fix: The staff management window is now updated when staff is hired or - fired from outside the window itself. -* Fix: If the desired language cannot be loaded on startup the game now - reverts to English instead of crashing. -* Fix: The game could not autosave if the save or load dialog was open. - -* The auto-scroll setting is now saved between sessions. -* The adviser can now be turned off from the top menu. -* The game uses a new icon. - --- Map Editor -- - -* Fix: The game no longer crash just because the map builder has not added any - access roads from the edge of the map. - -------------------------------------------------------------------------------- -Version Beta 8 - released 2011-09-24 -------------------------------------------------------------------------------- - --- Gameplay -- - -* Fix: Patients should manage to use benches more often now. -* Fix: Staff will never have the "waiting for patient" mood when in a training - room or a staff room anymore. -* Change: Which diagnosis rooms different patients go to have been changed - to be more like the original game. -* Change: No patients will arrive until you have both a receptionist and a reception - desk. There will be no emergencies or VIP visits either until this criterion is met. -* Added: People may now puke or pee on the floor. -* Added: Various things such as litter and plants affect patient happiness. -* Added: A doctor may now get crazy if he is waaay too tired. -* Added: VIP visits. Watch out for those picky black suit visitors! -* Added: The "guess cure" fax message will now properly pop up. - --- User Interface -- - -* Change: The save and load dialogs now look a little different. Autosaves are stored - in a separate folder and there can be up to 12 autosaves at the same time. One for - each month. The dialogs now show when a save was made, and the list can also be - sorted by this criterion. -* Added: It is now possible to cycle through owned machines by right-clicking - the machine name in the machine dialog. -* Added: Sound, announcement and music volumes and on/off settings are now - saved between sessions.s - --- Graphics -- - -* Added: Waiting patients may sometimes check their watch or start to tap their foot. -* Added: Soda machines now sell more than soda cans. This can be seen through the - litter people throw on the floor after using said machines. -* Added: (Animation Viewer) A new export function has been added. Note that there - is currently no import equivalent, so it is mostly for people to try out and - see what graphics there are in the game. In the future we hope to make it possible - to import these graphics after changing them in your favourite graphics program. - --- Translations -- - -New language: Polish - -------------------------------------------------------------------------------- -Version Beta 7 - released 2011-06-24 -------------------------------------------------------------------------------- - --- Known Issues -- - -* If the X-Ray Viewer is inaccessible in the Operating Theatre the whole - room will be unusable. -* There are still many features which are not yet implemented including trash, - earthquakes, epidemics and awards. -* The graph window doesn't show any graphs. -* Handyman priorities are not yet fully implemented. - --- Gameplay -- - -* Added: Staff severance pay. -* Added: Patients may die if they don't get treated in time. -* Added: Doctors slowly gain skill when working. -* Added: Extra objects and the number of trainees influence speed of training - in the training room. -* Added: Even with no research new machines will eventually become available. -* Added: Some patients have started littering your hospital with soda cans! - Make sure you have enough handymen to keep your hospital clean. -* Added: Modern heating systems aren't as reliable as they used to be. Prepare - for breakdowns now and then. - -* New disease: Alien DNA! Note that there are still a few glitches to fix - concerning this new disease. - -* Change: Vending maintenance costs have increased throughout the world and - as a result Sodas now cost $20, up from $15. -* Change: Heating costs are calculated on a per day basis, rather than per month. -* Change: Machine and drug improvements are now made evenly across all eligible - objects rather than maxing one at a time. -* Change: Humanoids never meander outside anymore. - -* Fix: Handymen no longer crash the game when trying to water an unreachable - plant. -* Fix: Staff resting in the staff room should keep their sofa until fully - rested if there's nothing else to do. -* Fix: The player can't hire new staff or pay bonuses without a positive balance. - --- User Interface -- - -* Added: The graph window, no graphs yet though. -* Added: Right click menu in the queue dialog. -* Added: Confirmation dialog when about to fire a member of staff. - -* Fix: If there is only one person who is in an emergency, use the singular - form in the sentence. -* Fix: The pickup item button in the edit room dialog is now fully functional. -* Fix: The pointer should no longer jump around in Linux when using SDL. - --- Graphics -- - -* Added: The scanner uses more than one animation. - -* Fix: Some objects were cut in half after a relocation. - --- Translations -- - -* Change: If the specified language is not found, try to revert to English. -* Fix: Competitor names are now translatable. - -------------------------------------------------------------------------------- -Version Beta 6 - released 2011-03-24 -------------------------------------------------------------------------------- - --- Gameplay -- - -* Feature: Staff speed! -* Added: All parts of research have been implemented, including - machine strength improvements, drug improvements and the - "concentrate research" button in the drug casebook. -* Added: Overdraft charges for having a negative balance. -* Fix: The length of a day was about half as long as it should be. -* Fix: A few occurrences of bone-idle patients have been resolved. -* Fix: Juniors were not correctly labeled as Doctors after promotion. -* Fix: Some crashes regarding receptionists. -* Fix: Never charge less than initial cost when reputation is below 500. -* Fix: Some repair animations were too short. -* Fix: Don't check winning and losing conditions so often. -* Fix: Taking loans can now make the player avoid losing. -* Fix: Level 7 had an emergency with an unavailable disease. -* Fix: Doctors on their way back to the research room or training room - will no longer answer to any calls. -* Fix: Don't crash if a patient in a machine is sent home. -* Fix: Various tweaks to the operating theatre logic. -* Fix: Don't crash if the staff window of a leaving staff member - is open when he/she leaves the world. -* Fix: Persistant data (salary, built rooms etc) are no longer lost - after restarting a level. - --- User Interface -- - -* Feature: The drug casebook now shows if you can treat a disease or not, - and in the latter case the tooltip tells you what is missing. Actual - price is shown after some time, instead of charge %. -* Feature: Press and hold on value buttons will now make the value continue - to increase until the button is released again. -* Feature: The Theme Hospital installation path can be changed from the - options menu. -* Added: The adviser will help out in a few more situations. -* Fix: Mouse position events such as moving staff around didn't work - when scrolling using the arrow keys. -* Fix: Tooltips are now updated more frequently, - most evidently in the research pane. - --- Translations -- - -* Feature: CorsixTH now supports TrueType fonts via FreeType2! -* Feature: To assist translators a new diff file is now created when you - choose the debug option "dump strings" (with languages other than English). - It contains those strings which are either found in English but not in - the given language, or found in the given language but not in English. - -* New languages: Traditional Chinese, Simplified Chinese, Russian. - -------------------------------------------------------------------------------- -Version Beta 5 - released 2010-12-24 -------------------------------------------------------------------------------- - --- Gameplay -- - -* Feature: (Some) Cheats added. Type 24328 into the fax machine to get access to them. -* Feature: Custom map "Avatar" added. -* Feature: Player's "salary" (read: score) now increases over your level progress. -* Feature: Level based interest rate. -* Feature: Level based "starting staff" (e.g. original level 5). -* Feature: "No deaths" trophy added. -* Fix: Error could occur when losing a game. -* Fix: Multiple handymen watering the same plant at the same time. -* Fix: Some placements of opposite doors/objects were wrongly forbidden. -* Fix: Error could occur when building a surgery. -* Fix: Autopsy now has an appropriate impact on research. -* Fix: Salaries for doctors were too high. -* Fix: In some cases lose conditions were not triggered. -* Fix: Research room door could disappear after autopsy. - ... and various other bugs fixed. - --- User Interface -- - -* Feature: The player is now told the reason why he lost, when he loses, instead of being left in the dark. -* Fix: Wrong winning faxes shown for levels 5-11. -* Fix: Weird scrolling behavior could occur after loading a game. -* Fix: No tutorial when playing with demo files. -* Fix: Adviser disappeared too quickly during tutorial. -* Some improvements to textboxes. -* Some improvements to windows. - ... and various other small improvements and fixes. - --- Translations -- - -* Fix: Error caused by some winning faxes in Norwegian. - -------------------------------------------------------------------------------- -Version Beta 4 - released 2010-11-12 -------------------------------------------------------------------------------- - --- Gameplay -- - -* Feature: The Research Department and research policy dialog. -* Feature: The Operating Theatre. -* Feature: Not all parcels are owned by the player from the beginning, but - can now be bought from the Town Map dialog. -* Feature: Calculate staff wages and properties for those for hire based - on the level files. - -* Added 7 new diseases related to the operating theatre. -* Added treatment room: Operating Theatre. - -* Fix: The adviser no longer complains about watering of plants all the time. -* Fix: Some crashes related to crashed rooms has been fixed. - - --- User Interface -- - -* Feature: Possibility to choose difficulty level when starting a new game. -* Feature: Zooming (only when using DirectX or OpenGL). -* Feature: The Annual Report Dialog. - -* Graphics: Improved the main menu background. -* Fix: Solved issues with non-English keyboard layouts. - - --- Translations -- - -* New languages: Finnish and Danish -* Fix: When playing the game in French it no longer crashes upon completion of a level. - - -------------------------------------------------------------------------------- -Version Beta 3 - released 2010-06-24 -------------------------------------------------------------------------------- - --- Gameplay -- - -* Feature: Swing doors (used by new diagnosis room ward). -* Feature: Plants will now droop unless they are watered by a handyman. -* Feature: Adjustable handyman priorities. -* Feature: Existing rooms can now be edited and deleted. -* Feature: Watch for initial opening of hospital at start of each level. -* Feature: Each level has its own goals, shown at the beginning of the level and - in the new status dialog. When the goals have been achieved the player may go on - to the next one. -* Feature: Not all implemented rooms and diseases appear anymore in each level, but - only those defined by the level script. -* Feature: Support for custom levels with their own maps and level scripts. -* Feature: A heating system that depends on outside temperature, adjacent tiles - and radiators among other things. - -* Added 6 new diseases -* Added treatment rooms: Jelly Vat, Decontamination -* Added diagnosis rooms: Blood Machine, Ward, Scanner - -* Fix: Staff needed in rooms is handled much better. -* Fix: Objects retain their statistics when moved. -* Fix: A horde of other bugs have also been fixed. - - --- User Interface -- - -* Feature: Savegames are no longer limited to 8 slots + autosave. -* Feature: Fullscreen mode, screen resolution and interface language can be changed - ingame. The changes are saved in the config file and preserved. -* Feature: Hovering the mouse over a room will mark all patients in queue for this room. -* Feature: Patients can be moved to the head/tail of queues in the corresponding dialog. - They can also be placed between other patients. -* New dialogs: Load Game, Save Game, Custom Level to cope with arbitrary number of - savegames/levels. -* New dialog: Options -* New dialog: Progress Report (Status) showing status of the current level's goals. -* Added all tooltips that were still missing. - - --- Misc -- - -* Translations: Italian, Spanish and French: added new strings not available in vanilla TH, - Portuguese (WIP) and Dutch (WIP) -* The configuration file and saved games can now, if desired, also be stored in the user's - home directory or equivalent. - - -------------------------------------------------------------------------------- -Version Beta 2 - released 2010-03-24 -------------------------------------------------------------------------------- - -* Feature: Save / Load functionality. -* Feature: Patients and staff now have a need for heat (from radiators) in - order to stay happy. Patients will also get thirsty (build drinks machines) - and will need a bathroom sooner or later, and staff will ask for a salary - raise when unhappy. -* Feature: Machines will need repair now and then. A dialog that shows - necessarry information is displayed when the machine is clicked. -* Feature: Dynamic Information Bar in the bottom right corner of the UI added. - It shows information about entities beneath the mouse cursor. -* Feature: The training room can now be built, where doctors can increase - their skill and get additional traits if a consultant is present. -* Feature: When a patient cannot be cured or a room is missing a fax will - arrive and ask the player what to do. -* Feature: A new string system that allows us to add new (translatable) text - to the game, correct mistakes in existing languages and add new languages. -* Feature: A tutorial is offered to the player at the start of the game. -* Feature: Tooltips are displayed when hovering over buttons for some time. -* Feature: Emergencies may happen every now and then. -* Feature: Hospital reputation system. -* Feature: Humurous disease description faxes are now shown when a disease is - first diagnosed. -* Feature: Room blueprints can be resized during the build process. - -* New Dialogs: Hospital Policy, Drug Casebook, Bank Manager, Staff Management, - Town Map (work in progress), Main Menu -* Many new key shortcuts (see Hotkeys wiki page for full list). -* Dialogs can now be re-positioned by dragging them to where they are wanted. -* Added floating money signs to better indicate where money is coming from. -* Added comments from the advisor in more situations. - -* 10 new diseases. -* New treatment room: Hair Restorer -* Additional functional diagnosis rooms: General Diagnosis, Ultrascan, X-Ray -* Room queues should now re-balance themselves when new rooms are built. - -* Translation: Norwegian (bokml). - -A lot of other small improvements. -Also, a great number of bugs have been squashed. Most remaining bugs are no -longer fatal, and can be continued from. - - -------------------------------------------------------------------------------- -Version Beta 1 - released 2009-12-24 -------------------------------------------------------------------------------- - -Initial release diff -Nru corsix-th-0.30/CorsixTH/CMakeLists.txt corsix-th-0.62/CorsixTH/CMakeLists.txt --- corsix-th-0.30/CorsixTH/CMakeLists.txt 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/CMakeLists.txt 2018-07-21 11:13:17.000000000 +0000 @@ -1,46 +1,40 @@ # Sanity check -IF(CORSIX_TH_DONE_TOP_LEVEL_CMAKE) -ELSE(CORSIX_TH_DONE_TOP_LEVEL_CMAKE) -message(FATAL_ERROR "Please run cmake on the top-level directory, not this one.") -ENDIF(CORSIX_TH_DONE_TOP_LEVEL_CMAKE) +if(CORSIX_TH_DONE_TOP_LEVEL_CMAKE) +else() + message(FATAL_ERROR "Please run cmake on the top-level directory, not this one.") +endif() # Project Declaration -PROJECT(CorsixTH) +project(CorsixTH) -# Basic platform dependant stuff -IF(UNIX) - IF(APPLE) - # fruit goes here - add_subdirectory(SDLMain) - ELSE(APPLE) - # regular unix/linux - ENDIF(APPLE) -ELSE() - IF(WIN32) - # Win32 specific - IF(MSVC) - # We want to bind against the very latest versions of the MSVC runtimes - add_definitions(/D "_BIND_TO_CURRENT_VCLIBS_VERSION=1") - ELSE(MSVC) - IF(MSYS) - # MSYS stuff - ELSE(MSYS) - # What's left? MINGW? CYGWIN? BORLAND? - ENDIF(MSYS) - ENDIF(MSVC) - ELSE(WIN32) - # other OS (not UNIX, not 32/64 bit Windows) - ENDIF(WIN32) -ENDIF(UNIX) +if(APPLE) + add_subdirectory(SDLMain) +elseif(MSVC) + # We want to bind against the very latest versions of the MSVC runtimes + add_definitions(/D "_BIND_TO_CURRENT_VCLIBS_VERSION=1") +endif() + +if(USE_SOURCE_DATADIRS) + set(CORSIX_TH_DATADIR ${CMAKE_CURRENT_SOURCE_DIR}) + set(CORSIX_TH_INTERPRETER_PATH ${CORSIX_TH_DATADIR}/CorsixTH.lua) +elseif(MSVC) + set(CORSIX_TH_DATADIR CorsixTH) + set(CORSIX_TH_INTERPRETER_PATH CorsixTH.lua) +elseif(APPLE) + set(CORSIX_TH_DATADIR CorsixTH.app/Contents/Resources/) + set(CORSIX_TH_INTERPRETER_PATH ${CMAKE_INSTALL_PREFIX}/${CORSIX_TH_DATADIR}/CorsixTH.lua) +else() + set(CORSIX_TH_DATADIR ${CMAKE_INSTALL_DATADIR}/corsix-th) + set(CORSIX_TH_INTERPRETER_PATH ${CMAKE_INSTALL_FULL_DATADIR}/corsix-th/CorsixTH.lua) +endif() # Modify the config.h based upon our selection of options -CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/CorsixTH/Src/config.h.in ${CMAKE_BINARY_DIR}/CorsixTH/Src/config.h) -INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/CorsixTH/Src/) -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/agg/include/) +configure_file(${CMAKE_SOURCE_DIR}/CorsixTH/Src/config.h.in ${CMAKE_BINARY_DIR}/CorsixTH/Src/config.h) +include_directories(${CMAKE_BINARY_DIR}/CorsixTH/Src/) # Generate source files list # Note: Done after generating config.h -FILE(GLOB_RECURSE corsixth_source_files +file(GLOB_RECURSE corsixth_source_files ${CMAKE_SOURCE_DIR}/CorsixTH/SrcUnshared/*.cpp ${CMAKE_SOURCE_DIR}/CorsixTH/SrcUnshared/*.c ${CMAKE_SOURCE_DIR}/CorsixTH/SrcUnshared/*.h @@ -49,19 +43,18 @@ ${CMAKE_SOURCE_DIR}/CorsixTH/Src/*.c ${CMAKE_SOURCE_DIR}/CorsixTH/Src/*.hpp ${CMAKE_SOURCE_DIR}/CorsixTH/Src/*.h + ${CMAKE_SOURCE_DIR}/common/rnc.cpp + ${CMAKE_SOURCE_DIR}/common/rnc.h ${CMAKE_SOURCE_DIR}/CorsixTH/Src/shaders/*.psh ${CMAKE_BINARY_DIR}/CorsixTH/Src/config.h ${CMAKE_SOURCE_DIR}/CorsixTH/Lua/api_version.lua ${CMAKE_SOURCE_DIR}/CorsixTH/CorsixTH.rc ${CMAKE_SOURCE_DIR}/LFS/*.c ${CMAKE_SOURCE_DIR}/LPEG/*.c - ${CMAKE_SOURCE_DIR}/agg/src/agg_image_filters.cpp ) # Declaration of the executable -IF(APPLE) - add_definitions(-DIS_CORSIXTH_APP) - +if(APPLE) set(corsixth_icon_file ${CMAKE_SOURCE_DIR}/CorsixTH/Icon.icns) set_source_files_properties( ${corsixth_icon_file} @@ -75,158 +68,188 @@ set_target_properties(CorsixTH PROPERTIES LINK_FLAGS_MINSIZEREL "-dead_strip") set_target_properties(CorsixTH PROPERTIES XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks") - #Add an extra step at the end of the build process to copy the resources into the bundle. - add_custom_command(TARGET CorsixTH - POST_BUILD - COMMAND rsync -rv --include-from ${CMAKE_SOURCE_DIR}/CorsixTH/RequiredResources.txt ${CMAKE_SOURCE_DIR}/CorsixTH/ \${TARGET_BUILD_DIR}/\${FULL_PRODUCT_NAME}/Contents/Resources) - - target_link_libraries(CorsixTH SDLmain) - INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/CorsixTH/SDLMain/) -ELSE() + target_link_libraries(CorsixTH SDL2main) + include_directories(${CMAKE_BINARY_DIR}/CorsixTH/SDLMain/) +else() add_executable(CorsixTH ${corsixth_source_files}) +endif() + +if(UNIX AND NOT APPLE) + set_target_properties(CorsixTH PROPERTIES OUTPUT_NAME corsix-th) +endif() + +# Add an extra step to copy built DLLs on MSVC +if(USE_VCPKG_DEPS) + include(CopyVcpkgLua) ENDIF() -# Finding libraries +## Finding libraries # Find SDL -FIND_PACKAGE(SDL REQUIRED) -IF(SDL_FOUND) - INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR}) - IF(SDLMAIN_LIBRARY STREQUAL "") - IF(WIN32) - # SDLmain not being found is not fatal, as the win32 SDLmain.c is distributed with CorsixTH - ELSE(WIN32) +if(MSVC AND USE_VCPKG_DEPS) + find_package(SDL2 CONFIG REQUIRED) + target_link_libraries(CorsixTH SDL2::SDL2) + target_link_libraries(CorsixTH SDL2::SDL2main) +else() + find_package(SDL2 REQUIRED) + if(SDL_FOUND) + include_directories(${SDL_INCLUDE_DIR}) + if(SDLMAIN_LIBRARY STREQUAL "") message(FATAL_ERROR "Error: SDL was found but SDLmain was not") message("Make sure the path is correctly defined or set the environment variable SDLDIR to the correct location") - ENDIF(WIN32) - ENDIF(SDLMAIN_LIBRARY STREQUAL "") - # No need to specify sdlmain seperately, the FindSDL.cmake file will take care of that. If not we get an error about it - TARGET_LINK_LIBRARIES(CorsixTH ${SDL_LIBRARY}) - message(" SDL found") -ELSE(SDL_FOUND) - message(FATAL_ERROR "Error: SDL library not found, it is required to build. Make sure the path is correctly defined or set the environment variable SDLDIR to the correct location") -ENDIF(SDL_FOUND) + endif() + # No need to specify sdlmain separately, the FindSDL.cmake file will take care of that. If not we get an error about it + target_link_libraries(CorsixTH ${SDL_LIBRARY}) + message(" SDL found") + else() + message(FATAL_ERROR "Error: SDL library not found, it is required to build. Make sure the path is correctly defined or set the environment variable SDLDIR to the correct location") + endif() +endif() # Find Lua -FIND_PACKAGE(Lua REQUIRED) -IF(Lua_FOUND) - TARGET_LINK_LIBRARIES(CorsixTH ${LUA_LIBRARY}) - INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR}) +find_package(Lua REQUIRED) +if(Lua_FOUND) + target_link_libraries(CorsixTH ${LUA_LIBRARY}) + include_directories(${LUA_INCLUDE_DIR}) + # Special link flags needed on OSX/64bit, according to: http://luajit.org/install.html + # If these are not specified, luaL_newstate() returns NULL and we get this: + # Fatal error starting CorsixTH: Cannot open Lua state. + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND LUA_INTERPRETER_TYPE STREQUAL "LuaJIT" AND CMAKE_SIZEOF_VOID_P EQUAL 8) + target_link_libraries(CorsixTH "-pagezero_size 10000" "-image_base 100000000") + endif() message(" ${LUA_INTERPRETER_TYPE} found") -ELSE(Lua_FOUND) +else() message(FATAL_ERROR "Error: Lua library not found, it is required to build") -ENDIF(Lua_FOUND) +endif() + +# Add threading library +find_package(Threads) +target_link_libraries(CorsixTH ${CMAKE_THREAD_LIBS_INIT}) # Find SDL_mixer -IF(CORSIX_TH_USE_SDL_MIXER) - FIND_PACKAGE(SDL_mixer REQUIRED) - IF(SDLMIXER_FOUND) - TARGET_LINK_LIBRARIES(CorsixTH ${SDLMIXER_LIBRARY}) - INCLUDE_DIRECTORIES(${SDLMIXER_INCLUDE_DIR}) +if(CORSIX_TH_USE_SDL_MIXER) + find_package(SDL2_mixer REQUIRED) + if(SDLMIXER_FOUND) + target_link_libraries(CorsixTH ${SDLMIXER_LIBRARY}) + include_directories(${SDLMIXER_INCLUDE_DIR}) message(" SDL_mixer found") - ELSE(SDLMIXER_FOUND) - message("Error: SDL_mixer library not found, even though it was selected to be included") - ENDIF(SDLMIXER_FOUND) -ENDIF(CORSIX_TH_USE_SDL_MIXER) + else() + message(FATAL_ERROR "Error: SDL_mixer library not found, even though it was selected to be included") + endif() +endif() -message( STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}" ) +message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") # Find FFMPEG -IF(CORSIX_TH_USE_FFMPEG) - FIND_PACKAGE(FFmpeg COMPONENTS AVFORMAT AVCODEC AVUTIL SWSCALE SWRESAMPLE REQUIRED) - IF(FFMPEG_FOUND) - TARGET_LINK_LIBRARIES(CorsixTH ${FFMPEG_LIBRARIES}) - INCLUDE_DIRECTORIES(${FFMPEG_INCLUDE_DIRS}) - IF(APPLE) - TARGET_LINK_LIBRARIES(CorsixTH libz.dylib) - ENDIF() +if(CORSIX_TH_USE_FFMPEG) + find_package(FFmpeg COMPONENTS AVFORMAT AVCODEC AVUTIL SWSCALE SWRESAMPLE REQUIRED) + if(FFMPEG_FOUND) + target_link_libraries(CorsixTH ${FFMPEG_LIBRARIES}) + include_directories(${FFMPEG_INCLUDE_DIRS}) + if(APPLE) + target_link_libraries(CorsixTH libz.dylib) + endif() message(" FFmpeg found") - ELSE(FFMPEG_FOUND) - message("Error: FFmpeg library not found, even though it was selected to be included") - ENDIF(FFMPEG_FOUND) -ENDIF(CORSIX_TH_USE_FFMPEG) + else() + message(FATAL_ERROR "Error: FFmpeg library not found, even though it was selected to be included") + endif() +endif() + +if(CORSIX_TH_USE_LIBAV) + find_package(LibAV COMPONENTS AVFORMAT AVCODEC AVRESAMPLE AVUTIL SWSCALE REQUIRED) + if(LIBAV_FOUND) + target_link_libraries(CorsixTH ${LIBAV_LIBRARIES}) + include_directories(${LIBAV_INCLUDE_DIRS}) + if(APPLE) + target_link_libraries(CorsixTH libz.dylib) + endif() + message(" LibAV found") + else() + message(FATAL_ERROR "Error: LibAV library not found, even though it was selected to be included") + endif() +endif() # Find Freetype2 -IF(CORSIX_TH_USE_FREETYPE2) - FIND_PACKAGE(Freetype REQUIRED) - IF(FREETYPE_FOUND) - TARGET_LINK_LIBRARIES(CorsixTH ${FREETYPE_LIBRARIES}) - INCLUDE_DIRECTORIES(${FREETYPE_INCLUDE_DIRS}) - IF(APPLE) - TARGET_LINK_LIBRARIES(CorsixTH libz.dylib) - TARGET_LINK_LIBRARIES(CorsixTH libbz2.dylib) - ENDIF() +if(CORSIX_TH_USE_FREETYPE2) + find_package(Freetype REQUIRED) + if(FREETYPE_FOUND) + target_link_libraries(CorsixTH ${FREETYPE_LIBRARIES}) + include_directories(${FREETYPE_INCLUDE_DIRS}) + if(APPLE) + target_link_libraries(CorsixTH libz.dylib) + target_link_libraries(CorsixTH libbz2.dylib) + endif() message(" FreeType2 found") - ELSE(FREETYPE_FOUND) - message("Error: FreeType2 library not found, even though it was selected to be used") - ENDIF(FREETYPE_FOUND) -ENDIF(CORSIX_TH_USE_FREETYPE2) - -# Find OpenGL -IF(CORSIX_TH_USE_OGL_RENDERER) - FIND_PACKAGE(OpenGL REQUIRED) - IF(OPENGL_FOUND) - TARGET_LINK_LIBRARIES(CorsixTH ${OPENGL_gl_LIBRARY}) - INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) - message(" OpenGL found") - ELSE(OPENGL_FOUND) - message(FATAL_ERROR "Error: OpenGL library not found, it is required to build (consider changing choice of renderer)") - ENDIF(OPENGL_FOUND) -ENDIF(CORSIX_TH_USE_OGL_RENDERER) - -# Find DirectX -IF(CORSIX_TH_USE_DX9_RENDERER) - FIND_PACKAGE(DirectX REQUIRED) - IF(DirectX_FOUND) - TARGET_LINK_LIBRARIES(CorsixTH ${DirectX_LIBRARY}) - TARGET_LINK_LIBRARIES(CorsixTH ${DirectX_D3DX9_LIBRARY}) - INCLUDE_DIRECTORIES(${DirectX_INCLUDE_DIR}) - message(" DirectX found") - ELSE(DirectX_FOUND) - message(FATAL_ERROR "Error: DirectX library not found, it is required to build (consider changing choice of renderer)") - ENDIF(DirectX_FOUND) -ENDIF(CORSIX_TH_USE_DX9_RENDERER) - -# Find msinttypes for MSVC -IF(MSVC AND NOT CORSIX_TH_HAS_INTTYPES_H) - FIND_PATH(MSINTTYPES_INCLUDE_DIRS "inttypes.h" NO_DEFAULT_PATH) - MESSAGE(STATUS "Adding include directory: ${MSINTTYPES_INCLUDE_DIRS}") - INCLUDE_DIRECTORIES(${MSINTTYPES_INCLUDE_DIRS}) - SET(CORSIX_TH_HAS_STDINT_H 1) - SET(CORSIX_TH_HAS_INTTYPES_H 1) -ENDIF(MSVC AND NOT CORSIX_TH_HAS_INTTYPES_H) + else() + message(FATAL_ERROR "Error: FreeType2 library not found, even though it was selected to be used") + endif() +endif() + +if(MSVC AND CORSIX_TH_USE_VLD) + find_package(VLD REQUIRED) + if(VLD_FOUND) + target_link_libraries(CorsixTH ${VLD_LIBRARY}) + include_directories(CorsixTH ${VLD_INCLUDE_DIR}) + message(" VLD found") + else() + message(FATAL_ERROR "Error: VLD Library not found, it is required to build when USE_VLD is set") + endif() +endif() + +# Launch script to facilitate out of source builds +if(USE_SOURCE_DATADIRS) + #do not generate launch script. The default is fine for this case. +elseif(XCODE) + message(WARNING "By default you will not be able to run CorsixTH from Xcode. If you do not plan to deploy then run cmake with -DUSE_SOURCE_DATADIRS. If you want to both run and deploy from Xcode then set the command line arguments in your run scheme to --interpreter=${CMAKE_CURRENT_SOURCE_DIR}/CorsixTH.lua") +elseif(APPLE) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run-corsix-th-dev.sh.in.apple ${CMAKE_CURRENT_BINARY_DIR}/run-corsixth-dev.sh @ONLY) +elseif(UNIX) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run-corsix-th-dev.sh.in ${CMAKE_CURRENT_BINARY_DIR}/run-corsixth-dev.sh @ONLY) +elseif(MSVC) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CorsixTH.vcxproj.user.in ${CMAKE_CURRENT_BINARY_DIR}/CorsixTH.vcxproj.user @ONLY) +endif() -# Declaration of the install process -IF(APPLE) - #Just use the prefix as it's sufficient to just set the prefix to /Applications on Mac. - install(TARGETS CorsixTH BUNDLE DESTINATION .) +# Declaration of the install process +if(NOT USE_SOURCE_DATADIRS) + if(APPLE) + #Just use the prefix as it's sufficient to just set the prefix to /Applications on Mac. + install(TARGETS CorsixTH BUNDLE DESTINATION .) + elseif(MSVC) + install(TARGETS CorsixTH + RUNTIME DESTINATION ${CORSIX_TH_DATADIR} + LIBRARY DESTINATION ${CORSIX_TH_DATADIR} + ARCHIVE DESTINATION ${CORSIX_TH_DATADIR} + ) + install(FILES CorsixTH.ico DESTINATION ${CORSIX_TH_DATADIR}) + + # install dependencies + file(GLOB DLL_DEPS "${CMAKE_CURRENT_BINARY_DIR}/*.dll") + install(FILES ${DLL_DEPS} DESTINATION ${CORSIX_TH_DATADIR}) + file(GLOB LUA_DEPS "${CMAKE_CURRENT_BINARY_DIR}/*.lua") + install(FILES ${LUA_DEPS} DESTINATION ${CORSIX_TH_DATADIR}) + if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/mime") + install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mime" "${CMAKE_CURRENT_BINARY_DIR}/socket" DESTINATION ${CORSIX_TH_DATADIR}) + endif() + else() + install(TARGETS CorsixTH + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + endif() + install(DIRECTORY Campaigns Lua Levels DESTINATION ${CORSIX_TH_DATADIR}) + install(DIRECTORY Bitmap DESTINATION ${CORSIX_TH_DATADIR} + FILES_MATCHING REGEX ".*\\.(tab|pal|dat|png)$" + ) + install(FILES CorsixTH.lua ../LICENSE.txt DESTINATION ${CORSIX_TH_DATADIR}) - #Copy the required frameworks into the bundle. - IF(SDL_FOUND) - IF(SDL_LIBRARY MATCHES "\\.framework") #Only copy if it's an actual framework. - string(REPLACE "-framework Cocoa" "" SDL_FRAMEWORK_LOC ${SDL_LIBRARY}) - install(DIRECTORY ${SDL_FRAMEWORK_LOC} DESTINATION CorsixTH.app/Contents/Frameworks) - ENDIF() - ENDIF() - - IF(SDLMIXER_FOUND) - IF(${SDLMIXER_LIBRARY} MATCHES "\\.framework$") #Only copy if it's an actual framework. - install(DIRECTORY ${SDLMIXER_LIBRARY} DESTINATION CorsixTH.app/Contents/Frameworks) - ENDIF() - ENDIF() - - IF(LUA_FOUND) - IF(${LUA_LIBRARY} MATCHES "\\.framework$") #Only copy if it's an actual framework. - install(DIRECTORY ${LUA_LIBRARY} DESTINATION CorsixTH.app/Contents/Frameworks) - ENDIF() - ENDIF() - -ELSE() - install(TARGETS CorsixTH RUNTIME DESTINATION CorsixTH) - install(DIRECTORY Lua Levels DESTINATION CorsixTH PATTERN "*.svn" EXCLUDE) - install(DIRECTORY Bitmap DESTINATION CorsixTH - FILES_MATCHING REGEX ".*\\.(tab|pal|dat|png)$" - PATTERN "*.svn" EXCLUDE) - install(FILES CorsixTH.lua ../LICENSE.txt CorsixTH.ico DESTINATION CorsixTH ) -ENDIF() + if(APPLE) + # Fix the OS X bundle to include required libraries (create a redistributable app) + install(CODE " + INCLUDE(BundleUtilities) + SET(BU_CHMOD_BUNDLE_ITEMS ON) + FIXUP_BUNDLE(${CMAKE_INSTALL_PREFIX}/CorsixTH.app \"\" \"\") + ") + endif() +endif() Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/CorsixTH.aps and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/CorsixTH.aps differ diff -Nru corsix-th-0.30/CorsixTH/CorsixTH.deproj corsix-th-0.62/CorsixTH/CorsixTH.deproj --- corsix-th-0.30/CorsixTH/CorsixTH.deproj 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/CorsixTH.deproj 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ - - - - CorsixTH.lua - - - Lua\app.lua - - - Lua\audio.lua - - - Lua\class.lua - - - Lua\entity.lua - - - Lua\graphics.lua - - - Lua\humanoid.lua - - - Lua\map.lua - - - Lua\object.lua - - - Lua\strict.lua - - - Lua\ui.lua - - - Lua\window.lua - - - Lua\world.lua - - - Lua\dialogs\bottom_panel.lua - - - Lua\dialogs\build_room.lua - - - Lua\dialogs\edit_room.lua - - - Lua\dialogs\furnish_corridor.lua - - - Lua\dialogs\jukebox.lua - - - Lua\dialogs\patient.lua - - - Lua\objects\bench.lua - - - Lua\objects\door.lua - - - Lua\objects\drinks_machine.lua - - - Lua\objects\fire_extinguisher.lua - - - Lua\objects\plant.lua - - - Lua\objects\radiator.lua - - - Lua\objects\reception_desk.lua - - - Lua\rooms\general_diag.lua - - - Lua\rooms\gp.lua - - - Lua\rooms\inflation.lua - - - Lua\rooms\pharmacy.lua - - - Lua\rooms\psych.lua - - - Lua\rooms\staff_room.lua - - - Lua\rooms\toilets.lua - - - Lua\rooms\ward.lua - - - Lua\walls\blue.lua - - - Lua\walls\external.lua - - - Lua\walls\green.lua - - - Lua\walls\white.lua - - - Lua\walls\yellow.lua - - - config.txt - - - Lua\dialogs\menu.lua - - - Lua\dialogs\place_objects.lua - - diff -Nru corsix-th-0.30/CorsixTH/CorsixTH.lua corsix-th-0.62/CorsixTH/CorsixTH.lua --- corsix-th-0.30/CorsixTH/CorsixTH.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/CorsixTH.lua 2018-07-21 11:13:17.000000000 +0000 @@ -9,64 +9,31 @@ error "This file must be invoked by the CorsixTH executable" end --- Check Lua version -if _VERSION ~= "Lua 5.1" then - if _VERSION == "Lua 5.2" then - print "Notice: Lua 5.2 is not officially supported at the moment" - -- Compatibility: Keep the global unpack function - unpack = table.unpack - -- Compatibility: Provide a replacement for deprecated ipairs() - -- NB: It might be wiser to migrate away from ipairs entirely, but the - -- following works as an immediate band-aid - local rawget, error, type = rawget, error, type - if not pcall(ipairs, {}) then - local function next_int(t, i) - i = i + 1 - local v = rawget(t, i) - if v ~= nil then - return i, v - end - end - function ipairs(t) - if type(t) ~= "table" then - error("table expected, got " .. type(t)) - end - return next_int, t, 0 - end - end - else - error "Please recompile CorsixTH and link against Lua version 5.1" +-- Parse script parameters: +local run_debugger = false +for _, arg in ipairs({...}) do + if arg:match("^%-%-connect%-lua%-dbgp") then + run_debugger = true end end --- If being debugged in Decoda, turn off JIT compilation (as it cannot debug --- machine code). Note that this file cannot be debugged, but all other files --- can be. See http://www.unknownworlds.com/decoda/ for Decoda info. -if decoda_output then - _DECODA = true - if jit then - jit.off() - decoda_output "JIT compilation disabled" - end -else - _DECODA = false -end - -_MAP_EDITOR = _MAP_EDITOR or false - -- Redefine dofile such that it adds the direction name and file extension, and -- won't redo a file which it has previously done. local pathsep = package.config:sub(1, 1) local base_dir = debug.getinfo(1, "S").source:sub(2, -13) local code_dir = base_dir .. "Lua" .. pathsep +package.cpath = base_dir .. '?.so;' .. package.cpath for _, arg in ipairs{...} do local dir = arg:match"^%-%-lua%-dir=(.*)$" if dir then code_dir = dir .. pathsep end end + +package.path = code_dir .. "?.lua;" .. code_dir .. "?/init.lua;" .. package.path + local done_files = {} -local persist = require "persist" +local persist = require("persist") local save_results if table.pack then -- Lua 5.2 @@ -81,10 +48,22 @@ return ... end end -function dofile(name) - if pathsep ~= "/" then - name = name:gsub("/", pathsep) - end + +_G['corsixth'] = {} + +--! Loads and runs a lua file. +-- Similar to the built in require function with three important differenes: +-- * This function searches for --[[persistance: comments and maps the +-- following function into the persistence table. +-- * This function only searches in the Lua code directory +-- * This function is only able to load lua source files (not C modules or +-- compiled lua. +--!param name (string) +-- The name of the lua source file to run. Use dots to seperate directories, +-- and do not include the .lua file extension. +--!return The return value of whatever source file is opened. +corsixth.require = function(name) + name = name:gsub("%.", pathsep) if done_files[name] then local results = done_files[name] return unpack(results, 1, results.n) @@ -94,24 +73,62 @@ end -- Load standard library extensions -dofile "utility" +corsixth.require("utility") + +-- If requested run a Lua DBGp Debugger Client: +if run_debugger then + dofile("run_debugger")() +end + +-- Check Lua version +if _VERSION ~= "Lua 5.1" then + if _VERSION == "Lua 5.2" or _VERSION == "Lua 5.3" then + -- Compatibility: Keep the global unpack function + unpack = table.unpack + -- Compatibility: Provide a replacement for deprecated ipairs() + -- NB: It might be wiser to migrate away from ipairs entirely, but the + -- following works as an immediate band-aid + local rawget, error, type = rawget, error, type + if not pcall(ipairs, {}) then + local function next_int(t, i) + i = i + 1 + local v = rawget(t, i) + if v ~= nil then + return i, v + end + end + function ipairs(t) + if type(t) ~= "table" then + error("table expected, got " .. type(t)) + end + return next_int, t, 0 + end + end + else + error "Please recompile CorsixTH and link against Lua version 5.1, 5.2 or 5.3" + end +end +-- +-- A DBGp debugger can debug this file if you start a CorsixTH DBGp client & connect +-- it to a running server, using this CorsixTH startup arg: -debugger -- Enable strict mode -dofile "strict" +corsixth.require("strict") require = destrict(require) +dofile = destrict(dofile) -- Load the class system (required for App) -dofile "class" +corsixth.require("class") -- Load the main App class -dofile "app" +corsixth.require("app") -- Create an instance of the App class and transfer control to it strict_declare_global "TheApp" TheApp = App() TheApp:setCommandLine( - "--bitmap-dir="..base_dir.."Bitmap", - "--config-file="..dofile"config_finder", + "--bitmap-dir=" ..base_dir.. "Bitmap", + "--config-file=" .. corsixth.require("config_finder"), -- If a command line option is given twice, the later one is used, hence -- if the user gave one of the above, that will be used instead. ... diff -Nru corsix-th-0.30/CorsixTH/CorsixTH.rc corsix-th-0.62/CorsixTH/CorsixTH.rc --- corsix-th-0.30/CorsixTH/CorsixTH.rc 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/CorsixTH.rc 2018-07-21 11:13:17.000000000 +0000 @@ -7,7 +7,7 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" +#include "WinResrc.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -34,7 +34,7 @@ 2 TEXTINCLUDE BEGIN - "#include ""afxres.h""\r\n" + "#include ""WinResrc.h""\r\n" "\0" END diff -Nru corsix-th-0.30/CorsixTH/CorsixTH.vcxproj.user.in corsix-th-0.62/CorsixTH/CorsixTH.vcxproj.user.in --- corsix-th-0.30/CorsixTH/CorsixTH.vcxproj.user.in 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/CorsixTH.vcxproj.user.in 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,8 @@ + + + + --interpreter=@CMAKE_CURRENT_SOURCE_DIR@/CorsixTH.lua + WindowsLocalDebugger + + + diff -Nru corsix-th-0.30/CorsixTH/Graphics/file_mapping.txt corsix-th-0.62/CorsixTH/Graphics/file_mapping.txt --- corsix-th-0.30/CorsixTH/Graphics/file_mapping.txt 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Graphics/file_mapping.txt 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,26 @@ +--[[ Copyright (c) 2013 Edvin "Lego3" Linge + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + + +-- This table specifies the custom animation files to load. +file_mapping = { + "plant_anim.dat" +} + diff -Nru corsix-th-0.30/CorsixTH/Levels/avatar.level corsix-th-0.62/CorsixTH/Levels/avatar.level --- corsix-th-0.30/CorsixTH/Levels/avatar.level 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Levels/avatar.level 2018-07-21 11:13:17.000000000 +0000 @@ -18,25 +18,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Only lines beginning with % or # as explained below will be considered by the game. - -Each line beginning with a %-sign are directives to use when loading the game, such as what -the level is called and where to find the map file. Available commands: -- Name: What the level should be called (within quotes) -- LevelFile: The name of the binary map file to load. First the Levels directory of the - original game will be searched, and then the Levels directory of CorsixTH. - -Lines that begin with # defines all parameters for the level. By default there are no diseases -and only some basic rooms are available. Note that if a player is using the demo files -on the contrary everything is available unless specified otherwise in the level file. - - ---------------------- General Information ------------------------- %Name = "Avatar" -%LevelFile = "avatar.map" +%MapFile = "avatar.map" + +%LevelBriefing = "In this town, there are no doctors available for hire, so you have decided to take the matter into your own hands. +Luckily, you happen to be a fully skilled consultant. Try to earn 50.000 - and don't worry too much about killing off your patients, you're only in for the money." -Note that the below introduction text at the moment must reside on a single line within this file! -%LevelBriefing = "In this town, there are no doctors available for hire, so you have decided to take the matter into your own hands. Luckily, you happen to be a fully skilled consultant. Try to earn 50.000 - and don't worry too much about killing off your patients, you're only in for the money." +%LevelDebriefing = "Good work! Having only one doctor is not easy, but you managed to get a really good hospital up and running anyway." Town properties InterestRate is defined as centiprocent to allow for two decimals precision, i.e. @@ -46,7 +35,7 @@ -------------------- Disease Configuration ------------------------- When a drug is researched, what effectiveness does it have -#gbv.StartRating 100 +#gbv.StartRating 100 The following table contains all diagnoses and treatments that shows up inte drug casebook in the game. Known specifies whether it should show up from the beginning of the level and @@ -187,7 +176,7 @@ --------------------- Research Configuration ----------------------- Divides research input to get the amount of research points. must be > 0 -#gbv.ResearchPointsDivisor 1 +#gbv.ResearchPointsDivisor 1 ---------------------- Awards and Trophies ------------------------- diff -Nru corsix-th-0.30/CorsixTH/Levels/confined_v5.level corsix-th-0.62/CorsixTH/Levels/confined_v5.level --- corsix-th-0.30/CorsixTH/Levels/confined_v5.level 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Levels/confined_v5.level 2018-07-21 11:13:17.000000000 +0000 @@ -18,24 +18,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Only lines beginning with % or # as explained below will be considered by the game. - -Each line beginning with a %-sign are directives to use when loading the game, such as what -the level is called and where to find the map file. Available commands: -- Name: What the level should be called (within quotes) -- LevelFile: The name of the binary map file to load. First the Levels directory of the - original game will be searched, and then the Levels directory of CorsixTH. - -Lines that begin with # defines all parameters for the level. By default there are no diseases -and only some basic rooms are available. - - ---------------------- General Information ------------------------- %Name = "Confined" -%LevelFile = "confined_v5.map" +%MapFile = "confined_v5.map" + +%LevelBriefing = "You have been tasked to build a hospital in an area where only a few apartments are for sale. +Land prices around here are astronomical, so you will have to live with a very confined space until you have earned enough money to expand." -Note that the below introduction text at the moment must reside on a single line within this file! -%LevelBriefing = "You have been tasked to build a hospital in an area where only a few apartments are for sale. Land prices around here are astronomical, so you will have to live with a very confined space until you have earned enough money to expand." +%LevelDebriefing = "Great job! You never really noticed the space issue, right?" Town properties InterestRate is defined as centiprocent to allow for two decimals precision, i.e. @@ -45,7 +35,7 @@ -------------------- Disease Configuration ------------------------- When a drug is researched, what effectiveness does it have -#gbv.StartRating 100 +#gbv.StartRating 100 The following table contains all diagnoses and treatments that shows up in the drug casebook in the game. Known specifies whether it should show up from the beginning of the level and @@ -187,7 +177,7 @@ --------------------- Research Configuration ----------------------- Divides research input to get the amount of research points. must be > 0 -#gbv.ResearchPointsDivisor 5 +#gbv.ResearchPointsDivisor 5 ---------------------- Awards and Trophies ------------------------- diff -Nru corsix-th-0.30/CorsixTH/Levels/demo.level corsix-th-0.62/CorsixTH/Levels/demo.level --- corsix-th-0.30/CorsixTH/Levels/demo.level 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Levels/demo.level 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2010 Edvin "Lego3" Linge +Copyright (c) 2010-2014 Edvin "Lego3" Linge Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -20,14 +20,19 @@ ---------------------- General Information ------------------------- %Name = "Demo Town" -%LevelFile = "LEVEL.L1" +%MapFile = "LEVEL.L1" + +%LevelBriefing = "This is the only map available as long as you use + the Theme Hospital Demo files." + +%LevelDebriefing = "That was not too hard right? Time to get the real deal?" #town.StartCash 60000 -------------------- Disease Configuration ------------------------- When a drug is researched, what effectiveness does it have -#gbv.StartRating 100 +#gbv.StartRating 100 #expertise[2].Known.RschReqd 1 40000 BLOATY_HEAD #expertise[4].Known.RschReqd 1 60000 ELVIS diff -Nru corsix-th-0.30/CorsixTH/Levels/example.level corsix-th-0.62/CorsixTH/Levels/example.level --- corsix-th-0.30/CorsixTH/Levels/example.level 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Levels/example.level 2018-07-21 11:13:17.000000000 +0000 @@ -20,22 +20,32 @@ Only lines beginning with % or # as explained below will be considered by the game. -Each line beginning with a %-sign are directives to use when loading the game, such as what -the level is called and where to find the map file. Available commands: +Each line beginning with a %-sign is a directive to use when loading the game, +such as the name of the level and where to find the map file. Available commands: - Name: What the level should be called (within quotes) -- LevelFile: The name of the binary map file to load. First the Levels directory of the +- MapFile: The name of the binary map file to load. First the Levels directory of the original game will be searched, and then the Levels directory of CorsixTH. - -Lines that begin with # defines all parameters for the level. By default there are no diseases -and only some basic rooms are available. +- LevelBriefing: The body of text shown before you start a custom scenario, + and as first information when you have just started a new level. + Everything between the citation marks will get included. If you use new lines: + One new line is simply discarded, while two new lines in a row creates + a new paragraph. So does the special expression // (legacy from Theme Hospital) +- LevelDebriefing: Text shown in the fax when you win a level. + +Lines that begin with # defines all parameters for the level. +By default there are no diseases and only some basic rooms are available. ---------------------- General Information ------------------------- %Name = "Example Town" -%LevelFile = "Example.map" +%MapFile = "Example.map" + +Everything within citation marks will be the briefing/debriefing. +Two new lines creates a new paragraph, but additional new lines in a row are discarded. +%LevelBriefing = "This is an example map that shows aspiring map makers + what can be done when making new fantastic creations!" -Note that the below introduction text at the moment must reside on a single line within this file! -%LevelBriefing = "This is an example map that shows aspiring map makers what can be done when making new fantastic creations!" +%LevelDebriefing = "Congratulations! You played through the example map. Time to do your own?" Town properties InterestRate is defined as centiprocent to allow for two decimals precision, i.e. @@ -186,7 +196,7 @@ --------------------- Research Configuration ----------------------- Divides research input to get the amount of research points. must be > 0 -#gbv.ResearchPointsDivisor 5 +#gbv.ResearchPointsDivisor 5 ---------------------- Awards and Trophies ------------------------- diff -Nru corsix-th-0.30/CorsixTH/Levels/finisham.level corsix-th-0.62/CorsixTH/Levels/finisham.level --- corsix-th-0.30/CorsixTH/Levels/finisham.level 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Levels/finisham.level 2018-07-21 11:13:17.000000000 +0000 @@ -18,25 +18,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Only lines beginning with % or # as explained below will be considered by the game. +---------------------- General Information ------------------------- +%Name = "Finisham" +%MapFile = "finisham.map" -Each line beginning with a %-sign are directives to use when loading the game, such as what -the level is called and where to find the map file. Available commands: -- Name: What the level should be called (within quotes) -- LevelFile: The name of the binary map file to load. First the Levels directory of the - original game will be searched, and then the Levels directory of CorsixTH. - -Lines that begin with # defines all parameters for the level. By default there are no diseases -and only some basic rooms are available. Note that if a player is using the demo files -on the contrary everything is available unless specified otherwise in the level file. +%LevelBriefing = "The Ministry of Health wants you to run his newest hospital in the holiday resort of Finisham. +This hospital is located in a popular tourist spot and they are opening a Theme Park nearby next year, so expect seasonal peaks in visitors. You are expected to run a superb hospital with the highest of standards; he expects nothing less than perfection. ----------------------- General Information ------------------------- -%Name = "Finisham" -%LevelFile = "finisham.map" +You should aim to keep queues to a minimum and keep your staff happy at the same time. + +Get a reputation of at least 700, treat 85% of your visitors, cure 900 patients, amass $500,000 in the bank and have a hospital worth $400,000 to keep the Minister happy and make him a big wad of cash at the same time." -Note that the below introduction text at the moment must reside on a single line within this file! -%LevelBriefing = "The Ministry of Health wants you to run his newest hospital in the holiday resort of Finisham. This hospital is located in a popular tourist spot and they are opening a Theme Park nearby next year, so expect seasonal peaks in visitors. You are expected to run a superb hospital with the highest of standards; he expects nothing less than perfection. You should aim to keep queues to a minimum and keep your staff happy at the same time. Get a reputation of at least 700, treat 85% of your visitors, cure 900 patients, amass $500,000 in the bank and have a hospital worth $400,000 to keep the Minister happy and make him a big wad of cash at the same time." +%LevelDebriefing = "Extremely good work! Where to next?" Town properties InterestRate is defined as centiprocent to allow for two decimals precision, i.e. @@ -46,7 +40,7 @@ -------------------- Disease Configuration ------------------------- When a drug is researched, what effectiveness does it have -#gbv.StartRating 80 +#gbv.StartRating 80 The following table contains all diagnoses and treatments that shows up inthe drug casebook in the game. Known specifies whether it should show up from the beginning of the level and @@ -108,7 +102,7 @@ #objects[30].StartAvail.StartStrength.AvailableForLevel 1 12 1 Operating Table #objects[37].StartAvail.StartStrength.AvailableForLevel 1 0 1 Projector #objects[40].StartAvail.StartStrength.AvailableForLevel 0 1 1 Research Computer -#objects[41].StartAvail.StartStrength.AvailableForLevel 0 1 1 Chemical Mixer +#objects[41].StartAvail.StartStrength.AvailableForLevel 0 1 1 Chemical Mixer #objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 1 Blood Machine #objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 1 Electrolysis Machine #objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 1 Jellyitus Moulding Machine @@ -255,7 +249,7 @@ --------------------- Research Configuration ----------------------- Divides research input to get the amount of research points. must be > 0 -#gbv.ResearchPointsDivisor 5 +#gbv.ResearchPointsDivisor 5 ---------------------- Awards and Trophies ------------------------- diff -Nru corsix-th-0.30/CorsixTH/Levels/st.peter's.level corsix-th-0.62/CorsixTH/Levels/st.peter's.level --- corsix-th-0.30/CorsixTH/Levels/st.peter's.level 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Levels/st.peter's.level 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,378 @@ +Copyright (c) 2014 Mark "MarkL" Lawlor + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +This level file and map have been put together with epidemics in mind. Wherever there are values +that have not been used previously there are some notes to assist map makers. + +---------------------- General Information ------------------------- +%Name = "St. Peter's near Cawley" +%MapFile = "st.peter's.map" + +%LevelBriefing = "The St Peter's hospital is near the small town of Cawley in the beautiful English countryside. Use all your knowledge to set up a well-run hospital which makes a healthy profit and can deal with anything the sickly public can throw up in it. + +You'll need to be aware that the atmosphere around here is particularly good at carrying germs and infections. The nearby swamp will add to your troubles, so you should expect frequent epidemics. You are expected to run a superb hospital with the highest of standards; the Minister of Health expects nothing less than perfection here. + +You should aim to keep queues to a minimum as this will help you combat epidemics and keep your staff happy at the same time. + +Get a reputation of at least 600, treat 80% of your visitors, cure 400 patients, amass $600,000 in the bank and have a hospital worth $275,000." + +%LevelDebriefing = "Congratulations, you made it! Now you can sit back and enjoy life." + +Town properties +InterestRate is defined as centiprocent to allow for two decimals precision, i.e. +300 means 3 % +#town.StartCash.InterestRate 30000 200 + If contagious how much - rand up to this figure. higher = more contagious. must be > 0 +#gbv.HowContagious 25 + 0-100 Higher equals more chance of spreading. +#gbv.ContagiousSpreadFactor 35 + Reduces cont illnesses until X months have passed +#gbv.ReduceContMonths 4 + Reduces cont illnesses until X peep have arrived +#gbv.ReduceContPeepCount 20 + If epidemic coverup fails - how much per person you are fined +#gbv.EpidemicFine 2500 + If an epidemic coverup succeeds how much compensation is received - lowest value +#gbv.EpidemicCompLo 5000 + If an epidemic coverup succeeds how much compensation is received - highest value +#gbv.EpidemicCompHi 30000 +Cost per vaccination +#gbv.VacCost 50 +How many patients still infected cause a reputation loss as well as a fine. if less than EpidemicEvacMinimum then this will be ignored +#gbv.EpidemicRepLossMinimum 5 +How many patients still infected and not-cured cause the hospital to be evacuated +#gbv.EpidemicEvacMinimum 10 + + +-------------------- Disease Configuration ------------------------- + +When a drug is first researched, what effectiveness does it have +#gbv.StartRating 80 + +The following table contains all diagnoses and treatments that shows up inthe drug casebook +in the game. ContRate is whether this is contagious (lower the number the greater the chances of it appearing, 0 means never) and +Known specifies whether it should show up from the beginning of the level and +RschReqd how much research is required to discover the treatment room for the disease. +NOTE: Most visual diseases cannot currently be part of an epidemic. Which can be included can be checked in the disease files + +#expertise[1].ContRate.Known.RschReqd 0 1 0 GENERAL_PRACTICE +#expertise[2].ContRate.Known.RschReqd 0 1 40000 BLOATY_HEAD +#expertise[3].ContRate.Known.RschReqd 0 0 40000 HAIRYITUS +#expertise[4].ContRate.Known.RschReqd 0 0 60000 ELVIS +#expertise[5].ContRate.Known.RschReqd 0 0 60000 INVIS +#expertise[6].ContRate.Known.RschReqd 10 0 60000 RADIATION +#expertise[7].ContRate.Known.RschReqd 0 0 40000 SLACK_TONGUE +#expertise[8].ContRate.Known.RschReqd 0 0 60000 ALIEN +#expertise[9].ContRate.Known.RschReqd 0 0 20000 BROKEN_BONES +#expertise[10].ContRate.Known.RschReqd 0 0 40000 BALDNESS +#expertise[11].ContRate.Known.RschReqd 10 0 40000 DISCRETE_ITCHING +#expertise[12].ContRate.Known.RschReqd 10 0 40000 JELLYITUS +#expertise[13].ContRate.Known.RschReqd 20 0 40000 SLEEPING_ILLNESS +#expertise[14].ContRate.Known.RschReqd 0 0 30000 PREGNANT +#expertise[15].ContRate.Known.RschReqd 10 0 40000 TRANSPARENCY +#expertise[16].ContRate.Known.RschReqd 10 0 20000 UNCOMMON_COLD +#expertise[17].ContRate.Known.RschReqd 10 0 60000 BROKEN_WIND +#expertise[18].ContRate.Known.RschReqd 20 0 20000 SPARE_RIBS +#expertise[19].ContRate.Known.RschReqd 30 0 20000 KIDNEY_BEANS +#expertise[20].ContRate.Known.RschReqd 10 0 20000 BROKEN_HEART +#expertise[21].ContRate.Known.RschReqd 10 0 20000 RUPTURED_NODULES +#expertise[22].ContRate.Known.RschReqd 10 0 40000 MULTIPLE_TV_PERSONALITIES +#expertise[23].ContRate.Known.RschReqd 10 1 60000 INFECTIOUS_LAUGHTER +#expertise[24].ContRate.Known.RschReqd 20 0 40000 CORRUGATED_ANKLES +#expertise[25].ContRate.Known.RschReqd 10 0 40000 CHRONIC_NOSEHAIR +#expertise[26].ContRate.Known.RschReqd 50 0 40000 3RD_DEGREE_SIDEBURNS +#expertise[27].ContRate.Known.RschReqd 20 0 40000 FAKE_BLOOD +#expertise[28].ContRate.Known.RschReqd 10 0 40000 GASTRIC_EJECTIONS +#expertise[29].ContRate.Known.RschReqd 20 1 20000 THE_SQUITS +#expertise[30].ContRate.Known.RschReqd 30 0 20000 IRON_LUNGS +#expertise[31].ContRate.Known.RschReqd 10 0 40000 SWEATY_PALMS +#expertise[32].ContRate.Known.RschReqd 15 0 20000 HEAPED_PILES +#expertise[33].ContRate.Known.RschReqd 10 0 20000 GUT_ROT +#expertise[34].ContRate.Known.RschReqd 20 0 20000 GOLF_STONES +#expertise[35].ContRate.Known.RschReqd 20 0 20000 UNEXPECTED_SWELLING +#expertise[36].Known.RschReqd 0 60000 I_D_SCANNER DIAGNOSIS +#expertise[37].Known.RschReqd 0 50000 I_D_BLOOD_MACHINE DIAGNOSIS +#expertise[38].Known.RschReqd 0 20000 I_D_CARDIO DIAGNOSIS +#expertise[39].Known.RschReqd 0 50000 I_D_XRAY DIAGNOSIS +#expertise[40].Known.RschReqd 0 60000 I_D_ULTRASCAN DIAGNOSIS +#expertise[41].Known.RschReqd 1 20000 I_D_STANDARD DIAGNOSIS +#expertise[42].Known.RschReqd 1 20000 I_D_WARD DIAGNOSIS +#expertise[43].Known.RschReqd 1 20000 I_D_SHRINK DIAGNOSIS + +| Objects available | Available from the start | Strength | Available for this level | Comment +#objects[9].StartAvail.StartStrength.AvailableForLevel 1 8 1 Inflator Machine +#objects[13].StartAvail.StartStrength.AvailableForLevel 1 13 1 Cardiogram +#objects[14].StartAvail.StartStrength.AvailableForLevel 0 12 1 Scanner +#objects[22].StartAvail.StartStrength.AvailableForLevel 0 9 1 Ultrascan +#objects[23].StartAvail.StartStrength.AvailableForLevel 0 7 1 DNA Restorer +#objects[24].StartAvail.StartStrength.AvailableForLevel 0 11 1 Cast Remover +#objects[25].StartAvail.StartStrength.AvailableForLevel 0 8 1 Hair restorer +#objects[26].StartAvail.StartStrength.AvailableForLevel 0 10 1 Slicer for slack tongues +#objects[27].StartAvail.StartStrength.AvailableForLevel 0 12 1 X-Ray +#objects[30].StartAvail.StartStrength.AvailableForLevel 0 12 1 Operating Table +#objects[37].StartAvail.StartStrength.AvailableForLevel 1 0 1 Projector +#objects[40].StartAvail.StartStrength.AvailableForLevel 0 1 1 Research Computer +#objects[41].StartAvail.StartStrength.AvailableForLevel 0 1 1 Chemical Mixer +#objects[42].StartAvail.StartStrength.AvailableForLevel 0 10 1 Blood Machine +#objects[46].StartAvail.StartStrength.AvailableForLevel 0 8 1 Electrolysis Machine +#objects[47].StartAvail.StartStrength.AvailableForLevel 0 7 1 Jellyitus Moulding Machine +#objects[54].StartAvail.StartStrength.AvailableForLevel 0 10 1 Decontamination Shower +#objects[55].StartAvail.StartStrength.AvailableForLevel 1 10 1 Autopsy Research Machine +#objects[57].StartAvail.StartStrength.AvailableForLevel 1 57 1 VideoGame + +Value represents the proportions of the disease - not implemented + +#visuals[0] 1 I_BLOATY_HEAD +#visuals[1] 21 I_HAIRYITUS +#visuals[2] 7 I_ELVIS +#visuals[3] 9 I_INVIS +#visuals[4] 23 I_RADIATION +#visuals[5] 11 I_SLACK_TONGUE +#visuals[6] 41 I_ALIEN +#visuals[7] 11 I_BROKEN_BONES +#visuals[8] 12 I_BALDNESS +#visuals[9] 5 I_DISCRETE_ITCHING +#visuals[10] 12 I_JELLYITUS +#visuals[11] 1 I_SLEEPING_ILLNESS +#visuals[12] 18 I_PREGNANT +#visuals[13] 16 I_TRANSPARENCY + +#non_visuals[0] 4 I_UNCOMMON_COLD +#non_visuals[1] 8 I_BROKEN_WIND +#non_visuals[2] 9 I_SPARE_RIBS +#non_visuals[3] 3 I_KIDNEY_BEANS +#non_visuals[4] 2 I_BROKEN_HEART +#non_visuals[5] 1 I_RUPTURED_NODULES +#non_visuals[6] 9 I_MULTIPLE_TV_PERSONALITIES +#non_visuals[7] 4 I_INFECTIOUS_LAUGHTER +#non_visuals[8] 2 I_CORRUGATED_ANKLES +#non_visuals[9] 5 I_CHRONIC_NOSEHAIR +#non_visuals[10] 1 I_3RD_DEGREE_SIDEBURNS +#non_visuals[11] 3 I_FAKE_BLOOD +#non_visuals[12] 3 I_GASTRIC_EJECTIONS +#non_visuals[13] 6 I_THE_SQUITS +#non_visuals[14] 1 I_IRON_LUNGS +#non_visuals[15] 9 I_SWEATY_PALMS +#non_visuals[16] 5 I_HEAPED_PILES +#non_visuals[17] 8 I_GUT_ROT +#non_visuals[18] 7 I_GOLF_STONES +#non_visuals[19] 5 I_UNEXPECTED_SWELLING + +You can use either or neither of these two to hold back the appearance of visual diseases + +Hold all visual illnesses until x months. 0 never hold +#gbv.HoldVisualMonths 9 + +Hold all visual illnesses until x peeps have arrived. 0 never hold +#gbv.HoldVisualPeepCount 60 + +Value represents the month this disease becomes available (when they will first appear in-game) +hold all visuals (above) take precedence + +#visuals_available[0] 0 I_BLOATY_HEAD +#visuals_available[1] 31 I_HAIRYITUS +#visuals_available[2] 7 I_ELVIS +#visuals_available[3] 9 I_INVIS +#visuals_available[4] 43 I_RADIATION +#visuals_available[5] 11 I_SLACK_TONGUE +#visuals_available[6] 60 I_ALIEN +#visuals_available[7] 11 I_BROKEN_BONES +#visuals_available[8] 22 I_BALDNESS +#visuals_available[9] 5 I_DISCRETE_ITCHING +#visuals_available[10] 32 I_JELLYITUS +#visuals_available[11] 19 I_SLEEPING_ILLNESS +#visuals_available[12] 28 I_PREGNANT +#visuals_available[13] 16 I_TRANSPARENCY + +---------------------- Staff Configuration ------------------------- + +Each entry states how many staff members of each category are available +a given month. The number of entries is not fixed. +| A list | Month it gets active (start at 0) | Each group | +#staff_levels[0].Month.Nurses.Doctors.Handymen.Receptionists 0 8 8 3 2 +#staff_levels[1].Month.Nurses.Doctors.Handymen.Receptionists 3 7 5 5 3 +#staff_levels[2].Month.Nurses.Doctors.Handymen.Receptionists 5 5 8 7 4 + +The minimum salary for each staff type +#staff[0].MinSalary 60 Nurse +#staff[1].MinSalary 75 Doctor +#staff[2].MinSalary 25 Handyman +#staff[3].MinSalary 20 Receptionist + +Salary modifiers for different doctor attributes +#gbv.SalaryAdd[3] -30 Junior +#gbv.SalaryAdd[4] 30 Doctor +#gbv.SalaryAdd[5] 40 Surgeon +#gbv.SalaryAdd[6] 30 Psychiatrist +#gbv.SalaryAdd[7] 100 Consultant +#gbv.SalaryAdd[8] 20 Researcher + +How much the skill of the doctor adds to the salary. skill * 1000 / divisor +#gbv.SalaryAbilityDivisor 10 +#gbv.LandCostPerTile 50 + +#gbv.TrainingRate 40 +#gbv.AbilityThreshold[0] 75 Surgeon +#gbv.AbilityThreshold[1] 60 Psychiatrist +#gbv.AbilityThreshold[2] 45 Researcher +#gbv.TrainingValue[0] 10 Projector +#gbv.TrainingValue[1] 15 Skeleton +#gbv.TrainingValue[2] 20 Bookcase + +#popn[0].Month.Change 0 2 +#popn[1].Month.Change 6 0 +#popn[2].Month.Change 12 2 +#popn[4].Month.Change 15 0 +#popn[5].Month.Change 23 1 +#popn[6].Month.Change 28 0 + +Set severity to 0 if you don't want any earthquakes +#quake_control[0].StartMonth.EndMonth.Severity 5 10 0 + + +#emergency_control[0].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 4 8 4 6 23 75 1500 +#emergency_control[1].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 12 16 8 10 2 75 1000 +#emergency_control[2].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 20 24 5 9 27 75 1000 +#emergency_control[3].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 28 32 10 14 33 75 500 +#emergency_control[4].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 36 40 4 5 8 75 2500 +#emergency_control[5].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 44 48 2 2 30 75 1800 +#emergency_control[6].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 52 56 7 12 12 75 1200 +#emergency_control[7].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 60 64 5 9 8 75 2000 +#emergency_control[8].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 68 72 4 5 21 75 1600 +#emergency_control[9].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 76 80 9 13 26 75 550 +#emergency_control[10].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 84 88 6 8 3 75 1300 +#emergency_control[11].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 92 96 7 11 8 75 2000 +#emergency_control[12].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 100 104 4 6 20 75 2000 +#emergency_control[13].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 108 112 10 14 28 75 700 +#emergency_control[14].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 116 120 6 11 6 75 2000 +#emergency_control[15].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 124 128 9 13 8 75 2000 +#emergency_control[16].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 132 136 14 18 31 75 800 +#emergency_control[17].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 140 144 4 7 34 75 1600 +#emergency_control[18].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 148 152 8 14 17 75 1400 +#emergency_control[19].StartMonth.EndMonth.Min.Max.Illness.PercWin.Bonus 156 160 18 20 4 75 5000 + +--------------------- Research Configuration ----------------------- + +Divides research input to get the amount of research points. must be > 0 +#gbv.ResearchPointsDivisor 2 + +---------------------- Awards and Trophies ------------------------- + +Trophy win conditions +#awards_trophies.RatKillsAbsolute 25 +#awards_trophies.CansofCoke 100 +#awards_trophies.Reputation 400 +#awards_trophies.Plant 80 +#awards_trophies.TrophyStaffHappiness 85 +#awards_trophies.RatKillsPercentage 11 +#awards_trophies.TrophyMayor 25 + +Trophy win bonuses +#awards_trophies.RatKillsAbsoluteBonus 4 +#awards_trophies.CansofCokeBonus 1000 +#awards_trophies.TrophyReputationBonus 1500 +#awards_trophies.PlantBonus 4 +#awards_trophies.TrophyStaffHappinessBonus 5 +#awards_trophies.RatKillsPercentageBonus 4000 +#awards_trophies.TrophyDeathBonus 6000 +#awards_trophies.TrophyCuresBonus 4000 +#awards_trophies.TrophyMayorBonus 4 + +Award win criteria +#awards_trophies.CuresAward 50 +#awards_trophies.CuresPoor 10 +#awards_trophies.DeathsAward 10 +#awards_trophies.DeathsPoor 25 +#awards_trophies.PopulationPercentageAward 50 +#awards_trophies.PopulationPercentagePoor 15 +#awards_trophies.CuresVDeathsAward 5 +#awards_trophies.CuresVDeathsPoor 1 +#awards_trophies.ReputationAward 500 +#awards_trophies.ReputationPoor 200 +#awards_trophies.HospValueAward 150000 +#awards_trophies.HospValuePoor 50000 +#awards_trophies.CleanlinessAward 5 +#awards_trophies.CleanlinessPoor 40 +#awards_trophies.EmergencyAwardv 90 +#awards_trophies.EmergencyPoor 50 +#awards_trophies.StaffHappinessAward 75 +#awards_trophies.StaffHappinessPoor 25 +#awards_trophies.PeepHappinessAward 75 +#awards_trophies.PeepHappinessPoor 25 +#awards_trophies.WaitingTimesAward 25 +#awards_trophies.WaitingTimesPoor 75 +#awards_trophies.WellKeptTechAward 20 +#awards_trophies.WellKeptTechPoor 70 + +Award win bonuses or penalties + +#awards_trophies.CuresBonus 1500 +#awards_trophies.CuresPenalty -4000 +#awards_trophies.DeathsBonus 2500 +#awards_trophies.DeathsPenalty -6000 +#awards_trophies.PopulationPercentageBonus 4 +#awards_trophies.PopulationPercentagePenalty -6 +#awards_trophies.CuresVDeathsBonus 3000 +#awards_trophies.CuresVDeathsPenalty -5000 +#awards_trophies.AwardReputationBonus 2000 +#awards_trophies.AwardReputationPenalty -5000 +#awards_trophies.HospValueBonus 3 +#awards_trophies.HospValuePenalty -6 +#awards_trophies.CleanlinessBonus 5 +#awards_trophies.CleanlinessPenalty -12 +#awards_trophies.EmergencyBonus 6 +#awards_trophies.EmergencyPenalty -11 +#awards_trophies.AwardStaffHappinessBonus 3 +#awards_trophies.AwardStaffHappinessPenalty -10 +#awards_trophies.PeepHappinessBonus 3 +#awards_trophies.PeepHappinessPenalty -9 +#awards_trophies.WaitingTimesBonus 2 +#awards_trophies.WaitingTimesPenalty -6 +#awards_trophies.WellKeptTechBonus 7 +#awards_trophies.WellKeptTechPenalty -5 +#awards_trophies.NewTechAward 1500 +#awards_trophies.NewTechPoor 0 +#awards_trophies.ResearchBonus 3 +#awards_trophies.ResearchPenalty -7 + +------------------ Winning and Losing Conditions ------------------- +But we don't want any such conditions on the example level! +1 Total reputation +2 Balance total +3 Percentage people your hospital has handled +4 Percentage people have been cured +5 Percentage people have been killed +6 Hospital value + +#win_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 1 600 1 0 +#win_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 1 600000 1 0 +#win_criteria[2].Criteria.MaxMin.Value.Group.Bound 3 1 80 1 0 +#win_criteria[3].Criteria.MaxMin.Value.Group.Bound 4 1 400 1 0 +#win_criteria[4].Criteria.MaxMin.Value.Group.Bound 6 1 275000 1 0 +#lose_criteria[0].Criteria.MaxMin.Value.Group.Bound 1 0 400 1 450 +#lose_criteria[1].Criteria.MaxMin.Value.Group.Bound 2 0 -20000 2 -10000 +#lose_criteria[2].Criteria.MaxMin.Value.Group.Bound 5 1 10 3 5 + +--------------------- Competitor Information ----------------------- + +| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment | +#computer[12].Playing 1 Corsix +#computer[13].Playing 1 Roujin +#computer[14].Playing 1 Edvin Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/Levels/st.peter's.map and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/Levels/st.peter's.map differ diff -Nru corsix-th-0.30/CorsixTH/Lua/api_version.lua corsix-th-0.62/CorsixTH/Lua/api_version.lua --- corsix-th-0.30/CorsixTH/Lua/api_version.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/api_version.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ -#ifdef _ /* Copyright (c) 2009 Peter "Corsix" Cawley +#ifdef _ /* Copyright (c) 2009-2017 Peter "Corsix" Cawley et al. --[[ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -32,4 +32,4 @@ #endif /*]]--*/ -return 2037; +return 2678; diff -Nru corsix-th-0.30/CorsixTH/Lua/app.lua corsix-th-0.62/CorsixTH/Lua/app.lua --- corsix-th-0.30/CorsixTH/Lua/app.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/app.lua 2018-07-21 11:13:17.000000000 +0000 @@ -19,25 +19,28 @@ SOFTWARE. --]] local pathsep = package.config:sub(1, 1) -local rnc = require "rnc" -local lfs = require "lfs" -local TH = require "TH" -local SDL = require "sdl" -local assert, io, type, dofile, loadfile, pcall, tonumber, print, setmetatable - = assert, io, type, dofile, loadfile, pcall, tonumber, print, setmetatable +local rnc = require("rnc") +local lfs = require("lfs") +local TH = require("TH") +local SDL = require("sdl") +local runDebugger = corsixth.require("run_debugger") -- Increment each time a savegame break would occur -- and add compatibility code in afterLoad functions -local SAVEGAME_VERSION = 82 +local SAVEGAME_VERSION = 127 class "App" +---@type App +local App = _G["App"] + function App:App() self.command_line = {} self.config = {} self.runtime_config = {} self.running = false + self.key_modifiers = {} self.gfx = {} self.last_dispatch_type = "" self.eventHandlers = { @@ -45,22 +48,34 @@ timer = self.onTick, keydown = self.onKeyDown, keyup = self.onKeyUp, + textediting = self.onEditingText, + textinput = self.onTextInput, buttonup = self.onMouseUp, buttondown = self.onMouseDown, + mousewheel = self.onMouseWheel, motion = self.onMouseMove, active = self.onWindowActive, + window_resize = self.onWindowResize, music_over = self.onMusicOver, - movie_over = self.onMovieOver + movie_over = self.onMovieOver, + sound_over = self.onSoundOver, + multigesture = self.onMultiGesture } self.strings = {} self.savegame_version = SAVEGAME_VERSION self.check_for_updates = true end +--! Starts a Lua DBGp client & connects it to a DBGp server. +--!return error_message (String) Returns an error message or nil. +function App:connectDebugger() + return runDebugger() +end + function App:setCommandLine(...) self.command_line = {...} - for i, arg in ipairs(self.command_line) do - local setting, value = arg:match"^%-%-([^=]*)=(.*)$" --setting=value + for _, arg in ipairs(self.command_line) do + local setting, value = arg:match("^%-%-([^=]*)=(.*)$") --setting=value if value then self.command_line[setting] = value end @@ -87,21 +102,21 @@ local conf_path = self.command_line["config-file"] or "config.txt" local conf_chunk, conf_err = loadfile_envcall(conf_path) if not conf_chunk then - error("Unable to load the config file. Please ensure that CorsixTH ".. - "has permission to read/write ".. conf_path ..", or use the ".. - "--config-file=filename command line option to specify a writable file. ".. - "For reference, the error loading the config file was: " .. conf_err) + error("Unable to load the config file. Please ensure that CorsixTH " .. + "has permission to read/write " .. conf_path .. ", or use the " .. + "--config-file=filename command line option to specify a writable file. " .. + "For reference, the error loading the config file was: " .. conf_err) else conf_chunk(self.config) end self:fixConfig() - dofile "filesystem" + corsixth.require("filesystem") local good_install_folder, error_message = self:checkInstallFolder() self.good_install_folder = good_install_folder -- self:checkLanguageFile() - + self.level_dir = debug.getinfo(1, "S").source:sub(2, -12) .. "Levels" .. pathsep + self:initUserLevelDir() self:initSavegameDir() - self:initScreenshotsDir() -- Create the window @@ -109,37 +124,24 @@ return false, "Cannot initialise SDL" end local compile_opts = TH.GetCompileOptions() - local api_version = dofile "api_version" + local api_version = corsixth.require("api_version") if api_version ~= compile_opts.api_version then api_version = api_version or 0 compile_opts.api_version = compile_opts.api_version or 0 if api_version < compile_opts.api_version then - print "Notice: Compiled binary is more recent than Lua scripts." + print("Notice: Compiled binary is more recent than Lua scripts.") elseif api_version > compile_opts.api_version then - print("Warning: Compiled binary is out of date. CorsixTH will likely".. + print("Warning: Compiled binary is out of date. CorsixTH will likely" .. " fail to run until you recompile the binary.") end end - local caption_descs = {compile_opts.renderer} - if compile_opts.jit then - caption_descs[#caption_descs + 1] = compile_opts.jit - end - if compile_opts.arch_64 then - caption_descs[#caption_descs + 1] = "64 bit" - end - self.caption = "CorsixTH (" .. table.concat(caption_descs, ", ") .. ")" - SDL.wm.setCaption(self.caption) - local modes = {"hardware", "doublebuf"} + + local modes = {} if compile_opts.renderer == "OpenGL" then modes[#modes + 1] = "opengl" end self.fullscreen = false - if _MAP_EDITOR then - MapEditorInitWithLuaApp(self) - modes[#modes + 1] = "reuse context" - self.config.width = 640 - self.config.height = 480 - elseif self.config.fullscreen then + if self.config.fullscreen then self.fullscreen = true modes[#modes + 1] = "fullscreen" end @@ -151,17 +153,30 @@ self.video:setBlueFilterActive(false) SDL.wm.setIconWin32() + self:setCaptureMouse() + + local caption_descs = {self.video:getRendererDetails()} + if compile_opts.jit then + caption_descs[#caption_descs + 1] = compile_opts.jit + else + caption_descs[#caption_descs + 1] = _VERSION + end + if compile_opts.arch_64 then + caption_descs[#caption_descs + 1] = "64 bit" + end + self.caption = "CorsixTH (" .. table.concat(caption_descs, ", ") .. ")" + self.video:setCaption(self.caption) -- Prereq 2: Load and initialise the graphics subsystem - dofile "persistance" - dofile "graphics" + corsixth.require("persistance") + corsixth.require("graphics") self.gfx = Graphics(self) -- Put up the loading screen if good_install_folder then self.video:startFrame() self.gfx:loadRaw("Load01V", 640, 480):draw(self.video, - (self.config.width - 640) / 2, (self.config.height - 480) / 2) + math.floor((self.config.width - 640) / 2), math.floor((self.config.height - 480) / 2)) self.video:endFrame() -- Add some notices to the loading screen local notices = {} @@ -174,9 +189,9 @@ if notices ~= "" then self.video:startFrame() self.gfx:loadRaw("Load01V", 640, 480):draw(self.video, - (self.config.width - 640) / 2, (self.config.height - 480) / 2) + math.floor((self.config.width - 640) / 2), math.floor((self.config.height - 480) / 2)) font:drawWrapped(self.video, notices, 32, - (self.config.height + 400) / 2, self.config.width - 64, "center") + math.floor((self.config.height + 400) / 2), math.floor(self.config.width - 64), "center") self.video:endFrame() end end @@ -197,43 +212,43 @@ return math.floor(input + 0.5) end -- Load audio - dofile "audio" + corsixth.require("audio") self.audio = Audio(self) self.audio:init() -- Load movie player - dofile "movie_player" - self.moviePlayer = MoviePlayer(self, self.audio) + corsixth.require("movie_player") + self.moviePlayer = MoviePlayer(self, self.audio, self.video) if good_install_folder then self.moviePlayer:init() end -- Load strings before UI and before additional Lua - dofile "strings" - dofile "string_extensions" + corsixth.require("strings") + corsixth.require("string_extensions") self.strings = Strings(self) self.strings:init() local language_load_success = self:initLanguage() - if (self.command_line.dump or ""):match"strings" then + if (self.command_line.dump or ""):match("strings") then -- Specify --dump=strings on the command line to dump strings -- (or insert "true or" after the "if" in the above) self:dumpStrings() end -- Load map before world - dofile "map" + corsixth.require("map") -- Load additional Lua before world if good_install_folder then self.anims = self.gfx:loadAnimations("Data", "V") self.animation_manager = AnimationManager(self.anims) - self.walls = self:loadLuaFolder"walls" - dofile "entity" - dofile "entities/humanoid" - dofile "entities/object" - dofile "entities/machine" + self.walls = self:loadLuaFolder("walls") + corsixth.require("entity") + corsixth.require("entities.humanoid") + corsixth.require("entities.object") + corsixth.require("entities.machine") - local objects = self:loadLuaFolder"objects" + local objects = self:loadLuaFolder("objects") self.objects = self:loadLuaFolder("objects/machines", nil, objects) -- Doors are in their own folder to ensure that the swing doors (which -- depend on the door) are loaded after the door object. @@ -245,70 +260,92 @@ end Object.processTypeDefinition(v) end - dofile "room" - self.rooms = self:loadLuaFolder"rooms" - self.humanoid_actions = self:loadLuaFolder"humanoid_actions" - local diseases = self:loadLuaFolder"diseases" + + corsixth.require("room") + self.rooms = self:loadLuaFolder("rooms") + + corsixth.require("humanoid_action") + self.humanoid_actions = self:loadLuaFolder("humanoid_actions") + + local diseases = self:loadLuaFolder("diseases") self.diseases = self:loadLuaFolder("diagnosis", nil, diseases) + -- Load world before UI - dofile "world" + corsixth.require("world") end -- Load UI - dofile "ui" + corsixth.require("ui") if good_install_folder then - dofile "game_ui" + corsixth.require("game_ui") self.ui = UI(self, true) else self.ui = UI(self, true) self.ui:setMenuBackground() local function callback(path) - local app = TheApp - app.config.theme_hospital_install = path - app:saveConfig() + TheApp.config.theme_hospital_install = path + TheApp:saveConfig() debug.getregistry()._RESTART = true - app.running = false + TheApp.running = false end self.ui:addWindow(UIDirectoryBrowser(self.ui, nil, _S.install.th_directory, "InstallDirTreeNode", callback)) return true end -- Load main menu (which creates UI) - if _MAP_EDITOR then - self:loadLevel("") - else - local function callback_after_movie() - self:loadMainMenu() - -- If we couldn't properly load the language, show an information dialog - if not language_load_success then - -- At this point we know the language is english, so no use having - -- localized strings. - self.ui:addWindow(UIInformation(self.ui, {"The game language has been reverted".. - " to English because the desired language could not be loaded. ".. - "Please make sure you have specified a font file in the config file."})) - end + local function callback_after_movie() + self:loadMainMenu() + -- If we couldn't properly load the language, show an information dialog + if not language_load_success then + -- At this point we know the language is english, so no use having + -- localized strings. + self.ui:addWindow(UIInformation(self.ui, {"The game language has been reverted" .. + " to English because the desired language could not be loaded. " .. + "Please make sure you have specified a font file in the config file."})) + end - -- If a savegame was specified, load it - if self.command_line.load then - local status, err = pcall(self.load, self, self.command_line.load) - if not status then - err = _S.errors.load_prefix .. err - print(err) - self.ui:addWindow(UIInformation(self.ui, {err})) - end - end - -- There might also be a message from the earlier initialization process that should be shown. - -- Show it using the built-in font in case the game's font is messed up. - if error_message then - self.ui:addWindow(UIInformation(self.ui, error_message, true)) + -- If a savegame was specified, load it + if self.command_line.load then + local status, err = pcall(self.load, self, self.savegame_dir .. self.command_line.load) + if not status then + err = _S.errors.load_prefix .. err + print(err) + self.ui:addWindow(UIInformation(self.ui, {err})) end end - if self.config.play_intro then - self.moviePlayer:playIntro(callback_after_movie) - else - callback_after_movie() + -- There might also be a message from the earlier initialization process that should be shown. + -- Show it using the built-in font in case the game's font is messed up. + if error_message then + self.ui:addWindow(UIInformation(self.ui, error_message, true)) end end + if self.config.play_intro then + self.moviePlayer:playIntro(callback_after_movie) + else + callback_after_movie() + end + return true +end + +--! Tries to initialize the user and built in level directories, returns true on +--! success and false on failure. +function App:initUserLevelDir() + local conf_path = self.command_line["config-file"] or "config.txt" + self.user_level_dir = self.config.levels or + conf_path:match("^(.-)[^" .. pathsep .. "]*$") .. "Levels" + + if self.user_level_dir:sub(-1, -1) == pathsep then + self.user_level_dir = self.user_level_dir:sub(1, -2) + end + if lfs.attributes(self.user_level_dir, "mode") ~= "directory" then + if not lfs.mkdir(self.user_level_dir) then + print("Notice: Level directory does not exist and could not be created.") + return false + end + end + if self.user_level_dir:sub(-1, -1) ~= pathsep then + self.user_level_dir = self.user_level_dir .. pathsep + end return true end @@ -316,13 +353,15 @@ --! false on failure. function App:initSavegameDir() local conf_path = self.command_line["config-file"] or "config.txt" - self.savegame_dir = self.config.savegames or conf_path:match("^(.-)[^".. pathsep .. "]*$") .. "Saves" + self.savegame_dir = self.config.savegames or + conf_path:match("^(.-)[^" .. pathsep .. "]*$") .. "Saves" + if self.savegame_dir:sub(-1, -1) == pathsep then self.savegame_dir = self.savegame_dir:sub(1, -2) end if lfs.attributes(self.savegame_dir, "mode") ~= "directory" then if not lfs.mkdir(self.savegame_dir) then - print "Notice: Savegame directory does not exist and could not be created." + print("Notice: Savegame directory does not exist and could not be created.") return false end end @@ -334,13 +373,15 @@ function App:initScreenshotsDir() local conf_path = self.command_line["config-file"] or "config.txt" - self.screenshot_dir = self.config.screenshots or conf_path:match("^(.-)[^".. pathsep .. "]*$") .. "Screenshots" + self.screenshot_dir = self.config.screenshots or + conf_path:match("^(.-)[^" .. pathsep .. "]*$") .. "Screenshots" + if self.screenshot_dir:sub(-1, -1) == pathsep then self.screenshot_dir = self.screenshot_dir:sub(1, -2) end if lfs.attributes(self.screenshot_dir, "mode") ~= "directory" then if not lfs.mkdir(self.screenshot_dir) then - print "Notice: Screenshot directory does not exist and could not be created." + print("Notice: Screenshot directory does not exist and could not be created.") return false end end @@ -374,7 +415,8 @@ _S = strings -- For immediate compatibility: getmetatable(_S).__call = function(_, sec, str, ...) - assert(_S.deprecated[sec] and _S.deprecated[sec][str], "_S(".. sec ..", ".. str ..") does not exist!") + assert(_S.deprecated[sec] and _S.deprecated[sec][str], + "_S(" .. sec .. ", " .. str .. ") does not exist!") str = _S.deprecated[sec][str] if ... then @@ -399,7 +441,15 @@ return success end +function App:worldExited() + self.audio:clearCallbacks() +end + function App:loadMainMenu(message) + if self.world then + self:worldExited() + end + -- Make sure there is no blue filter active. self.video:setBlueFilterActive(false) @@ -422,21 +472,135 @@ end end +--! Sets the mouse capture to the state set within +--! app.config.capture_mouse +function App:setCaptureMouse() + self.video:setCaptureMouse(self.config.capture_mouse) +end + +--! Loads the first level of the specified campaign and prepares the world +--! to be able to progress through that campaign. +--!param campaign_file (string) Name of a CorsixTH Campaign definition Lua file. +function App:loadCampaign(campaign_file) + local campaign_info, level_info, errors, _ + + campaign_info, errors = self:readCampaignFile(campaign_file) + if not campaign_info then + self.ui:addWindow(UIInformation(self.ui, {_S.errors.could_not_load_campaign:format(errors)})) + return + end + + level_info, errors = self:readLevelFile(campaign_info.levels[1]) + if not level_info then + self.ui:addWindow(UIInformation(self.ui, {_S.errors.could_not_find_first_campaign_level:format(errors)})) + return + end + + _, errors = self:readMapDataFile(level_info.map_file) + if errors then + self.ui:addWindow(UIInformation(self.ui, {errors})) + return + end + + self:loadLevel(campaign_info.levels[1], nil, level_info.name, + level_info.map_file, level_info.briefing) + -- The new world needs to know which campaign to continue on. + self.world.campaign_info = campaign_info +end + +--! Reads the given file name as a Lua chunk from the Campaigns folder in the CorsixTH install directory. +--! A correct campaign definition contains "name", "description", "levels", and "winning_text". +--!param campaign_file (string) Name of the file to read. +--!return (table) Definitions found in the campaign file. +function App:readCampaignFile(campaign_file) + local local_path = debug.getinfo(1, "S").source:sub(2, -12) + local dir = "Campaigns" .. pathsep + local path = local_path .. dir + local chunk, err = loadfile_envcall(path .. campaign_file) + if not chunk then + return nil, "Error loading " .. path .. campaign_file .. ":\n" .. tostring(err) + else + local result = {} + chunk(result) + return result + end +end + +--! Opens the given file name and returns all Level definitions in a table. +--! Values in the returned table: "path", "level_file", "name", "map_file", "briefing", and "end_praise". +--!param level (string) Name of the file to read. +--!return (table) Level info found in the file. +function App:readLevelFile(level) + local filename = self:getAbsolutePathToLevelFile(level) + local file, err = io.open(filename and filename or "") + if not file then + return nil, "Could not open the specified level file (" .. level .. "): " .. err + end + local contents = file:read("*all") + file:close() + + local level_info = {} + level_info.path = filename + level_info.level_file = level + level_info.name = contents:match("%Name ?= ?\"(.-)\"") or "Unknown name" + level_info.map_file = contents:match("%MapFile ?= ?\"(.-)\"") + if not level_info.map_file then + -- The old way of defining the Map File has been deprecated, but a warning is enough. + level_info.map_file = contents:match("%LevelFile ?= ?\"(.-)\"") + if level_info.map_file then + print("\nWarning: The level '" .. level_info.name .. "' contains a deprecated variable definition in the level file." .. + "'%LevelFile' has been renamed to '%MapFile'. Please advise the map creator to update the level.\n") + end + level_info.deprecated_variable_used = true + end + level_info.briefing = contents:match("%LevelBriefing ?= ?\"(.-)\"") + level_info.end_praise = contents:match("%LevelDebriefing ?= ?\"(.-)\"") + return level_info +end + +--! Searches for the given level file in the "Campaigns" and "Levels" folder of the +--! CorsixTH install directory. +--!param level (string) Filename to search for. +--!return (string, error) Returns the found absolute path, or nil if not found. Then +--! a second variable is returned with an error message. +function App:getAbsolutePathToLevelFile(level) + local path = debug.getinfo(1, "S").source:sub(2, -12) + -- First look in Campaigns. If not found there, fall back to Levels. + local list_of_possible_paths = {self.user_level_dir, path .. "Campaigns", self.level_dir} + for _, parent_path in ipairs(list_of_possible_paths) do + local check_path = parent_path .. pathsep .. level + local file, _ = io.open(check_path, "rb") + if file then + file:close() + return check_path + end + end + return nil, "Level not found: " .. level +end + -- Loads the specified level. If a string is passed it looks for the file with the same name -- in the "Levels" folder of CorsixTH, if it is a number it tries to load that level from -- the original game. -function App:loadLevel(level, ...) +function App:loadLevel(level, difficulty, level_name, level_file, level_intro, map_editor) + if self.world then + self:worldExited() + end + -- Check that we can load the data before unloading current map local new_map = Map(self) - local map_objects, errors = new_map:load(level, ...) + local map_objects, errors = new_map:load(level, difficulty, level_name, level_file, level_intro, map_editor) if not map_objects then - error(errors) + self.world.ui:addWindow(UIInformation(self.ui, {errors})) + return end -- If going from another level, save progress. local carry_to_next_level - if self.world and tonumber(self.world.map.level_number) then + if self.world and self.world.campaign_info then carry_to_next_level = { - world = {room_built = self.world.room_built}, + world = { + room_built = self.world.room_built, + campaign_info = self.world.campaign_info, + }, hospital = { player_salary = self.ui.hospital.player_salary, message_popup = self.ui.hospital.message_popup, @@ -463,8 +627,11 @@ self.world = World(self) self.world:createMapObjects(map_objects) + -- Enable / disable SoundEffects + self.audio:playSoundEffects(self.config.play_sounds) + -- Load UI - self.ui = GameUI(self, self.world:getLocalPlayerHospital()) + self.ui = GameUI(self, self.world:getLocalPlayerHospital(), map_editor) self.world:setUI(self.ui) -- Function call allows world to set up its keyHandlers if tonumber(level) then @@ -493,12 +660,12 @@ end local dir = self.command_line["config-file"] or "" dir = string.sub(dir, 0, -11) - local fi = assert(io.open(dir .. "debug-strings-orig.txt", "wt")) + local fi = assert(io.open(dir .. "debug-strings-orig.txt", "w")) for i, sec in ipairs(_S.deprecated) do for j, str in ipairs(sec) do fi:write("[" .. i .. "," .. j .. "] " .. ("%q\n"):format(val(str))) end - fi:write"\n" + fi:write("\n") end fi:close() @@ -541,11 +708,11 @@ end end - fi = assert(io.open(dir .. "debug-strings-new-lines.txt", "wt")) + fi = assert(io.open(dir .. "debug-strings-new-lines.txt", "w")) dump_by_line(fi, _S, "") fi:close() - fi = assert(io.open(dir .. "debug-strings-new-grouped.txt", "wt")) + fi = assert(io.open(dir .. "debug-strings-new-grouped.txt", "w")) dump_grouped(fi, _S, "") fi:close() @@ -616,7 +783,7 @@ end end - local fi = assert(io.open(dir .. "debug-strings-diff-" .. language_english:lower() .. ".txt", "wt")) + local fi = assert(io.open(dir .. "debug-strings-diff-" .. language_english:lower() .. ".txt", "w")) fi:write("------------------------------------\n") fi:write("MISSING STRINGS IN LANGUAGE \"" .. language:upper() .. "\":\n") fi:write("------------------------------------\n") @@ -630,8 +797,8 @@ end function App:fixConfig() - -- Fill in default values for things which dont exist - local _, config_defaults = dofile "config_finder" + -- Fill in default values for things which don't exist + local _, config_defaults = corsixth.require("config_finder") for k, v in pairs(config_defaults) do if self.config[k] == nil then self.config[k] = v @@ -642,8 +809,8 @@ -- Trim whitespace from beginning and end string values - it shouldn't be -- there (at least in any current configuration options). if type(value) == "string" then - if value:match"^[%s]" or value:match"[%s]$" then - self.config[key] = value:match"^[%s]*(.-)[%s]*$" + if value:match("^[%s]") or value:match("[%s]$") then + self.config[key] = value:match("^[%s]*(.-)[%s]*$") end end @@ -660,6 +827,15 @@ if key == "height" and type(value) == "number" and value < 480 then self.config[key] = 480 end + + if (key == "scroll_speed" or key == "shift_scroll_speed") and + type(value) == "number" then + if value > 10 then + self.config[key] = 10 + elseif value < 1 then + self.config[key] = 1 + end + end end end @@ -675,27 +851,26 @@ -- Look for identifiers we want to save local _, _, identifier, value = string.find(line, "^%s*([_%a][_%w]*)%s*=%s*(.-)%s*$") if identifier then + local _, temp -- Trim possible trailing comment from value - local _, _, temp = string.find(value, "^(.-)%s*%-%-.*") + _, _, temp = string.find(value, "^(.-)%s*%-%-.*") value = temp or value -- Remove enclosing [[]], if necessary - local _, _, temp = string.find(value, "^%[%[(.*)%]%]$") + _, _, temp = string.find(value, "^%[%[(.*)%]%]$") value = temp or value -- If identifier also exists in runtime options, compare their values and -- replace the line, if needed - --if self.config[identifier] ~= nil then - handled_ids[identifier] = true - if value ~= tostring(self.config[identifier]) then - local new_value = self.config[identifier] - if type(new_value) == "string" then - new_value = string.format("[[%s]]", new_value) - else - new_value = tostring(new_value) - end - lines[#lines] = string.format("%s = %s", identifier, new_value) + handled_ids[identifier] = true + if value ~= tostring(self.config[identifier]) then + local new_value = self.config[identifier] + if type(new_value) == "string" then + new_value = string.format("[[%s]]", new_value) + else + new_value = tostring(new_value) end - --end + lines[#lines] = string.format("%s = %s", identifier, new_value) + end end end end @@ -732,12 +907,12 @@ -- 2) If an error occurs, the call stack is preserved in the coroutine, so -- Lua can query or print the call stack as required, rather than -- hardcoding error behaviour in C. - local co = coroutine.create(function(self) + local co = coroutine.create(function(app) local yield = coroutine.yield - local dispatch = self.dispatch + local dispatch = app.dispatch local repaint = true - while self.running do - repaint = dispatch(self, yield(repaint)) + while app.running do + repaint = dispatch(app, yield(repaint)) end end) @@ -771,13 +946,13 @@ -- returned from mainloop(), meaning that where == "callback". self.last_dispatch_type = where end - print("An error has occured!") - print("Almost anything can be the cause, but the detailed information ".. - "below can help the developers find the source of the error.") + print("An error has occurred!") + print("Almost anything can be the cause, but the detailed information " .. + "below can help the developers find the source of the error.") print("Running: The " .. self.last_dispatch_type .. " handler.") - print "A stack trace is included below, and the handler has been disconnected." + print("A stack trace is included below, and the handler has been disconnected.") print(debug.traceback(co, e, 0)) - print "" + print("") if self.world then self.world:gameLog("Error in " .. self.last_dispatch_type .. " handler: ") self.world:gameLog(debug.traceback(co, e, 0)) @@ -796,13 +971,13 @@ self.ui:addWindow(UIStaff(self.ui, entity)) end self.ui:addWindow(UIConfirmDialog(self.ui, - "Sorry, but an error has occured. There can be many reasons - see the log ".. - "window for details. Would you like to attempt a recovery?", - --[[persistable:app_attempt_recovery]] function() - self.world:gameLog("Recovering from error in timer handler...") - entity.ticks = false - self.eventHandlers.timer = handler - end + "Sorry, but an error has occurred. There can be many reasons - see the " .. + "log window for details. Would you like to attempt a recovery?", + --[[persistable:app_attempt_recovery]] function() + self.world:gameLog("Recovering from error in timer handler...") + entity.ticks = false + self.eventHandlers.timer = handler + end )) end self.eventHandlers[self.last_dispatch_type] = nil @@ -849,13 +1024,15 @@ local fps_next = 1 -- Used to loop through fps_history when [over]writing function App:drawFrame() + self.video:startFrame() if(self.moviePlayer.playing) then + self.key_modifiers = {} self.moviePlayer:refresh() else - self.video:startFrame() + self.key_modifiers = SDL.getKeyModifiers() self.ui:draw(self.video) - self.video:endFrame() end + self.video:endFrame() if self.config.track_fps then fps_sum = fps_sum - fps_history[fps_next] @@ -879,6 +1056,14 @@ return self.ui:onKeyUp(...) end +function App:onEditingText(...) + return self.ui:onEditingText(...) +end + +function App:onTextInput(...) + return self.ui:onTextInput(...) +end + function App:onMouseUp(...) return self.ui:onMouseUp(...) end @@ -891,10 +1076,20 @@ return self.ui:onMouseMove(...) end +function App:onMouseWheel(...) + return self.ui:onMouseWheel(...) +end + function App:onWindowActive(...) return self.ui:onWindowActive(...) end +--! Window has been resized by the user +--! Call the UI to handle the new window size +function App:onWindowResize(...) + return self.ui:onWindowResize(...) +end + function App:onMusicOver(...) return self.audio:onMusicOver(...) end @@ -903,15 +1098,23 @@ self.moviePlayer:onMovieOver(...) end +function App:onSoundOver(...) + return self.audio:onSoundPlayed(...) +end + +function App:onMultiGesture(...) + return self.ui:onMultiGesture(...) +end + function App:checkInstallFolder() self.fs = FileSystem() - local status, err + local status, _ if self.config.theme_hospital_install then - status, err = self.fs:setRoot(self.config.theme_hospital_install) + status, _ = self.fs:setRoot(self.config.theme_hospital_install) end - local message = "Please make sure that you point the game to".. - " a valid copy of the data files from the original game,".. - " as said files are required for graphics and sounds." + local message = "Please make sure that you point the game to" .. + " a valid copy of the data files from the original game," .. + " as said files are required for graphics and sounds." if not status then -- If the given directory didn't exist, then likely the config file hasn't -- been changed at all from the default, so we continue to initialise the @@ -926,14 +1129,14 @@ missing[#missing + 1] = path end end - check("Data".. pathsep .."VBlk-0.tab") - check("Levels".. pathsep .."Level.L1") - check("QData".. pathsep .."SPointer.dat") + check("Data" .. pathsep .. "VBlk-0.tab") + check("Levels" .. pathsep .. "Level.L1") + check("QData" .. pathsep .. "SPointer.dat") if #missing ~= 0 then missing = table.concat(missing, ", ") - message = "Invalid Theme Hospital folder specified in config file, ".. - "as at least the following files are missing: ".. missing ..".\n".. - message + message = "Invalid Theme Hospital folder specified in config file, " .. + "as at least the following files are missing: " .. missing .. ".\n" .. + message print(message) print("Trying to let the user select a new one.") return false, {message} @@ -942,81 +1145,47 @@ -- Check for demo version if self.fs:readContents("DataM", "Demo.dat") then self.using_demo_files = true - print "Notice: Using data files from demo version of Theme Hospital." - print "Consider purchasing a full copy of the game to support EA." + print("Notice: Using data files from demo version of Theme Hospital.") + print("Consider purchasing a full copy of the game to support EA.") end -- Do a few more checks to make sure that commonly corrupted files are OK. local corrupt = {} - if not self.using_demo_files then - local function check_corrupt(path, correct_size) - local real_path = self.fs:getFilePath(path) - -- If the file exists but is smaller than usual it is probably corrupt - if real_path then - local real_size = lfs.attributes(real_path, "size") - if real_size + 1024 < correct_size or real_size - 1024 > correct_size then - corrupt[#corrupt + 1] = path .. " (Size: " .. math.floor(real_size/1024) .. " kB / Correct: about " .. math.floor(correct_size/1024) .. " kB)" - end - else - corrupt[#corrupt + 1] = path .. " (This file is missing)" + local function check_corrupt(path, correct_size) + local real_path = self.fs:getFilePath(path) + -- If the file exists but is smaller than usual it is probably corrupt + if real_path then + local real_size = lfs.attributes(real_path, "size") + if real_size + 1024 < correct_size or real_size - 1024 > correct_size then + corrupt[#corrupt + 1] = path .. " (Size: " .. math.floor(real_size/1024) .. " kB / Correct: about " .. math.floor(correct_size/1024) .. " kB)" end + else + corrupt[#corrupt + 1] = path .. " (This file is missing)" end + end + if self.using_demo_files then + check_corrupt("ANIMS" .. pathsep .. "WINLEVEL.SMK", 243188) + check_corrupt("LEVELS" .. pathsep .. "LEVEL.L1", 163948) + check_corrupt("DATA" .. pathsep .. "BUTTON01.DAT", 252811) + else check_corrupt("ANIMS" .. pathsep .. "AREA01V.SMK", 251572) check_corrupt("ANIMS" .. pathsep .. "WINGAME.SMK", 2066656) check_corrupt("ANIMS" .. pathsep .. "WINLEVEL.SMK", 335220) check_corrupt("INTRO" .. pathsep .. "INTRO.SM4", 33616520) check_corrupt("QDATA" .. pathsep .. "FONT00V.DAT", 1024) check_corrupt("ANIMS" .. pathsep .. "LOSE1.SMK", 1009728) + end - if #corrupt ~= 0 then - table.insert(corrupt, 1, "There appears to be corrupt files in your Theme Hospital folder, " .. - "so don't be suprised if CorsixTH crashes. At least the following files are wrong:") - table.insert(corrupt, message) - end + if #corrupt ~= 0 then + table.insert(corrupt, 1, "There appears to be corrupt files in your Theme Hospital folder, " .. + "so don't be surprised if CorsixTH crashes. At least the following files are wrong:") + table.insert(corrupt, message) end return true, #corrupt ~= 0 and corrupt or nil end --- TODO: is it okay to remove this without replacement? ---[[ -function App:checkLanguageFile() - -- Some TH installs are trimmed down to a single language file, rather than - -- providing every language file. If the user has selected a language which - -- isn't present, then we should detect this and inform the user of their - -- options. - - local filename = self:getDataFilename("Lang-" .. self.config.language .. ".dat") - local file, err = io.open(filename, "rb") - if file then - -- Everything is fine - file:close() - return - end - - print "Theme Hospital install seems to be missing the language file for the language which you requested." - print "The following language files are present:" - local none = true - local is_win32 = not not package.cpath:lower():find(".dll", 1, true) - for item in lfs.dir(self.config.theme_hospital_install .. self.data_dir_map.DATA) do - local n = item:upper():match"^LANG%-([0-9]+)%.DAT$" - if n then - local name = languages_by_num[tonumber(n)] or "??" - local warning = "" - if not is_win32 and item ~= item:upper() then - warning = " (Needs to be renamed to " .. item:upper() .. ")" - end - print(" " .. item .. " (" .. name .. ")" .. warning) - none = false - end - end - if none then - print " (none)" - end - error(err) -end]] - --! Get the directory containing the bitmap files. --!return Name of the directory containing the bitmap files, ending with a -- directory path separator. @@ -1030,7 +1199,7 @@ function App:readBitmapDataFile(filename) filename = self:getBitmapDir() .. filename local file = assert(io.open(filename, "rb")) - local data = file:read"*a" + local data = file:read("*a") file:close() if data:sub(1, 3) == "RNC" then data = assert(rnc.decompress(data)) @@ -1047,7 +1216,7 @@ if dir == "Bitmap" then return self:readBitmapDataFile(filename) elseif dir == "Levels" then - return self:readLevelDataFile(filename) + return self:readMapDataFile(filename) end if filename == nil then dir, filename = "Data", dir @@ -1063,16 +1232,18 @@ --!param filename (string) Name of the level file. --!return If the file could be found, the data of the file, else a -- tuple 'nil', and an error description -function App:readLevelDataFile(filename) - local dir = "Levels" .. pathsep .. filename +function App:readMapDataFile(filename) -- First look in the original install directory, if not found there - -- look in the CorsixTH directory "Levels". - local data = self.fs:readContents(dir) + -- look in the CorsixTH directories "Levels" and "Campaigns". + local data = self.fs:readContents("Levels" .. pathsep .. filename) if not data then - local file = io.open(debug.getinfo(1, "S").source:sub(2, -12) .. dir, "rb") - if file then - data = file:read"*a" - file:close() + local absolute_path = self:getAbsolutePathToLevelFile(filename) + if absolute_path then + local file = io.open(absolute_path, "rb") + if file then + data = file:read("*a") + file:close() + end end end if data then @@ -1092,8 +1263,8 @@ local path = ourpath .. dir local results = no_results and "" or (append_to or {}) for file in lfs.dir(path) do - if file:match"%.lua$" then - local status, result = pcall(dofile, dir .. file:sub(1, -5)) + if file:match("%.lua$") then + local status, result = pcall(corsixth.require, dir .. file:sub(1, -5)) if not status then print("Error loading " .. dir .. file .. ":\n" .. tostring(result)) else @@ -1108,7 +1279,7 @@ if type(result) == "table" and result.id then results[result.id] = result elseif type(result) == "function" then - results[file:match"(.*)%."] = result + results[file:match("(.*)%.")] = result end results[#results + 1] = result end @@ -1130,8 +1301,18 @@ -- a specific savegame verion is from. function App:getVersion(version) local ver = version or self.savegame_version - if ver > 78 then + if ver > 127 then return "Trunk" + elseif ver > 122 then + return "v0.62" + elseif ver > 111 then + return "v0.61" + elseif ver > 105 then + return "v0.60" + elseif ver > 91 then + return "0.50" + elseif ver > 78 then + return "0.40" elseif ver > 72 then return "0.30" elseif ver > 66 then @@ -1150,16 +1331,20 @@ end function App:save(filename) - return SaveGameFile(self.savegame_dir .. filename) + return SaveGameFile(filename) end + -- Omit the usual file extension so this file cannot be seen from the normal load and save screen and cannot be overwritten function App:quickSave() local filename = "quicksave" return SaveGameFile(self.savegame_dir .. filename) end -function App:load(filename) - return LoadGameFile(self.savegame_dir .. filename) +function App:load(filepath) + if self.world then + self:worldExited() + end + return LoadGameFile(filepath) end function App:quickLoad() @@ -1177,12 +1362,13 @@ assert(self.map, "Trying to restart while no map is loaded.") self.ui:addWindow(UIConfirmDialog(self.ui, _S.confirmation.restart_level, --[[persistable:app_confirm_restart]] function() + self:worldExited() local level = self.map.level_number local difficulty = self.map.difficulty local name, file, intro if not tonumber(level) then name = self.map.level_name - file = self.map.level_file + file = self.map.map_file intro = self.map.level_intro end if level and name and not file then @@ -1198,6 +1384,11 @@ end)) end +--! Begin the map editor +function App:mapEdit() + self:loadLevel("", nil, nil, nil, nil, true) +end + --! Exits the game completely (no confirmation window) function App:exit() -- Save config before exiting @@ -1212,6 +1403,7 @@ --! This function is automatically called after loading a game and serves for compatibility. function App:afterLoad() + self.ui:addOrRemoveDebugModeKeyHandlers() local old = self.world.savegame_version or 0 local new = self.savegame_version @@ -1225,8 +1417,9 @@ end local first = self.world.original_savegame_version if new == old then - self.world:gameLog("Savegame version is " .. new .. " (" .. self:getVersion() - .. "), originally it was " .. first .. " (" .. self:getVersion(first) .. ")") + self.world:gameLog("Savegame version is " .. new .. " (" .. self:getVersion() .. + "), originally it was " .. first .. " (" .. self:getVersion(first) .. ")") + self.world:playLoadedEntitySounds() return elseif new > old then self.world:gameLog("Savegame version changed from " .. old .. " (" .. self:getVersion(old) .. @@ -1240,6 +1433,20 @@ end self.world.savegame_version = new + if old < 87 then + local new_object = corsixth.require("objects.gates_to_hell") + Object.processTypeDefinition(new_object) + self.objects[new_object.id] = new_object + self.world:newObjectType(new_object) + end + + if old < 114 then + local rathole_type = corsixth.require("objects.rathole") + Object.processTypeDefinition(rathole_type) + self.objects[rathole_type.id] = rathole_type + self.world:newObjectType(rathole_type) + end + self.map:afterLoad(old, new) self.world:afterLoad(old, new) self.ui:afterLoad(old, new) @@ -1260,22 +1467,24 @@ -- Only check for updates against released versions if current_version == "Trunk" then - print "Will not check for updates since this is the Trunk version." + print("Will not check for updates since this is the Trunk version.") return end - local success, socket = pcall(require, "socket") + local success, _ = pcall(require, "socket") if not success then -- LuaSocket is not available, just return - print "Cannot check for updates since LuaSocket is not available." + print("Cannot check for updates since LuaSocket is not available.") return + else + self.lua_socket_available = true end - local http = require "socket.http" - local url = require "socket.url" + local http = require("socket.http") + local url = require("socket.url") - print "Checking for CorsixTH updates..." - local update_body, status, headers = http.request(update_url) + print("Checking for CorsixTH updates...") + local update_body, status, _ = http.request(update_url) if not update_body or not (status == 200) then print("Couldn't check for updates. Server returned code: " .. status) @@ -1288,7 +1497,7 @@ local new_version = update_table["major"] .. '.' .. update_table["minor"] .. update_table["revision"] if (new_version <= current_version) then - print "You are running the latest version of CorsixTH." + print("You are running the latest version of CorsixTH.") return end @@ -1302,24 +1511,38 @@ end end if not valid_url then - print ("Update download url is not on the trusted domains list (" .. updateTable["download_url"] .. ")") + print("Update download url is not on the trusted domains list (" .. update_table["download_url"] .. ")") return end -- Check to see if there's a changelog in the user's language local current_langs = self.strings:getLanguageNames(self.config.language) - for _,v in ipairs(current_langs) do + for _, v in ipairs(current_langs) do if (update_table["changelog_" .. v]) then changelog = update_table["changelog_" .. v] break end end - print ("New version found: " .. new_version) + print("New version found: " .. new_version) -- Display the update window self.ui:addWindow(UIUpdate(self.ui, current_version, new_version, changelog, update_table["download_url"])) end +-- Free up / stop any resources relying on the current video object +function App:prepareVideoUpdate() + self.video:endFrame() + self.moviePlayer:deallocatePictureBuffer() +end + +-- Update / start any resources relying on a video object +function App:finishVideoUpdate() + self.gfx:updateTarget(self.video) + self.moviePlayer:updateRenderer() + self.moviePlayer:allocatePictureBuffer() + self.video:startFrame() +end + -- Do not remove, for savegame compatibility < r1891 local app_confirm_quit_stub = --[[persistable:app_confirm_quit]] function() end diff -Nru corsix-th-0.30/CorsixTH/Lua/audio.lua corsix-th-0.62/CorsixTH/Lua/audio.lua --- corsix-th-0.30/CorsixTH/Lua/audio.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/audio.lua 2018-07-21 11:13:17.000000000 +0000 @@ -19,21 +19,33 @@ SOFTWARE. --]] local pathsep = package.config:sub(1, 1) -local rnc = require "rnc" -local lfs = require "lfs" -local SDL = require "sdl" -local TH = require "TH" +local rnc = require("rnc") +local lfs = require("lfs") +local SDL = require("sdl") +local TH = require("TH") local ipairs = ipairs --! Layer which handles the Lua-facing side of loading and playing audio. class "Audio" +---@type Audio +local Audio = _G["Audio"] + function Audio:Audio(app) self.app = app self.has_bg_music = false self.not_loaded = not app.config.audio + self.unused_played_callback_id = 0 + self.played_sound_callbacks = {} + self.entities_waiting_for_sound_to_be_enabled = {} +end + +function Audio:clearCallbacks() + self.unused_played_callback_id = 0 + self.played_sound_callbacks = {} + self.entities_waiting_for_sound_to_be_enabled = {} end local function GetFileData(path) @@ -54,9 +66,7 @@ return end if not SDL.audio.loaded then - if not _MAP_EDITOR then - print "Notice: Audio system not loaded as CorsixTH compiled without it" - end + print("Notice: Audio system not loaded as CorsixTH compiled without it") self.not_loaded = true return end @@ -108,8 +118,8 @@ if music_dir then info.filename_mp3 = music_dir .. file else - print("Warning: CorsixTH only supports xmi if audio_mp3" - .. " is not defined in the config file.") + print("Warning: CorsixTH only supports xmi if audio_mp3" .. + " is not defined in the config file.") music_array[filename:upper()] = nil end -- Remove the xmi version of this file, if found. @@ -151,12 +161,9 @@ end end if #self.background_playlist == 0 and self.app.good_install_folder then - print "Notice: Audio system loaded, but found no background tracks" + print("Notice: Audio system loaded, but found no background tracks") self.has_bg_music = false else - table.sort(self.background_playlist, function(left, right) - return left.title:upper() < right.title:upper() - end) self.has_bg_music = true end @@ -191,7 +198,7 @@ end local archive_data, err = load_sound_file(speech_file) - -- If sound file not found and language choosen is not English, + -- If sound file not found and language chosen is not English, -- maybe we can have more chance loading English sounds if not archive_data and speech_file ~= "Sound-0.dat" and self.app.good_install_folder then if self.speech_file_name == "Sound-0.dat" then @@ -223,14 +230,14 @@ self.sound_fx = TH.soundEffects() self.sound_fx:setSoundArchive(self.sound_archive) local w, h = self.app.config.width / 2, self.app.config.height / 2 - self.sound_fx:setCamera(w, h, (w^2 + h^2)^0.5) + self.sound_fx:setCamera(math.floor(w), math.floor(h), math.floor((w^2 + h^2)^0.5)) --self:dumpSoundArchive[[E:\CPP\2K8\CorsixTH\DataRaw\Sound\]] end end end function Audio:dumpSoundArchive(out_dir) - local info,warning = io.open(out_dir .. "info.csv", "wt") + local info,warning = io.open(out_dir .. "info.csv", "w") if info == nil then print("Error: Audio dump failed because info.csv couldn't be created and/or opened in the dump directory:" .. out_dir) @@ -252,37 +259,32 @@ local wilcard_cache = permanent "audio_wildcard_cache" {} -function Audio:playSound(name, where, is_announcement) +function Audio:playSound(name, where, is_announcement, played_callback, played_callback_delay) local sound_fx = self.sound_fx if sound_fx then if name:find("*") then -- Resolve wildcard to one particular sound - local list = wilcard_cache[name] - if not list then - list = {} - wilcard_cache[name] = list - local pattern = ("^" .. name:gsub("%*",".*") .. "$"):upper() - for i = 1, #self.sound_archive - 1 do - local filename = self.sound_archive:getFilename(i):upper() - if filename:find(pattern) then - list[#list + 1] = filename - end - end - end + local list = self:cacheSoundFilenamesAssociatedWithName(name) name = list[1] and list[math.random(1, #list)] or name end local _, warning local volume = is_announcement and self.app.config.announcement_volume or self.app.config.sound_volume + local x, y + local played_callbacks_id + if played_callback then + played_callbacks_id = self.unused_played_callback_id + self.unused_played_callback_id = self.unused_played_callback_id + 1 + self.played_sound_callbacks[tostring(played_callbacks_id)] = played_callback + end if where then - local x, y = Map:WorldToScreen(where.tile_x, where.tile_y) + x, y = Map:WorldToScreen(where.tile_x, where.tile_y) local dx, dy = where.th:getPosition() local ui = self.app.ui x = x + dx - ui.screen_offset_x y = y + dy - ui.screen_offset_y - _, warning = sound_fx:play(name, volume, x, y) - else - _, warning = sound_fx:play(name, volume) end + _, warning = sound_fx:play(name, volume, x, y, played_callbacks_id, played_callback_delay) + if warning then -- Indicates something happened self.app.world:gameLog("Audio:playSound - Warning: " .. warning) @@ -290,6 +292,135 @@ end end +function Audio:cacheSoundFilenamesAssociatedWithName(name) + local list = wilcard_cache[name] + if not list then + local filename + list = {} + wilcard_cache[name] = list + local pattern = ("^" .. name:gsub("%*",".*") .. "$"):upper() + for i = 1, #self.sound_archive - 1 do + filename = self.sound_archive:getFilename(i):upper() + if filename:find(pattern) then + list[#list + 1] = filename + end + end + end + return list +end + +--[[ +This function's integer array parameters for the min and max silence lengths should provide lengths +for this game's different speeds, indexed as follows: +[1] Slowest [2] Slow [3] Normal [4] Fast [5] Maximum + +!param min_silence_lengths (integer array) The desired minimum silence lengths for this game's different speeds. +!param max_silence_lengths (integer array) The desired maximum silence lengths for this game's different speeds. +!param num_silences (integer) How many silence lengths should be in the returned table of generated lengths. +!return (table) A table of randomly ordered integers for the generated silence lengths. +--]] +local function getSilenceLengths(min_silence_lengths, max_silence_lengths, num_silences) + local min_silence = min_silence_lengths[TheApp.world.tick_rate] + local max_silence = max_silence_lengths[TheApp.world.tick_rate] + + local silences = {} + if min_silence == max_silence then + silences[1] = min_silence + else + for i = 1, num_silences do + silences[i] = math.random(min_silence, max_silence) + end + end + + return silences +end + +--[[ +Plays related sounds at an entity in a random sequence, with random length silences between the sounds. + +This function's integer array parameters for the min and max silence lengths should provide lengths +for this game's different speeds, indexed as follows: +[1] Slowest [2] Slow [3] Normal [4] Fast [5] Maximum Speed + +!param names (string) A name pattern for the sequence of related sounds to be played for example: LAVA00*.wav +!param entity : Where the sounds will be played at, the player won't hear the sounds being played at the entity +when it isn't in their view. +!param min_silence_lengths (integer array) The desired minimum silence lengths for this game's different speeds. +!param max_silence_lengths (integer array) The desired maximum silence lengths for this game's different speeds. +!param num_silences (integer) How many different silence lengths should be used, this can be a nil parameter. +--]] +function Audio:playEntitySounds(names, entity, min_silence_lengths, max_silence_lengths, num_silences) + if self.sound_fx then + self:cacheSoundFilenamesAssociatedWithName(names) + local silences = getSilenceLengths(min_silence_lengths, max_silence_lengths, num_silences) + self:entitySoundsHandler(wilcard_cache[names], entity, silences, 1) + end +end + +local function canSoundsBePlayed() + return TheApp.config.play_sounds and not TheApp.world:isPaused() +end + +--[[ +Called by the above function. + +This function's integer array parameters for the min and max silence lengths should provide lengths +for this game's different speeds, indexed as follows: +[1] Slowest [2] Slow [3] Normal [4] Fast [5] Maximum Speed + +!param sounds (string) A name pattern for the sequence of related sounds to be played for example: LAVA00*.wav +!param entity : Where the sounds will be played at, the player won't hear the sounds being played at the entity +when it isn't in their view. +!param silences (integer array) the different pause durations to be used between the played sounds. +!param silences_pointer (integer) the index for the pause duration which should be used after this call's sound has been played. +--]] +function Audio:entitySoundsHandler(sounds, entity, silences, silences_pointer) + if entity.playing_sounds_in_random_sequence then + local sound_played_callback = function() + self:entitySoundsHandler(sounds, entity, silences, silences_pointer) + end + + if canSoundsBePlayed() then + local x, y = Map:WorldToScreen(entity.tile_x, entity.tile_y) + local dx, dy = entity.th:getPosition() + x = x + dx - self.app.ui.screen_offset_x + y = y + dy - self.app.ui.screen_offset_y + + self.played_sound_callbacks[tostring(self.unused_played_callback_id)] = sound_played_callback + self.sound_fx:play(sounds[math.random(1,#sounds)], self.app.config.sound_volume, + x, y, self.unused_played_callback_id, silences_pointer) + + self.unused_played_callback_id = self.unused_played_callback_id + 1 + if #silences > 1 then + silences_pointer = (silences_pointer % #silences) + 1 + end + --If the sound can't be played now: + else + self.entities_waiting_for_sound_to_be_enabled[entity] = sound_played_callback + entity:setWaitingForSoundEffectsToBeTurnedOn(true) + end + else + if self.entities_waiting_for_sound_to_be_enabled[entity] then + self.entities_waiting_for_sound_to_be_enabled[entity] = nil + end + end +end + +function Audio:onEndPause() + if TheApp.config.play_sounds then + self:tellInterestedEntitiesTheyCanNowPlaySounds() + end +end + +function Audio:onSoundPlayed(played_callbacks_id) + if TheApp.world ~= nil then + if self.played_sound_callbacks[tostring(played_callbacks_id)] then + self.played_sound_callbacks[tostring(played_callbacks_id)]() + self.played_sound_callbacks[tostring(played_callbacks_id)] = nil + end + end +end + --! Returns whether the given sound (either a string or a number) --! exists in the sound archive --!param sound The sound to look for, either a string (name) or a @@ -443,19 +574,13 @@ -- Someone might want to stop the player from -- starting to play once it's loaded though. self.load_music = true - SDL.audio.loadMusicAsync(data, function(music, e) + SDL.audio.loadMusicAsync(data, function(music_data, e) - if music == nil then - error("Could not load music file \'" .. (info.filename_mp3 or info.filename) .. "\'" - .. (e and (" (" .. e .. ")" or ""))) + if music_data == nil then + error("Could not load music file \'" .. (info.filename_mp3 or info.filename) .. "\'" .. + (e and (" (" .. e .. ")" or ""))) else - if _DECODA then - debug.getmetatable(music).__tostring = function(ud) - return debug.getfenv(ud).tostring - end - debug.getfenv(music).tostring = "Music <".. info.filename .. ">" - end - info.music = music + info.music = music_data -- Do we still want it to play? if self.load_music then return self:playBackgroundTrack(index) @@ -473,7 +598,7 @@ end function Audio:onMusicOver() - if self.not_loaded or #self.background_playlist == 0 then + if self.not_loaded or #self.background_playlist == 0 or self.background_music == nil then return end self:playNextBackgroundTrack() @@ -503,6 +628,23 @@ -- As above. self.sound_fx:setSoundEffectsOn(play_effects) end + + if canSoundsBePlayed() then + self:tellInterestedEntitiesTheyCanNowPlaySounds() + end +end + +function Audio:tellInterestedEntitiesTheyCanNowPlaySounds() + if table_length(self.entities_waiting_for_sound_to_be_enabled) > 0 then + for entity, callback in pairs(self.entities_waiting_for_sound_to_be_enabled) do + callback() + self.entities_waiting_for_sound_to_be_enabled[entity] = nil + end + end +end + +function Audio:entityNoLongerWaitingForSoundsToBeTurnedOn(entity) + self.entities_waiting_for_sound_to_be_enabled[entity] = nil end function Audio:setAnnouncementVolume(volume) diff -Nru corsix-th-0.30/CorsixTH/Lua/base_config.lua corsix-th-0.62/CorsixTH/Lua/base_config.lua --- corsix-th-0.30/CorsixTH/Lua/base_config.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/base_config.lua 2018-07-21 11:13:17.000000000 +0000 @@ -93,6 +93,12 @@ EpidemicCompLo = 1000, -- If an epidemic coverup succeeds how much compensation is received - hi value max 20000 EpidemicCompHi = 15000, + -- How many patients still infected cause a reputation loss as well as a fine if less than EpidemicEvacMinimum then ignored + EpidemicRepLossMinimum = 5, + -- How many patients still infected and not-cured cause the hospital to be evacuated + EpidemicEvacMinimum = 10, + --How many epidemics can exists at the same time - both active and quietly in the background + EpidemicConcurrentLimit = 1, -- % of research completed for an autopsy AutopsyRschPercent = 33, -- % rep hit for discovered autopsy @@ -403,7 +409,7 @@ -- TODO: this one is hard to understand! percentage of what exactly? -- Percentage (0-100) low is good needs at 2 mayor visits to be triggered -- So for now, it is super visits that will trigger this prize - -- Please all of the VIPs that visit your hospital during the year + -- Please all of the VIPs that visit your hospital during the year -- you will have to get a super feedback for each visit -- TrophyMayor = 25, @@ -464,11 +470,11 @@ EmergencyAward = 90, -- x Percentage - to win the award MIN 0 MAX 100 - staff mean happiness thoughout the year + -- >x Percentage - to win the award MIN 0 MAX 100 - staff mean happiness throughout the year StaffHappinessAward = 75, -- x Percentage - to win the award MIN 0 MAX 100 - peeps mean happiness thoughout the year + -- >x Percentage - to win the award MIN 0 MAX 100 - peeps mean happiness throughout the year PeepHappinessAward = 75, -- = hours_per_day do + self._hour = self._hour - hours_per_day + self._day = self._day + 1 + end + self:_adjustDayOverflow() +end + +--[[ PRIVATE Adjusts the days overflows + +! Method to deal with day being more or less than valid value +]] +function Date:_adjustDayOverflow() + while self._day < 1 do + self._month = self._month - 1 + self:_adjustMonthOverflow() + self._day = self._day + self:lastDayOfMonth() + end + while self._day > self:lastDayOfMonth() do + self._day = self._day - self:lastDayOfMonth() + self._month = self._month + 1 + self:_adjustMonthOverflow() + end +end + +--[[ PRIVATE Adjusts the months overflows + +! Method to deal with month being more or less than valid value +]] +function Date:_adjustMonthOverflow() + local monthIx = self._month - 1 + self._year = self._year + math.floor(monthIx / 12) + self._month = monthIx % 12 + 1 +end + +--[[ PRIVATE Adjusts all the overflows + +! Normalize date to fix all the overflows of hours, days and months. This +method is a key to date adjustments. +]] +function Date:_adjustOverflow() + self:_adjustMonthOverflow() + self:_adjustDayOverflow() + self:_adjustHoursOverflow() +end diff -Nru corsix-th-0.30/CorsixTH/Lua/debug_script.lua corsix-th-0.62/CorsixTH/Lua/debug_script.lua --- corsix-th-0.30/CorsixTH/Lua/debug_script.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/debug_script.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,15 @@ +--- +-- Calling "execute script" while CorsixTH is running will execute the latest +-- code in this script so you don't need to restart CorsixTH. +-- +-- This script's execution key command and the key commands for the debug console +-- & connecting a Lua DBGp server can be used anywhere at any time in CorsixTH +-- when debug mode is enabled. +-- +-- Like with the console you can reference clicked humanoids with the underscore +-- global variable so for example: _:die() will make a clicked patient die. +-- +-- The run time App class instance can be referenced with its global variable +-- "TheApp", with it you can reference other run time class instances like: +-- TheApp.world +--- diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/adviser.lua corsix-th-0.62/CorsixTH/Lua/dialogs/adviser.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/adviser.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/adviser.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,11 +18,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") --! The (ideally) helpful advisor who pops up from the bottom dialog during a game. class "UIAdviser" (Window) +---@type UIAdviser +local UIAdviser = _G["UIAdviser"] + function UIAdviser:UIAdviser(ui) self:Window() @@ -185,9 +188,10 @@ return Window.onMouseDown(self, button, x, y) end -- Normal operation outside the adviser bounds - if x + self.balloon_width < 128 or x > 200 or y + self.y > 0 or y + self.y + 40 < 0 then - if x < self.x - 200 or y < self.y - 40 or x > self.x - 200 + self.width - or y > self.y + self.height - 40 then + if x + self.balloon_width < 128 or x > 200 or + y + self.y > 0 or y + self.y + 40 < 0 then + if x < self.x - 200 or y < self.y - 40 or + x > self.x - 200 + self.width or y > self.y + self.height - 40 then return Window.onMouseDown(self, button, x, y) end end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/bottom_panel.lua corsix-th-0.62/CorsixTH/Lua/dialogs/bottom_panel.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/bottom_panel.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/bottom_panel.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! The multi-purpose panel for launching dialogs / screens and dynamic information. class "UIBottomPanel" (Window) +---@type UIBottomPanel +local UIBottomPanel = _G["UIBottomPanel"] + function UIBottomPanel:UIBottomPanel(ui) self:Window() @@ -197,35 +200,65 @@ function UIBottomPanel:drawReputationMeter(canvas, x_left, y) local width = 65 -- Reputation meter width local step = width / (self.ui.hospital.reputation_max - self.ui.hospital.reputation_min) - self.panel_sprites:draw(canvas, 36, x_left + step * (self.ui.hospital.reputation - self.ui.hospital.reputation_min), y) + self.panel_sprites:draw(canvas, 36, x_left + math.floor(step * (self.ui.hospital.reputation - self.ui.hospital.reputation_min)), y) end function UIBottomPanel:drawDynamicInfo(canvas, x, y) - if self.world:isCurrentSpeed("Pause") then + if self.world:isCurrentSpeed("Pause") and not self.world.user_actions_allowed then self.pause_font:drawWrapped(canvas, _S.misc.pause, x + 10, y + 14, 255, "center") - elseif self.dynamic_info then - local info = self.dynamic_info - local font = self.white_font - for i, text in ipairs(info["text"]) do - font:drawWrapped(canvas, text, x + 20, y + 10*i, 240) - if i == #info["text"] and info["progress"] then - local white = canvas:mapRGB(255, 255, 255) - local black = canvas:mapRGB(0, 0, 0) - local orange = canvas:mapRGB(221, 83, 0) - canvas:drawRect(white, x + 165, y + 10*i, 100, 10) - canvas:drawRect(black, x + 166, y + 1 + 10*i, 98, 8) - canvas:drawRect(orange, x + 166, y + 1 + 10*i, 98*info["progress"], 8) - if info["dividers"] then - for k, value in ipairs(info["dividers"]) do - canvas:drawRect(white, x + 165 + value*100, y + 10*i, 1, 10) - end + return + end + + if not (self.dynamic_info and self.dynamic_info["text"]) then + return + end + + local info = self.dynamic_info + local font = self.white_font + for i, text in ipairs(info["text"]) do + font:drawWrapped(canvas, text, x + 20, y + 10 * i, 240) + if i == #info["text"] and info["progress"] then + local white = canvas:mapRGB(255, 255, 255) + local black = canvas:mapRGB(0, 0, 0) + local orange = canvas:mapRGB(221, 83, 0) + canvas:drawRect(white, x + 165, y + 10 * i, 100, 10) + canvas:drawRect(black, x + 166, y + 1 + 10 * i, 98, 8) + canvas:drawRect(orange, x + 166, y + 1 + 10 * i, math.floor(98 * info["progress"]), 8) + if info["dividers"] then + for _, value in ipairs(info["dividers"]) do + canvas:drawRect(white, x + 165 + math.floor(value * 100), y + 10 * i, 1, 10) end end end end end +--! Update the information shown in the information box on the panel. +--! +--! If the info is nil then a cooldown timer is used before removing the +--! information from the display. +--! +--!param info (table) A table containing the information to display. The text +--! key is required and contains an array of lines to show. An optional +--! progress key may be given to draw a progress bar, following the text and +--! and an array of dividers may be provided to draw extra vertical lines in +--! the progress bar. +--! +--! info = { +--! text: { "He's not the saviour", "He's very naughty boy" }, +--! progress: 50, +--! dividers: { 25, 50, 75 } +--! } function UIBottomPanel:setDynamicInfo(info) + if info and not info["text"] then + self.world:gameLog("") + self.world:gameLog("Dynamic info is missing text!") + self.world:gameLog("Please report this issue including the call stack below.") + self.world:gameLog(debug.traceback()) + + return + end + if not info then self.countdown = 25 else @@ -288,7 +321,7 @@ self.world.ui.adviser:say(_A.information.fax_received) self.ui.hospital.message_popup = true end - self.message_queue[#self.message_queue + 1] = { + local fax = { type = type, message = message, owner = owner, @@ -296,11 +329,69 @@ default_choice = default_choice, callback = callback, } - -- create reference to message in owner - if owner then - owner.message = message + + if self:canQueueFax(fax) then + self.message_queue[#self.message_queue + 1] = fax + -- create reference to message in owner + if owner then + owner.message = message + end + else + self:cancelFax(fax.type) end end + +--[[ A fax can be queued if the event the fax causes does not affect +an event caused by any other fax that is queued. i.e both emergency +and epidemics use the timer, so both faxes cannot appear at the same time. +@param fax (table) the fax we want to determine if can be queued. +@return true if fax can be queued, false otherwise (boolean) ]] +function UIBottomPanel:canQueueFax(fax) + --[[ Determine if fax of a particular type is queued either in the + message queue or the message window (ui) + @param fax_type (string) the fax type to check if any queued + @return true if any of fax_type is queued false otherwise (boolean) ]] + local function isFaxTypeQueued(fax_type) + -- Check the queued messages + for _, fax_msg in ipairs(self.message_queue) do + if fax_msg.type == fax_type then + return true + end + end + -- Then the messages displayed on the bottom bar + for _, fax_msg in ipairs(self.message_windows) do + if fax_msg.type == fax_type then + return true + end + end + return false + end + + if fax.type == "epidemy" then + if isFaxTypeQueued("emergency") then + return false + end + elseif fax.type == "emergency" then + if isFaxTypeQueued("epidemy") then + return false + end + end + return true +end + +--[[ Cancels a fax of a particular type currently only "emergency" and "epidemy" +Handles the cancelling of the event which the fax pertains to. +@param fax_type (string) type of fax event to be cancelled]] +function UIBottomPanel:cancelFax(fax_type) + local hospital = self.ui.hospital + if fax_type == "epidemy" then + hospital.epidemic:clearAllInfectedPatients() + hospital.epidemic = nil + elseif fax_type == "emergency" then + self.world:nextEmergency() + end +end + -- Opens the last available message. Currently used to open the level completed message. function UIBottomPanel:openLastMessage() if #self.message_queue > 0 then @@ -422,9 +513,9 @@ local fps = self.ui.app:getFPS() if fps then self.dynamic_info = {text = { - ("FPS: %i"):format(fps), - ("Lua GC: %.1f Kb"):format(collectgarbage"count"), - ("Entities: %i"):format(#self.ui.app.world.entities), + ("FPS: %i"):format(math.floor(fps + 0.5) or 0), + ("Lua GC: %.1f Kb"):format(collectgarbage("count") or 0), + ("Entities: %i"):format(#self.ui.app.world.entities or 0), }} self.countdown = 1 end @@ -660,7 +751,7 @@ self.ui:setEditRoom(false) local dialog = _G[dialog_class](self.ui) if extra_function then - _G[dialog_class][extra_function](d) + _G[dialog_class][extra_function](dialog) end self.ui:addWindow(dialog) self:updateButtonStates() diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/build_room.lua corsix-th-0.62/CorsixTH/Lua/dialogs/build_room.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/build_room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/build_room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,10 +18,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") class "UIBuildRoom" (Window) +---@type UIBuildRoom +local UIBuildRoom = _G["UIBuildRoom"] + function UIBuildRoom:UIBuildRoom(ui) self:Window() @@ -41,16 +44,16 @@ self.default_button_sound = "selectx.wav" local function cat(n) - return --[[persistable:build_room_set_category]] function(self) - return self:setCategory(n) + return --[[persistable:build_room_set_category]] function(window) + return window:setCategory(n) end end local room_n = 1 local function rm() local n = room_n room_n = room_n + 1 - return --[[persistable:build_room_build_room]] function(self) - return self:buildRoom(n) + return --[[persistable:build_room_build_room]] function(window) + return window:buildRoom(n) end end @@ -95,13 +98,13 @@ } self.category_rooms = { } - for i, category in ipairs{"diagnosis", "treatment", "clinics", "facilities"} do + for i, category in ipairs({"diagnosis", "treatment", "clinics", "facilities"}) do local rooms = {} self.category_rooms[i] = rooms for _, room in ipairs(app.world.available_rooms) do -- NB: Unimplemented rooms are hidden unless in debug mode - if (app.config.debug or room.class) and room.categories[category] - and ui.hospital.discovered_rooms[room] then + if (app.config.debug or room.class) and room.categories[category] and + ui.hospital.discovered_rooms[room] then rooms[#rooms + 1] = room end end @@ -158,8 +161,13 @@ function UIBuildRoom:buildRoom(index) local hosp = self.ui.hospital + local world = self.ui.app.world + if index == 1 then self.ui:tutorialStep(3, 3, 4) end - if hosp.balance >= hosp.research.research_progress[self.list[index]].build_cost then + + local cost = world.free_build_mode and 0 or + hosp.research.research_progress[self.list[index]].build_cost + if world.free_build_mode or hosp.balance >= cost then -- Close any full screen window currently open. local fullscreen = self.ui:getWindow(UIFullscreen) if fullscreen then @@ -167,12 +175,10 @@ end local edit_dlg = UIEditRoom(self.ui, self.list[index]) self.ui:addWindow(edit_dlg) - elseif hosp.balance < hosp.research.research_progress[self.list[index]].build_cost then + else -- give visual warning that player doesn't have enough $ to build self.ui.adviser:say(_A.warnings.money_very_low_take_loan, false, true) self.ui:playSound("Wrong2.wav") - else - self.ui:playSound("Wrong2.wav") end end @@ -191,12 +197,15 @@ end if hover_idx ~= self.list_hover_index then - self.ui:playSound "HLightP2.wav" + self.ui:playSound("HLightP2.wav") if hover_idx == 0 then self.cost_box = _S.build_room_window.cost .. "0" self.preview_anim = false else - local cost = self.ui.hospital.research.research_progress[self.list[hover_idx]].build_cost + local hosp = self.ui.hospital + local world = self.ui.app.world + local cost = world.free_build_mode and 0 or + hosp.research.research_progress[self.list[hover_idx]].build_cost self.cost_box = _S.build_room_window.cost .. cost self.preview_anim = TH.animation() self.preview_anim:setAnimation(self.ui.app.anims, self.list[hover_idx].build_preview_animation) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/confirm_dialog.lua corsix-th-0.62/CorsixTH/Lua/dialogs/confirm_dialog.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/confirm_dialog.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/confirm_dialog.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Dialog for "Are you sure you want to quit?" and similar yes/no questions. class "UIConfirmDialog" (Window) +---@type UIConfirmDialog +local UIConfirmDialog = _G["UIConfirmDialog"] + function UIConfirmDialog:UIConfirmDialog(ui, text, callback_ok, callback_cancel) self:Window() @@ -56,7 +59,8 @@ self:addPanel(362, 90, last_y + 10):makeButton(0, 10, 82, 34, 363, self.ok) :setTooltip(_S.tooltip.window_general.confirm):setSound"YesX.wav" - self:addKeyHandler("Enter", self.ok) + self:addKeyHandler("return", self.ok) + self:addKeyHandler("keypad enter", self.ok) end function UIConfirmDialog:cancel() @@ -89,3 +93,13 @@ x, y = x + self.x, y + self.y self.white_font:drawWrapped(canvas, self.text, x + 17, y + 17, 153) end + +function UIConfirmDialog:afterLoad(old, new) + if old < 101 then + self:removeKeyHandler("enter") + self:addKeyHandler("return", self.ok) + end + if old < 104 then + self:addKeyHandler("keypad enter", self.ok) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/edit_room.lua corsix-th-0.62/CorsixTH/Lua/dialogs/edit_room.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/edit_room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/edit_room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,27 +18,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" -local math_floor - = math.floor - -dofile "dialogs/place_objects" +corsixth.require("dialogs.place_objects") class "UIEditRoom" (UIPlaceObjects) +---@type UIEditRoom +local UIEditRoom = _G["UIEditRoom"] + function UIEditRoom:UIEditRoom(ui, room_type) -- NB: UIEditRoom:onCursorWorldPositionChange is called by the UIPlaceObjects -- constructor, hence the initialisation of required fields prior to the call. self.UIPlaceObjects(self, ui) - self:addKeyHandler("Enter", self.confirm) -- UIPlaceObjects does not need this + self:addKeyHandler("return", self.confirm) -- UIPlaceObjects does not need this + self:addKeyHandler("keypad enter", self.confirm) local app = ui.app + local blue_red_swap = self.anims.Alt32_BlueRedSwap -- Set alt palette on wall blueprint to make it red - self.anims:setAnimationGhostPalette(124, app.gfx:loadGhost("QData", "Ghost1.dat", 6)) + self.anims:setAnimationGhostPalette(124, app.gfx:loadGhost("QData", "Ghost1.dat", 6), blue_red_swap) -- Set on door and window blueprints too - self.anims:setAnimationGhostPalette(126, app.gfx:loadGhost("QData", "Ghost1.dat", 6)) - self.anims:setAnimationGhostPalette(130, app.gfx:loadGhost("QData", "Ghost1.dat", 6)) + self.anims:setAnimationGhostPalette(126, app.gfx:loadGhost("QData", "Ghost1.dat", 6), blue_red_swap) + self.anims:setAnimationGhostPalette(130, app.gfx:loadGhost("QData", "Ghost1.dat", 6), blue_red_swap) self.cell_outline = TheApp.gfx:loadSpriteTable("Bitmap", "aux_ui", true) if not room_type.room_info then self.blueprint_rect = { @@ -182,6 +183,7 @@ else self:close() end + self.ui:setCursor(self.ui.default_cursor) elseif self.phase == "objects" then self:stopPickupItems() self:returnToDoorPhase() @@ -209,7 +211,6 @@ self.mouse_down_y = false self.move_rect_x = false self.move_rect_y = false - self.ui:setCursor(self.ui.default_cursor) self.phase = "door" self:enterDoorPhase() elseif self.phase == "door" then @@ -241,22 +242,23 @@ self.world:markRoomAsBuilt(self.room) self.closed_cleanly = true -- If information dialogs are disabled, go ahead. - if self.world.room_information_dialogs_off then - self.ui:tutorialStep(3, 15, "next") - else + if self.ui:getWindow(UIInformation) then self.ui:tutorialStep(3, 15, 16) + else + self.ui:tutorialStep(3, 15, "next") end self:close() end end -function UIEditRoom:isHumanoidObscuringArea(entity, x1, x2, y1, y2) - if entity.tile_x then - if x1 <= entity.tile_x and entity.tile_x <= x2 - and y1 <= entity.tile_y and entity.tile_y <= y2 then - if (x1 == entity.tile_x or x2 == entity.tile_x) or (y1 == entity.tile_y or y2 == entity.tile_y) then +local function isHumanoidObscuringArea(humanoid, x1, x2, y1, y2) + if humanoid.tile_x then + if x1 <= humanoid.tile_x and humanoid.tile_x <= x2 and + y1 <= humanoid.tile_y and humanoid.tile_y <= y2 then + if (x1 == humanoid.tile_x or x2 == humanoid.tile_x) or + (y1 == humanoid.tile_y or y2 == humanoid.tile_y) then -- Humanoid not in the rectangle, but might be walking into it - local action = entity.action_queue[1] + local action = humanoid:getCurrentAction() if action.name ~= "walk" then return false end @@ -286,32 +288,33 @@ local y1 = rect.y - 1 local y2 = rect.y + rect.h for _, entity in ipairs(world.entities) do - if class.is(entity, Humanoid) - and self:isHumanoidObscuringArea(entity, x1, x2, y1, y2) then + if class.is(entity, Humanoid) and + isHumanoidObscuringArea(entity, x1, x2, y1, y2) then humanoids_to_watch[entity] = true -- Try to make the humanoid leave the area + local current_action = entity:getCurrentAction() local meander = entity.action_queue[2] if meander and meander.name == "meander" then -- Interrupt the idle or walk, which will cause a new meander target -- to be chosen, which will be outside the blueprint rectangle meander.can_idle = false - local on_interrupt = entity.action_queue[1].on_interrupt + local on_interrupt = current_action.on_interrupt if on_interrupt then - entity.action_queue[1].on_interrupt = nil - on_interrupt(entity.action_queue[1], entity) + current_action.on_interrupt = nil + on_interrupt(current_action, entity) end - elseif entity.action_queue[1].name == "seek_room" or (meander and meander.name == "seek_room") then + elseif current_action.name == "seek_room" or (meander and meander.name == "seek_room") then -- Make sure that the humanoid doesn't stand idle waiting within the blueprint - if entity.action_queue[1].name == "seek_room" then - entity:queueAction({name = "meander", count = 1, must_happen = true}, 0) + if current_action.name == "seek_room" then + entity:queueAction(MeanderAction():setCount(1):setMustHappen(true), 0) else meander.done_walk = false end else -- Look for a queue action and re-arrange the people in it, which -- should cause anyone queueing within the blueprint to move - for i, action in ipairs(entity.action_queue) do + for _, action in ipairs(entity.action_queue) do if action.name == "queue" then for _, humanoid in ipairs(action.queue) do local callbacks = action.queue.callbacks[humanoid] @@ -337,7 +340,7 @@ self.check_for_clear_area_timer = 10 self.humanoids_to_watch = humanoids_to_watch - self.ui:setDefaultCursor "sleep" + self.ui:setCursor(self.ui.waiting_cursor) end function UIEditRoom:onTick() @@ -354,11 +357,11 @@ -- The person might be dying (this check should probably be moved into -- isHumanoidObscuringArea, but I don't want to change too much right -- before a release). - if humanoid.action_queue[1].name == "die" then + if humanoid:getCurrentAction().name == "die" then if not humanoid.hospital then self.humanoids_to_watch[humanoid] = nil end - elseif not self:isHumanoidObscuringArea(humanoid, x1, x2, y1, y2) then + elseif not isHumanoidObscuringArea(humanoid, x1, x2, y1, y2) then self.humanoids_to_watch[humanoid] = nil end end @@ -394,21 +397,29 @@ if dir == "north_window_1" then if x ~= rect.x then map:setCell(x, y, layer, flag + tiles.north) - map:setCell(x + 1, y, layer, flag + tiles.north) + if map:getCell(x + 1, y, layer) ~= 0 then + map:setCell(x + 1, y, layer, flag + tiles.north) + end end elseif dir == "north_window_2" then if x == rect.x then - map:setCell(x - 1, y, layer, flag + tiles.north) + if map:getCell(x - 1, y, layer) ~= 0 then + map:setCell(x - 1, y, layer, flag + tiles.north) + end map:setCell(x, y, layer, flag + tiles.north) end elseif dir == "west_window_1" then if y == rect.y then map:setCell(x, y, layer, flag + tiles.west) - map:setCell(x, y - 1, layer, flag + tiles.west) + if map:getCell(x, y - 1, layer) ~= 0 then + map:setCell(x, y - 1, layer, flag + tiles.west) + end end elseif dir == "west_window_2" then if y ~= rect.y then - map:setCell(x, y + 1, layer, flag + tiles.west) + if map:getCell(x, y + 1, layer) ~= 0 then + map:setCell(x, y + 1, layer, flag + tiles.west) + end map:setCell(x, y, layer, flag + tiles.west) end end @@ -498,17 +509,19 @@ self.place_objects = false self:stopPickupItems() + local cfg_objects = self.world.map.level_config.objects + local research = self.ui.hospital.research + local object_list = {} -- transform set to list for i, o in ipairs(self.room.room_info.objects_additional) do -- Don't show the object if it hasn't been researched yet. local object = TheApp.objects[o] - local research = self.ui.hospital.research - local avail = research.level_config.objects[object.thob].AvailableForLevel - if avail == 1 and (not research.research_progress[object] - or research.research_progress[object].discovered) then + local avail = cfg_objects[object.thob].AvailableForLevel + if avail == 1 and (not research.research_progress[object] or + research.research_progress[object].discovered) then -- look up current quantity local cur_qty = 0 - for j, p in ipairs(self.objects) do + for _, p in ipairs(self.objects) do if p.object.id == o then cur_qty = p.qty end @@ -580,11 +593,10 @@ function UIEditRoom:returnToDoorPhase() self.ui:tutorialStep(3, {13, 14, 15}, 9) local map = self.ui.app.map.th - local rect = self.blueprint_rect local room = self.room room.built = false if room.door and room.door.queue then - room.door.queue:rerouteAllPatients({name = "seek_room", room_type = room.room_info.id}) + room.door.queue:rerouteAllPatients(SeekRoomAction(room.room_info.id)) end self.purchase_button:enable(false) @@ -598,10 +610,16 @@ if not obj or obj == room.door or class.is(obj, SwingDoor) then break end + if obj.object_type.id == "litter" then -- Silently remove litter from the world. + obj.remove() + break + end + local obj_state = obj:getState() self.world:destroyEntity(obj) if not obj.master then self:addObjects({{ object = TheApp.objects[obj.object_type.id], + state = obj_state, qty = 1 }}) end @@ -616,14 +634,14 @@ -- backup list of objects self.objects_backup = {} for k, o in pairs(self.objects) do - self.objects_backup[k] = { object = o.object, qty = o.qty } + self.objects_backup[k] = { object = o.object, qty = o.qty, state = o.state } end UIPlaceObjects.removeAllObjects(self, true) -- Remove walls local function remove_wall_line(x, y, step_x, step_y, n_steps, layer, neigh_x, neigh_y) - for i = 1, n_steps do + for _ = 1, n_steps do local existing = map:getCell(x, y, layer) -- Possibly add transparency. local flag = 0 @@ -671,8 +689,8 @@ function UIEditRoom:screenToWall(x, y) local cellx, celly = self.ui:ScreenToWorld(x, y) - cellx = math_floor(cellx) - celly = math_floor(celly) + cellx = math.floor(cellx) + celly = math.floor(celly) local rect = self.blueprint_rect if cellx == rect.x or cellx == rect.x - 1 or cellx == rect.x + rect.w or cellx == rect.x + rect.w - 1 or @@ -694,15 +712,21 @@ end if cellx == rect.x and celly == rect.y then -- top corner - local x_, y_ = self.ui:WorldToScreen(cellx, celly) + local x_, _ = self.ui:WorldToScreen(cellx, celly) if x >= x_ then - return cellx + 1 + modifier, celly, "north" + -- correctly reflects (at least origin version) of TH. + -- Swing doors in top corner to the east, actually skip another tile + if swinging then + return cellx + 2 + modifier, celly, "north" + else + return cellx + 1 + modifier, celly, "north" + end else return cellx, celly + 1 + modifier, "west" end elseif cellx == rect.x + rect.w - 1 and celly == rect.y + rect.h - 1 then -- bottom corner - local x_, y_ = self.ui:WorldToScreen(cellx, celly) + local x_, _ = self.ui:WorldToScreen(cellx, celly) if x >= x_ then return cellx, celly - 1, "east" else @@ -710,17 +734,25 @@ end elseif cellx == rect.x and celly == rect.y + rect.h - 1 then -- left corner - local x_, y_ = self.ui:WorldToScreen(cellx, celly) + local _, y_ = self.ui:WorldToScreen(cellx, celly) if y >= y_ + 16 then - return cellx + 1, celly, "south" + if swinging and cellx <= rect.x + 2 then + return cellx + 1 + modifier, celly, "south" + else + return cellx + 1, celly, "south" + end else return cellx, celly - 1, "west" end elseif cellx == rect.x + rect.w - 1 and celly == rect.y then -- right corner - local x_, y_ = self.ui:WorldToScreen(cellx, celly) + local _, y_ = self.ui:WorldToScreen(cellx, celly) if y >= y_ + 16 then - return cellx, celly + 1, "east" + if swinging and celly <= rect.y + 2 then + return cellx, celly + 1 + modifier, "east" + else + return cellx, celly + 1, "east" + end else return cellx - 1, celly, "north" end @@ -737,28 +769,33 @@ return rect.x, celly, "west" elseif (celly == rect.y - 1 or celly == rect.y) and rect.x <= cellx and cellx < rect.x + rect.w then -- north edge - if cellx == rect.x then - cellx = rect.x + 1 + -- correctly reflects (at least origin version) of TH. + -- Swing doors in top corner to the east, actually skip another tile + if swinging and cellx <= rect.x + 2 then + cellx = rect.x + 3 + elseif cellx == rect.x then + cellx = rect.x + 1 + modifier elseif cellx == rect.x + rect.w - 1 then cellx = rect.x + rect.w - 2 end - if swinging and cellx <= rect.x + 1 then - cellx = cellx + 1 - end return cellx, rect.y, "north" - elseif (cellx == rect.x + rect.w or cellx == rect.x + rect.w - 1) - and rect.y <= celly and celly < rect.y + rect.h then - -- east edge - if celly == rect.y then + elseif (cellx == rect.x + rect.w or cellx == rect.x + rect.w - 1) and + rect.y <= celly and celly < rect.y + rect.h then + -- east edge + if swinging and celly <= rect.y + 1 then + celly = rect.y + 2 + elseif celly == rect.y then celly = rect.y + 1 elseif celly == rect.y + rect.h - 1 then celly = rect.y + rect.h - 2 end return rect.x + rect.w - 1, celly, "east" - elseif (celly == rect.y + rect.h or celly == rect.y + rect.h - 1) - and rect.x <= cellx and cellx < rect.x + rect.w then + elseif (celly == rect.y + rect.h or celly == rect.y + rect.h - 1) and + rect.x <= cellx and cellx < rect.x + rect.w then -- south edge - if cellx == rect.x then + if swinging and cellx <= rect.x + 1 then + cellx = rect.x + 2 + elseif cellx == rect.x then cellx = rect.x + 1 elseif cellx == rect.x + rect.w - 1 then cellx = rect.x + rect.w - 2 @@ -789,22 +826,22 @@ end while x < rect.x + rect.w do - if not check"travelSouth" then return false end + if not check("travelSouth") then return false end x = x + 1 end y = y + 1 while y < rect.y + rect.h do - if not check"travelWest" then return false end + if not check("travelWest") then return false end y = y + 1 end x = x - 1 while x >= rect.x do - if not check"travelNorth" then return false end + if not check("travelNorth") then return false end x = x - 1 end y = y - 1 while y >= rect.y do - if not check"travelEast" then return false end + if not check("travelEast") then return false end y = y - 1 end @@ -844,7 +881,7 @@ -- Re-organise wall anims to index by x and y local walls = {} for _, wall in ipairs(self.blueprint_wall_anims) do - local map, x, y = wall:getTile() + local _, x, y = wall:getTile() if not walls[x] then walls[x] = {} end @@ -860,6 +897,7 @@ end function UIEditRoom:enterObjectsPhase() + self.ui:setCursor(self.ui.default_cursor) self.ui:tutorialStep(3, {11, 12}, 13) self.ui:setWorldHitTest(self.room) local confirm = self:checkEnableConfirm() @@ -876,7 +914,7 @@ if self.objects_backup then self:addObjects(self.objects_backup, true) else - local room_objects = self.room.room_info.objects_needed; + local room_objects = self.room.room_info.objects_needed if TheApp.config.enable_avg_contents then room_objects = self:computeAverageContents() end @@ -896,8 +934,8 @@ local average_objects = {} -- what does the average room of this type contain? local room_count = 0 for _, room in pairs(self.world.rooms) do - if room and room.built and not room.crashed - and room.hospital == self.ui.hospital and room.room_info == self.room_type then + if room and room.built and not room.crashed and + room.hospital == self.ui.hospital and room.room_info == self.room_type then room_count = room_count + 1 for obj, _ in pairs(room.objects) do average_objects[obj.object_type.id] = (average_objects[obj.object_type.id] or 0) + 1 @@ -931,8 +969,8 @@ local x, y = ui:WorldToScreen(self.mouse_cell_x, self.mouse_cell_y) local zoom = self.ui.zoom_factor if canvas:scale(zoom) then - x = x / zoom - y = y / zoom + x = math.floor(x / zoom) + y = math.floor(y / zoom) end self.cell_outline:draw(canvas, 2, x - 32, y) canvas:scale(1) @@ -947,9 +985,9 @@ if self.phase == "walls" then if 0 <= x and x < self.width and 0 <= y and y < self.height then else - local x, y = self.ui:ScreenToWorld(self.x + x, self.y + y) - self.mouse_down_x = math_floor(x) - self.mouse_down_y = math_floor(y) + local mouse_x, mouse_y = self.ui:ScreenToWorld(self.x + x, self.y + y) + self.mouse_down_x = math.floor(mouse_x) + self.mouse_down_y = math.floor(mouse_y) if self.move_rect then self.move_rect_x = self.mouse_down_x - self.blueprint_rect.x self.move_rect_y = self.mouse_down_y - self.blueprint_rect.y @@ -961,7 +999,7 @@ end elseif self.phase == "door" then if self.blueprint_door.valid then - self.ui:playSound "buildclk.wav" + self.ui:playSound("buildclk.wav") self:confirm(true) else self.ui:tutorialStep(3, 9, 10) @@ -997,6 +1035,8 @@ function UIEditRoom:setBlueprintRect(x, y, w, h) local rect = self.blueprint_rect local map = self.ui.app.map + if x < 1 then x = 1 end + if y < 1 then y = 1 end if x + w > map.width then w = map.width - x end if y + h > map.height then h = map.height - y end @@ -1006,12 +1046,13 @@ end local too_small = w < self.room_type.minimum_size or h < self.room_type.minimum_size + local player_id = self.ui.hospital:getPlayerIndex() -- Entire update of floor tiles and wall animations done in C to replace -- several hundred calls into C with just a single call. The price for this -- is reduced flexibility. See l_map_updateblueprint in th_lua.cpp for code. local is_valid = map.th:updateRoomBlueprint(rect.x, rect.y, rect.w, rect.h, - x, y, w, h, self.blueprint_wall_anims, self.anims, too_small) + x, y, w, h, player_id, self.blueprint_wall_anims, self.anims, too_small) -- NB: due to the unflexibility, tutorial step "too small AND invalid position" (3.7) -- is currently unusable, as it's not possible to determine if the position would @@ -1034,11 +1075,20 @@ rect.h = h end +--25 north wall, west +--26 north wall, east +--27 east wall, south +--28 east wall, north +--29 south wall, west +--30 south wall, east +--31 west wall, south +--32 west wall, north +-- single door blue print values matching TH local door_floor_blueprint_markers = { - north = 25, - east = 28, - south = 29, - west = 32, + north = 26, + east = 27, + south = 30, + west = 31 } local window_floor_blueprint_markers = { @@ -1048,12 +1098,74 @@ west = 36, } -function UIEditRoom:setDoorBlueprint(x, y, wall) - local orig_x = x - local orig_y = y - local orig_wall = wall +--! Check walls for having room for the door +--!param x (int) X tile position of the door. +--!param y (int) Y tile position of the door. +--!param wall (string) Name of the wall (either 'north' or 'west'). +--!param has_swingdoor (boolean) Whether the room has a normal door (false) or a swing door (true) as entrance. +--!return (int) bit flags indicating invalid tile position using 1 based power of 2 as this works with ipairs +--! values returned are the enumeration of +--! 4 = centre door in swing door or for single door the value can just be non-zero but uses the same bit of code +--! 2 (door section closer to top of screen) - smaller x or y +--! 8 (door section closer to bottom of screen) - larger x or y +local function checkDoorWalls(x, y, wall, has_swingdoor) + local th = TheApp.map.th + + local dx, dy, wall_num + if wall == "west" then + wall_num = 3 + dx = 0 + dy = 1 + else + wall_num = 2 + dx = 1 + dy = 0 + end + local invalid_tile = 0 + if th:getCell(x, y, wall_num) % 0x100 ~= 0 then + invalid_tile = 4 + end + + -- If it is a swing door there are two more locations to check. + if has_swingdoor then + if th:getCell(x - dx, y - dy, wall_num) % 0x100 ~= 0 then + invalid_tile = invalid_tile + 2 + end + if th:getCell(x + dx, y + dy, wall_num) % 0x100 ~= 0 then + invalid_tile = invalid_tile + 8 + end + end + return invalid_tile +end + +--! Check whether the given tile can function as a door entry/exit tile. +--!param xpos (int) X position of the tile. +--!param ypos (int) Y position of the tile. +--!param player_id (int) Player id owning the hospital. +--!param world - reference to world object instance +--!return (boolean) whether the tile is considered to be valid. +local function validDoorTile(xpos, ypos, player_id, world) + local th = TheApp.map.th + local tile_flags = th:getCellFlags(xpos, ypos) + -- check own it + if tile_flags.owner ~= player_id then return false end + -- any object will cause it to be blocked (ignore litter) + if tile_flags.thob ~= 0 and tile_flags.thob ~= 62 then return false end + -- check if its passable that no object footprint blocks it + if tile_flags.passable then return world:isTileExclusivelyPassable(xpos, ypos, 1) end + return true +end - -- Used to get the adjacent tiles when placing swing doors. +--! Calculate position offsets and door blueprint wall values +--! param x (int) doors blueprint x value +--! param y (int) doors blueprint y value +--! param wall (string) original wall orientation +--! return x (int) updated x value +--! return y (int) updated y value +--! return x_mod (int) offest value to apply to tile count to determine relative position +--! return y_mod (int) offset value to apply to tile count to determine relatitve position +--! return wall (string) wall orientation style (only 2 styles) +local function doorWallOffsetCalculations(x, y, wall) local x_mod local y_mod if wall == "south" then @@ -1069,11 +1181,20 @@ else y_mod = 2 end - local map = self.ui.app.map.th + return x, y, x_mod, y_mod, wall +end + +function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) + local x, y, x_mod, y_mod, wall = doorWallOffsetCalculations(orig_x, orig_y, orig_wall) + local map = TheApp.map.th if self.blueprint_door.anim then if self.room_type.swing_doors then if self.blueprint_door.anim[1] then + -- retrieve the old door position details to reset the blue print + local oldx, oldy + local _, _, oldx_mod, oldy_mod, _ = doorWallOffsetCalculations(self.blueprint_door.floor_x, + self.blueprint_door.floor_y, self.blueprint_door.wall) -- If we're dealing with swing doors the anim variable is actually a table with three -- identical "doors". for i, anim in ipairs(self.blueprint_door.anim) do @@ -1081,8 +1202,10 @@ self.blueprint_door.old_flags[i]) anim:setTag(nil) self.blueprint_door.anim[i] = nil + oldx = oldx_mod and self.blueprint_door.floor_x + (i - oldx_mod) or self.blueprint_door.floor_x + oldy = oldy_mod and self.blueprint_door.floor_y + (i - oldy_mod) or self.blueprint_door.floor_y + map:setCell(oldx, oldy, 4, 24) end - map:setCell(self.blueprint_door.floor_x, self.blueprint_door.floor_y, 4, 24) end else self.blueprint_door.anim:setAnimation(self.anims, self.blueprint_door.old_anim, @@ -1119,82 +1242,72 @@ else if anim ~= self.blueprint_door.anim then self.blueprint_door.anim = anim - self.blueprint_door.anim:setTag"door" + self.blueprint_door.anim:setTag("door") self.blueprint_door.old_anim = anim:getAnimation() self.blueprint_door.old_flags = anim:getFlag() end end - self.blueprint_door.valid = true + local flags local x2, y2 = x, y if wall == "west" then flags = 1 x2 = x2 - 1 - -- Check for a wall to the west, and prevent placing a door on top of an - -- existing wall. - if map:getCell(x, y, 3) % 0x100 ~= 0 then - self.blueprint_door.valid = false - end - -- If it is a swing door there are two more locations to check. - if self.room_type.swing_doors then - if map:getCell(x, y - 1, 3) % 0x100 ~= 0 - or map:getCell(x, y + 1, 3) % 0x100 ~= 0 then - self.blueprint_door.valid = false - end - end else--if wall == "north" then flags = 0 y2 = y2 - 1 - if map:getCell(x, y, 2) % 0x100 ~= 0 then - self.blueprint_door.valid = false - end - -- If it is a swing door there are two more locations to check. - if self.room_type.swing_doors then - if map:getCell(x - 1, y, 2) % 0x100 ~= 0 - or map:getCell(x + 1, y, 2) % 0x100 ~= 0 then - self.blueprint_door.valid = false - end - end end - if self.blueprint_door.valid then - -- Ensure that the door isn't being built on top of an object - local flags = {} - local flag_names - if wall == "west" then - flag_names = {"buildableNorth", "buildableSouth"} - else - flag_names = {"buildableWest", "buildableEast"} - end - if not (map:getCellFlags(x , y , flags).buildable or flags.passable) - or not (flags[flag_names[1]] and flags[flag_names[2]]) - or not (map:getCellFlags(x2, y2, flags).buildable or flags.passable) - or not (flags[flag_names[1]] and flags[flag_names[2]]) - then - self.blueprint_door.valid = false + local world = self.ui.app.world + -- invalid_tile used to select the individual blueprint that is blocked + local invalid_tile = checkDoorWalls(x, y, wall, self.room_type.swing_doors) + -- Ensure that the door isn't being built on top of an object + local player_id = self.ui.hospital:getPlayerIndex() + if not validDoorTile(x, y, player_id, world) or + not validDoorTile(x2, y2, player_id, world) then + invalid_tile = bitOr(invalid_tile, 4) + end + -- If we're making swing doors two more tiles need to be checked. + if self.room_type.swing_doors then + local dx = x_mod and 1 or 0 + local dy = y_mod and 1 or 0 + if not validDoorTile(x + dx, y + dy, player_id, world) or + not validDoorTile(x2 + dx, y2 + dy, player_id, world) then + invalid_tile = bitOr(invalid_tile, 8) end - -- If we're making swing doors two more tiles need to be checked. - if self.room_type.swing_doors then - if not (map:getCellFlags(x + (x_mod and 1 or 0) , y + (y_mod and 1 or 0) , flags).buildable or flags.passable) - or not (map:getCellFlags(x2 + (x_mod and 1 or 0) , y2 + (y_mod and 1 or 0) , flags).buildable or flags.passable) then - self.blueprint_door.valid = false - end - if not (map:getCellFlags(x - (x_mod and 1 or 0) , y - (y_mod and 1 or 0) , flags).buildable or flags.passable) - or not (map:getCellFlags(x2 - (x_mod and 1 or 0) , y2 - (y_mod and 1 or 0), flags).buildable or flags.passable) then - self.blueprint_door.valid = false - end + if not validDoorTile(x - dx, y - dy, player_id, world) or + not validDoorTile(x2 - dx, y2 - dy, player_id, world) then + invalid_tile = bitOr(invalid_tile, 2) end end - if not self.blueprint_door.valid then - flags = flags + 16 -- Use red palette rather than normal palette - end + + self.blueprint_door.valid = (invalid_tile == 0) + if self.room_type.swing_doors then - for i, anim in ipairs(anim) do - anim:setAnimation(self.anims, 126, flags) + for i, animation in ipairs(anim) do + -- calculation here to flag blocked blueprint tiles on swing doors for each door tile + animation:setAnimation(self.anims, 126, flags + (hasBit(invalid_tile, i) and 1 or 0) * 16) end else - anim:setAnimation(self.anims, 126, flags) + anim:setAnimation(self.anims, 126, flags + (invalid_tile ~= 0 and 1 or 0) * 16) end - if self.blueprint_door.valid then + if self.room_type.swing_doors then + flags = door_floor_blueprint_markers[orig_wall] + local dirfix = orig_wall == "east" + flags = dirfix and flags + 1 or flags + for i = 1, 3 do + local x1 = x_mod and orig_x + i - x_mod or orig_x + local y1 = y_mod and orig_y + i - y_mod or orig_y + if (i == 2) then + map:setCell(x1, y1, 4, 24) + else + if dirfix then + map:setCell(x1, y1, 4, i < 2 and flags or flags - 1) + else + map:setCell(x1, y1, 4, i > 2 and flags or flags - 1) + end + end + end + else map:setCell(self.blueprint_door.floor_x, self.blueprint_door.floor_y, 4, door_floor_blueprint_markers[orig_wall]) end @@ -1203,16 +1316,16 @@ function UIEditRoom:placeWindowBlueprint() if self.blueprint_window.anim and self.blueprint_window.valid then self.blueprint_window = {} - self.ui:playSound "buildclk.wav" + self.ui:playSound("buildclk.wav") elseif self.blueprint_window.anim and not self.blueprint_window.valid then self.ui:tutorialStep(3, 11, 12) end end -function UIEditRoom:setWindowBlueprint(x, y, wall) - local orig_x = x - local orig_y = y - local orig_wall = wall +function UIEditRoom:setWindowBlueprint(orig_x, orig_y, orig_wall) + local x = orig_x + local y = orig_y + local wall = orig_wall if wall == "south" then y = y + 1 @@ -1235,7 +1348,8 @@ local anim = x and self.blueprint_wall_anims[x][y] if anim and anim:getTag() then - x, y, wall, orig_x, orig_y, orig_wall = nil + x, y, wall = nil, nil, nil + orig_x, orig_y, orig_wall = nil, nil, nil end self.blueprint_window.x = x @@ -1250,7 +1364,7 @@ if anim ~= self.blueprint_window.anim then self.blueprint_window.anim = anim - self.blueprint_window.anim:setTag"window" + self.blueprint_window.anim:setTag("window") self.blueprint_window.old_anim = anim:getAnimation() self.blueprint_window.old_flags = anim:getFlag() end @@ -1287,8 +1401,8 @@ return end local wx, wy = ui:ScreenToWorld(self.x + x, self.y + y) - wx = math_floor(wx) - wy = math_floor(wy) + wx = math.floor(wx) + wy = math.floor(wy) if self.phase == "walls" then local rect = self.blueprint_rect @@ -1300,7 +1414,7 @@ self.resize_rect = false elseif wx < rect.x or wx >= rect.x + rect.w or wy < rect.y or wy >= rect.y + rect.h then -- outside blueprint - ui:setCursor(ui.default_cursor) + ui:setCursor(ui.app.gfx:loadMainCursor("resize_room")) self.move_rect = false self.resize_rect = false else @@ -1323,6 +1437,9 @@ end end else + if self.phase ~= "clear_area" and self.phase ~= "objects" then + ui:setCursor(ui.app.gfx:loadMainCursor("resize_room")) + end local cell_x, cell_y, wall = self:screenToWall(self.x + x, self.y + y) if self.phase == "door" then self:setDoorBlueprint(cell_x, cell_y, wall) @@ -1412,3 +1529,13 @@ self:checkEnableConfirm() end end + +function UIEditRoom:afterLoad(old, new) + if old < 101 then + self:removeKeyHandler("enter") + self:addKeyHandler("return", self.confirm) + end + if old < 104 then + self:addKeyHandler("keypad enter", self.confirm) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/annual_report.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/annual_report.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/annual_report.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/annual_report.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,11 +18,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" - --! Annual Report fullscreen window shown at the start of each year. class "UIAnnualReport" (UIFullscreen) +---@type UIAnnualReport +local UIAnnualReport = _G["UIAnnualReport"] + +--! Helper function that enables and makes visible button or table of buttons/panels. +--!param button The button or table of buttons that should be activated/deactivated. If +-- a table is given it needs to have the is_table flag set to true. +--!param active Defines if the new state is active (true) or inactive (false). +local function setActive(button, active) + if button.is_table then + for _, btn in ipairs(button) do + btn.enabled = active + btn.visible = active + end + else + button.enabled = active + button.visible = active + end +end + function UIAnnualReport:UIAnnualReport(ui, world) self:UIFullscreen(ui) @@ -65,15 +82,15 @@ -- Close button, in the future different behaviours for different screens though --self.first_close = self:addPanel(0, 609, 449):makeButton(0, 0, 26, 26, 1, self.changePage) self.second_close = self:addPanel(0, 608, 449):makeButton(0, 0, 26, 26, 1, self.close) - self:setActive(self.second_close, true) + setActive(self.second_close, true) -- Change page buttons for the second and third pages local --[[persistable:annual_report_change_page]] function change() self:changePage(3) end self.second_change = self:addPanel(0, 274, 435):makeButton(0, 0, 91, 42, 3, change) - self:setActive(self.second_change, true) + setActive(self.second_change, true) self.third_change = self:addPanel(0, 272, 367):makeButton(0, 0, 91, 42, 3, self.changePage) - self:setActive(self.third_change, false) + setActive(self.third_change, false) -- The plaque showed after the player has clicked on a trophy local plaque = {} @@ -83,11 +100,11 @@ plaque[4] = self:addPanel(22, 206, 321) plaque.is_table = true self.plaque = plaque - self:setActive(self.plaque, false) + setActive(self.plaque, false) -- Close button for the trophy motivations self.third_close = self:addPanel(0, 389, 378):makeButton(0, 0, 26, 26, 2, self.showTrophyMotivation) - self:setActive(self.third_close, false) + setActive(self.third_close, false) -- The scroll showed after the player has clicked on an award local scroll = {} @@ -97,11 +114,11 @@ scroll[4] = self:addPanel(15, 300, 341) scroll.is_table = true self.scroll = scroll - self:setActive(self.scroll, false) + setActive(self.scroll, false) -- Close button for the award motivations self.fourth_close = self:addPanel(0, 369, 358):makeButton(0, 0, 26, 26, 2, self.showAwardMotivation) - self:setActive(self.fourth_close, false) + setActive(self.fourth_close, false) -- How many awards the player got this year. Will increase after the checkup. self.no_awards = 0 @@ -154,7 +171,7 @@ table.sort(self.salary_sort, sort_order) -- Pause the game to allow the player plenty of time to check all statistics and trophies won - if world and world:isCurrentSpeed("Speed Up") then + if world and not world:isCurrentSpeed("Pause") then world:setSpeed("Pause") end TheApp.video:setBlueFilterActive(false) @@ -164,10 +181,11 @@ function UIAnnualReport:checkTrophiesAndAwards(world) local hosp = self.ui.hospital - local prices = world.map.level_config.awards_trophies + local level_config = world.map.level_config + local prices = level_config and level_config.awards_trophies or nil -- Check CuresAward so that we know the new config settings are available - if hosp.win_awards and prices.TrophyMayorBonus then + if prices and prices.TrophyMayorBonus then self.won_amount = 0 self.rep_amount = 0 self.award_won_amount = 0 @@ -339,7 +357,7 @@ trophy_parts[1] = self:addPanel(prop.sprite, prop.x, prop.y) trophy_parts[2] = trophy_parts[1]:makeButton(0, 0, prop.w, prop.h, prop.sprite, change) - self:setActive(trophy_parts, false) + setActive(trophy_parts, false) self.trophies[no] = trophy_parts end self.no_trophies = no @@ -387,7 +405,7 @@ local --[[persistable:annual_report_show_award_motivation]] function change() self:showAwardMotivation(no) end award_parts[4] = award_parts[3]:makeButton(0, 0, 105, 103, award_shadows[no].shadow, change) self.awards[no] = award_parts - self:setActive(award_parts, false) + setActive(award_parts, false) end -- The economic part of the award. @@ -400,18 +418,18 @@ if text_index_to_show then -- Make sure no trophy motivation is shown self:showTrophyMotivation() - self:setActive(self.scroll, true) + setActive(self.scroll, true) -- Possibly hide the black award symbol if self.awards[text_index_to_show].info.amount > 0 then - self:setActive(self.scroll[4], false) + setActive(self.scroll[4], false) end - self:setActive(self.fourth_close, true) - self:setActive(self.third_change, false) + setActive(self.fourth_close, true) + setActive(self.third_change, false) self.award_motivation = text_index_to_show else - self:setActive(self.scroll, false) - self:setActive(self.fourth_close, false) - self:setActive(self.third_change, true) + setActive(self.scroll, false) + setActive(self.fourth_close, false) + setActive(self.third_change, true) self.award_motivation = nil end end @@ -422,34 +440,18 @@ if text_index_to_show then -- Make sure no award motivation is shown self:showAwardMotivation() - self:setActive(self.plaque, true) - self:setActive(self.third_close, true) - self:setActive(self.third_change, false) + setActive(self.plaque, true) + setActive(self.third_close, true) + setActive(self.third_change, false) self.trophy_motivation = text_index_to_show else - self:setActive(self.plaque, false) - self:setActive(self.third_close, false) - self:setActive(self.third_change, true) + setActive(self.plaque, false) + setActive(self.third_close, false) + setActive(self.third_change, true) self.trophy_motivation = nil end end ---! Helper function that enables and makes visible button or table of buttons/panels. ---!param button The button or table of buttons that should be activated/deactivated. If --- a table is given it needs to have the is_table flag set to true. ---!param active Defines if the new state is active (true) or inactive (false). -function UIAnnualReport:setActive(button, active) - if button.is_table then - for _, btn in ipairs(button) do - btn.enabled = active - btn.visible = active - end - else - button.enabled = active - button.visible = active - end -end - --! Overridden close function. The game should be unpaused again when closing the dialog. function UIAnnualReport:close() if TheApp.world:getLocalPlayerHospital().game_won then @@ -459,41 +461,46 @@ end TheApp.world.ui.bottom_panel:openLastMessage() elseif TheApp.world:isCurrentSpeed("Pause") then - TheApp.world:setSpeed(TheApp.world.prev_speed) + if TheApp.ui.speed_up_key_pressed then + TheApp.world:setSpeed("Speed Up") + else + TheApp.world:setSpeed(TheApp.world.prev_speed) + end end self:updateAwards() Window.close(self) + self.ui.app.world:checkIfGameWon() end --! Changes the page of the annual report --!param page_no The page to go to, either page 1, 2 or 3. Default is currently page 2. function UIAnnualReport:changePage(page_no) -- Can only go to page 2 from page 1, and then only between page 2 and 3 - --self:setActive(self.first_close, false) - self:setActive(self.second_close, true) + --setActive(self.first_close, false) + setActive(self.second_close, true) self.second_close.visible = true if page_no == 2 or not page_no then -- Statistics page. self.background = self.stat_background - self:setActive(self.third_change, false) - self:setActive(self.second_change, true) + setActive(self.third_change, false) + setActive(self.second_change, true) for i, _ in ipairs(self.trophies) do - self:setActive(self.trophies[i], false) + setActive(self.trophies[i], false) end for i, _ in ipairs(self.awards) do - self:setActive(self.awards[i], false) + setActive(self.awards[i], false) end self.state = 2 else -- Awards and trophies self.background = self.award_background - self:setActive(self.third_change, true) - self:setActive(self.second_change, false) + setActive(self.third_change, true) + setActive(self.second_change, false) -- Show awards given. for i, _ in ipairs(self.awards) do - self:setActive(self.awards[i], true) + setActive(self.awards[i], true) end -- And trophies given. for i, _ in ipairs(self.trophies) do - self:setActive(self.trophies[i], true) + setActive(self.trophies[i], true) end self.state = 3 end @@ -521,7 +528,7 @@ font:draw(canvas, i .. ".", x + 220, y + 160 + dy) font:draw(canvas, world.hospitals[1].name:upper(), x + 260, y + 160 + dy) font:draw(canvas, "NA", x + 360, y + 160 + dy) - dy = dy + 25 + -- dy = dy + 25 --end elseif self.state == 2 then -- Statistics screen self:drawStatisticsScreen(canvas, x, y) @@ -564,8 +571,7 @@ local world = self.ui.app.world -- Draw titles - font:draw(canvas, _S.menu.charts .. " " - .. (world.year + 1999), x + 210, y + 30, 200, 0) + font:draw(canvas, _S.menu.charts .. " " .. (world:date():year() + 1999), x + 210, y + 30, 200, 0) font:draw(canvas, _S.high_score.categories.money, x + 140, y + 98, 170, 0) font:draw(canvas, _S.high_score.categories.salary, x + 328, y + 98, 170, 0) font:draw(canvas, _S.high_score.categories.cures, x + 140, y + 205, 170, 0) @@ -605,49 +611,49 @@ local name = player.name -- Most Money - local index, dup_m = getindex(self.money_sort, self.money[name]) - -- index is the returned value of the sorted place for this player. + local index_m, dup_m = getindex(self.money_sort, self.money[name]) + -- index_* is the returned value of the sorted place for this player. -- However there might be many players with the same value, so each iteration a -- duplicate has been found, one additional row lower is the right place to be. font:draw(canvas, name:upper(), x + 140, - y + row_y + row_dy*(index-1) + row_dy*(dup_money)) + y + row_y + row_dy * (index_m - 1) + row_dy * dup_money) font:draw(canvas, self.money[name], x + 240, - y + row_y + row_dy*(index-1) + row_dy*(dup_money), 70, 0, "right") + y + row_y + row_dy * (index_m - 1) + row_dy * dup_money, 70, 0, "right") -- Highest Salary - local index, dup_s = getindex(self.salary_sort, self.salary[name]) + local index_s, dup_s = getindex(self.salary_sort, self.salary[name]) font:draw(canvas, name:upper(), x + 140 + col_x, - y + row_y + row_dy*(index-1) + row_dy*(dup_salary)) + y + row_y + row_dy * (index_s - 1) + row_dy * dup_salary) font:draw(canvas, self.salary[name], x + 240 + col_x, - y + row_y + row_dy*(index-1) + row_dy*(dup_salary), 70, 0, "right") + y + row_y + row_dy * (index_s - 1) + row_dy * dup_salary, 70, 0, "right") -- Most Cures - local index, dup_c = getindex(self.cures_sort, self.cures[name]) + local index_c, dup_c = getindex(self.cures_sort, self.cures[name]) font:draw(canvas, name:upper(), x + 140, - y + row_y + row_no_y + row_dy*(index-1) + row_dy*(dup_cures)) + y + row_y + row_no_y + row_dy * (index_c - 1) + row_dy * dup_cures) font:draw(canvas, self.cures[name], x + 240, - y + row_y + row_no_y + row_dy*(index-1) + row_dy*(dup_cures), 70, 0, "right") + y + row_y + row_no_y + row_dy * (index_c - 1) + row_dy * dup_cures, 70, 0, "right") -- Most Deaths - local index, dup_d = getindex(self.deaths_sort, self.deaths[name]) + local index_d, dup_d = getindex(self.deaths_sort, self.deaths[name]) font:draw(canvas, name:upper(), x + 140 + col_x, - y + row_y + row_no_y + row_dy*(index-1) + row_dy*(dup_deaths)) + y + row_y + row_no_y + row_dy * (index_d - 1) + row_dy * dup_deaths) font:draw(canvas, self.deaths[name], x + 240 + col_x, - y + row_y + row_no_y + row_dy*(index-1) + row_dy*(dup_deaths), 70, 0, "right") + y + row_y + row_no_y + row_dy * (index_d - 1) + row_dy * dup_deaths, 70, 0, "right") -- Most Visitors - local index, dup_v = getindex(self.visitors_sort, self.visitors[name]) + local index_v, dup_v = getindex(self.visitors_sort, self.visitors[name]) font:draw(canvas, name:upper(), x + 140, - y + row_y + row_no_y*2 + row_dy*(index-1) + row_dy*(dup_visitors)) + y + row_y + row_no_y * 2 + row_dy * (index_v - 1) + row_dy * dup_visitors) font:draw(canvas, self.visitors[name], x + 240, - y + row_y + row_no_y*2 + row_dy*(index-1) + row_dy*(dup_visitors), 70, 0, "right") + y + row_y + row_no_y * 2 + row_dy * (index_v - 1) + row_dy * dup_visitors, 70, 0, "right") -- Highest Value - local index, dup_v2 = getindex(self.value_sort, self.value[name]) + local index_v2, dup_v2 = getindex(self.value_sort, self.value[name]) font:draw(canvas, name:upper(), x + 140 + col_x, - y + row_y + row_no_y*2 + row_dy*(index-1) + row_dy*(dup_value)) + y + row_y + row_no_y * 2 + row_dy * (index_v2 - 1) + row_dy * dup_value) font:draw(canvas, self.value[name], x + 240 + col_x, - y + row_y + row_no_y*2 + row_dy*(index-1) + row_dy*(dup_value), 70, 0, "right") + y + row_y + row_no_y * 2 + row_dy * (index_v2 - 1) + row_dy * dup_value, 70, 0, "right") if dup_m > 1 then dup_money = dup_money + 1 else dup_money = 0 end if dup_s > 1 then dup_salary = dup_salary + 1 else dup_salary = 0 end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/bank_manager.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/bank_manager.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/bank_manager.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/bank_manager.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Bank manager (for loans / insurance companies) and bank statement fullscreen windows. class "UIBankManager" (UIFullscreen) +---@type UIBankManager +local UIBankManager = _G["UIBankManager"] + function UIBankManager:UIBankManager(ui) self:UIFullscreen(ui) local gfx = ui.app.gfx @@ -121,15 +124,18 @@ UIFullscreen.afterLoad(self, old, new) end +--! Sum the values in the provided array. +--!param t Array to sum. +--!return (int) The sum of all values from the t array. local function sum(t) - local sum = 0 + local total = 0 for _, entry in ipairs(t) do - sum = sum + entry + total = total + entry end - return sum + return total end --- animation function +--! Animation function. function UIBankManager:onTick() self.counter = self.counter + 1 -- animate the eyes to blink @@ -226,6 +232,15 @@ font:draw(canvas, _S.bank_manager.statistics_page.money_in, x + 449, y + 41, 70, 0) font:draw(canvas, _S.bank_manager.statistics_page.balance, x + 525, y + 40, 70, 0) + -- Lua < 5.3 stored integer money amount in floating point values. + -- Lua 5.3 introduced an integer representation, and started printing + -- integer floating point numbers with a trailing .0 . + -- + -- As a result, CorsixTH games converted from earlier Lua versions print a + -- trailing .0 in the bank manager window. The "math.floor" around all + -- numbers printed below avoids that problem by converting to integer + -- representation for Lua 5.3, and doing nothing in Lua < 5.3. + -- Each transaction -- A for loop going backwards for no = 1, #hospital.transactions do @@ -234,11 +249,11 @@ font:draw(canvas, _S.date_format.daymonth:format(values.day, values.month), x + 48, current_y) font:draw(canvas, values.desc, x + 129, current_y) if values.spend then - font:draw(canvas, "$ " .. values.spend, x + 377, current_y) + font:draw(canvas, "$ " .. math.floor(values.spend), x + 377, current_y) else - font:draw(canvas, "$ " .. values.receive, x + 453, current_y) + font:draw(canvas, "$ " .. math.floor(values.receive), x + 453, current_y) end - font:draw(canvas, "$ " .. values.balance, x + 529, current_y) + font:draw(canvas, "$ " .. math.floor(values.balance), x + 529, current_y) end -- Summary @@ -252,11 +267,11 @@ -- The left side font:draw(canvas, _S.bank_manager.hospital_value, x + 60, y + 109, 143, 0) - font:draw(canvas, "$ " .. hospital.value, x + 60, y + 139, 143, 0) + font:draw(canvas, "$ " .. math.floor(hospital.value), x + 60, y + 139, 143, 0) font:draw(canvas, _S.bank_manager.balance, x + 60, y + 174, 143, 0) - font:draw(canvas, "$ " .. hospital.balance, x + 60, y + 204, 143, 0) + font:draw(canvas, "$ " .. math.floor(hospital.balance), x + 60, y + 204, 143, 0) font:draw(canvas, _S.bank_manager.current_loan, x + 60, y + 239, 143, 0) - font:draw(canvas, "$ " .. hospital.loan, x + 60, y + 269, 143, 0) + font:draw(canvas, "$ " .. math.floor(hospital.loan), x + 60, y + 269, 143, 0) font:draw(canvas, _S.bank_manager.interest_payment, x + 60, y + 305, 143, 0) local interest = math.floor(hospital.loan * hospital.interest_rate / 12) font:draw(canvas, "$ " .. interest, x + 60, y + 334, 143, 0) @@ -267,11 +282,11 @@ font:draw(canvas, hospital.insurance[self.chosen_insurance], x + 430, y + 132, 158, 0) else font:draw(canvas, hospital.insurance[1], x + 430, y + 132, 158, 0) - font:draw(canvas, "$ ".. sum(hospital.insurance_balance[1]), x + 430, y + 162, 100, 0) + font:draw(canvas, "$ ".. math.floor(sum(hospital.insurance_balance[1])), x + 430, y + 162, 100, 0) font:draw(canvas, hospital.insurance[2], x + 430, y + 192, 158, 0) - font:draw(canvas, "$ ".. sum(hospital.insurance_balance[2]), x + 430, y + 222, 100, 0) + font:draw(canvas, "$ ".. math.floor(sum(hospital.insurance_balance[2])), x + 430, y + 222, 100, 0) font:draw(canvas, hospital.insurance[3], x + 430, y + 252, 158, 0) - font:draw(canvas, "$ ".. sum(hospital.insurance_balance[3]), x + 430, y + 282, 100, 0) + font:draw(canvas, "$ ".. math.floor(sum(hospital.insurance_balance[3])), x + 430, y + 282, 100, 0) end font:draw(canvas, _S.bank_manager.inflation_rate, x + 430, y + 312, 100, 0) font:draw(canvas, hospital.inflation_rate*100 .. " %", x + 550, y + 313, 38, 0) @@ -398,7 +413,7 @@ local hospital = self.ui.hospital local max_loan = not self.world.free_build_mode and (math.floor((hospital.value * 0.33) / 5000) * 5000) + 10000 or 0 if hospital.loan + 5000 <= max_loan then - local amount = self.buttons_down.ctrl and max_loan - hospital.loan or 5000 + local amount = self.ui.app.key_modifiers.ctrl and max_loan - hospital.loan or 5000 hospital.loan = hospital.loan + amount hospital:receiveMoney(amount, _S.transactions.bank_loan) self.ui:playSound("selectx.wav") @@ -410,7 +425,7 @@ function UIBankManager:decreaseLoan() local hospital = self.ui.hospital local amount = 5000 - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then -- Repay as much as possible in increments of 5000 if hospital.balance > 5000 then amount = math.min(hospital.loan, math.floor(hospital.balance / 5000) * 5000) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/drug_casebook.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/drug_casebook.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/drug_casebook.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/drug_casebook.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Drug Casebook fullscreen window (view disease statistics and set prices). class "UICasebook" (UIFullscreen) +---@type UICasebook +local UICasebook = _G["UICasebook"] + function UICasebook:UICasebook(ui, disease_selection) self:UIFullscreen(ui) local gfx = ui.app.gfx @@ -56,7 +59,6 @@ self:addKeyHandler("down", self.scrollDown) self:addKeyHandler("right", self.increasePay) self:addKeyHandler("left", self.decreasePay) - self.ui:enableKeyboardRepeat() -- To quickly change values -- Icons representing cure effectiveness and other important information. self.machinery = self:addPanel(6, 306, 352):setTooltip(_S.tooltip.casebook.cure_type.machine) @@ -96,11 +98,11 @@ end function UICasebook:close() - self.ui:disableKeyboardRepeat() UIFullscreen.close(self) self.ui:getWindow(UIBottomPanel):updateButtonStates() end +--! The diseases list has been changed, update the list. function UICasebook:updateDiseaseList() -- A sorted list of known diseases and pseudo diseases. -- Used to be able to list the diseases in, believe it or not, @@ -118,11 +120,14 @@ end return c1.disease.name:upper() < c2.disease.name:upper() end) - if self.selected_index then - self.selected_disease = self.names_sorted[self.selected_index] + + if self.selected_disease then -- Re-select the current disease. + self:selectDisease(self.selected_disease) end end +--! Select a disease by name. +--!param disease (string) Name of the disease function UICasebook:selectDisease(disease) for i = 1, #self.names_sorted do if disease == self.names_sorted[i] then @@ -161,7 +166,7 @@ local staff = false -- Room requirements if #req.rooms > 0 then - for i, room_id in ipairs(req.rooms) do + for _, room_id in ipairs(req.rooms) do -- Not researched yet? if not hosp.discovered_rooms[world.available_rooms[room_id]] then known = false @@ -239,8 +244,8 @@ titles:draw(canvas, rep, x + 248, y + 92, 114, 0) -- Reputation -- Treatment Charge is either displayed in percent, or normally - local price_text = self.percentage_counter and ("%.0f%%"):format(book[disease].price * 100) - or "$" .. self.hospital:getTreatmentPrice(disease) + local price_text = self.percentage_counter and ("%.0f%%"):format(book[disease].price * 100) or + "$" .. self.hospital:getTreatmentPrice(disease) titles:draw(canvas, price_text, x + 262, y + 137, 90, 0) -- Treatment Charge titles:draw(canvas, "$" .. book[disease].money_earned, x + 248, y + 181, 114, 0) -- Money Earned @@ -268,7 +273,7 @@ function UICasebook:scrollUp() if self.selected_index > 1 then - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then self.selected_index = 1 else self.selected_index = self.selected_index - 1 @@ -284,7 +289,7 @@ function UICasebook:scrollDown() if self.selected_index < #self.names_sorted then - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then self.selected_index = #self.names_sorted else self.selected_index = self.selected_index + 1 @@ -301,9 +306,9 @@ function UICasebook:increasePay() local price = self.casebook[self.selected_disease].price local amount = 0.01 - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then amount = amount * 25 - elseif self.buttons_down.shift then + elseif self.ui.app.key_modifiers.shift then amount = amount * 5 end price = price + amount @@ -320,9 +325,9 @@ function UICasebook:decreasePay() local price = self.casebook[self.selected_disease].price local amount = 0.01 - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then amount = amount * 25 - elseif self.buttons_down.shift then + elseif self.ui.app.key_modifiers.shift then amount = amount * 5 end price = price - amount @@ -367,14 +372,13 @@ end end -function UICasebook:onMouseUp(code, x, y) - if not UIFullscreen.onMouseUp(self, code, x, y) then - if self:hitTest(x, y) then - if code == 4 then - -- Mouse wheel, scroll. +function UICasebook:onMouseWheel(x, y) + if not UIFullscreen.onMouseWheel(self, x, y) then + if self:hitTest(self.cursor_x, self.cursor_y) then + if y > 0 then self:scrollUp() return true - elseif code == 5 then + else self:scrollDown() return true end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/fax.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/fax.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/fax.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/fax.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,6 +20,9 @@ class "UIFax" (UIFullscreen) +---@type UIFax +local UIFax = _G["UIFax"] + function UIFax:UIFax(ui, icon) self:UIFullscreen(ui) local gfx = ui.app.gfx @@ -42,11 +45,10 @@ for i = 1, #choices do local y = orig_y + ((i-1) + (3-#choices)) * 48 local choice = choices[i].choice - local additionalInfo = choices[i].additionalInfo -- NB: both nil and true result in enabled; also handle old "disabled" choice local enabled = (choices[i].enabled ~= false) and (choice ~= "disabled") local --[[persistable:fax_choice_button]] function callback() - self:choice(choice,additionalInfo) + self:choice(i) end self.choice_buttons[i] = self:addPanel(17, 492, y):makeButton(0, 0, 43, 43, 18, callback) :setDisabledSprite(19):enable(enabled) @@ -65,21 +67,21 @@ return --[[persistable:fax_button]] function() self:appendNumber(char) end end - self:addPanel(0, 220, 348):makeButton(0, 0, 43, 10, 2, button"1"):setSound"Fax_1.wav" - self:addPanel(0, 272, 348):makeButton(0, 0, 44, 10, 3, button"2"):setSound"Fax_2.wav" - self:addPanel(0, 327, 348):makeButton(0, 0, 43, 10, 4, button"3"):setSound"Fax_3.wav" - - self:addPanel(0, 219, 358):makeButton(0, 0, 44, 10, 5, button"4"):setSound"Fax_4.wav" - self:addPanel(0, 272, 358):makeButton(0, 0, 43, 10, 6, button"5"):setSound"Fax_5.wav" - self:addPanel(0, 326, 358):makeButton(0, 0, 44, 10, 7, button"6"):setSound"Fax_6.wav" - - self:addPanel(0, 218, 370):makeButton(0, 0, 44, 11, 8, button"7"):setSound"Fax_7.wav" - self:addPanel(0, 271, 370):makeButton(0, 0, 44, 11, 9, button"8"):setSound"Fax_8.wav" - self:addPanel(0, 326, 370):makeButton(0, 0, 44, 11, 10, button"9"):setSound"Fax_9.wav" - - self:addPanel(0, 217, 382):makeButton(0, 0, 45, 12, 11, button"*") - self:addPanel(0, 271, 382):makeButton(0, 0, 44, 11, 12, button"0"):setSound"Fax_0.wav" - self:addPanel(0, 326, 382):makeButton(0, 0, 44, 11, 13, button"#") + self:addPanel(0, 220, 348):makeButton(0, 0, 43, 10, 2, button("1")):setSound("Fax_1.wav") + self:addPanel(0, 272, 348):makeButton(0, 0, 44, 10, 3, button("2")):setSound("Fax_2.wav") + self:addPanel(0, 327, 348):makeButton(0, 0, 43, 10, 4, button("3")):setSound("Fax_3.wav") + + self:addPanel(0, 219, 358):makeButton(0, 0, 44, 10, 5, button("4")):setSound("Fax_4.wav") + self:addPanel(0, 272, 358):makeButton(0, 0, 43, 10, 6, button("5")):setSound("Fax_5.wav") + self:addPanel(0, 326, 358):makeButton(0, 0, 44, 10, 7, button("6")):setSound("Fax_6.wav") + + self:addPanel(0, 218, 370):makeButton(0, 0, 44, 11, 8, button("7")):setSound("Fax_7.wav") + self:addPanel(0, 271, 370):makeButton(0, 0, 44, 11, 9, button("8")):setSound("Fax_8.wav") + self:addPanel(0, 326, 370):makeButton(0, 0, 44, 11, 10, button("9")):setSound("Fax_9.wav") + + self:addPanel(0, 217, 382):makeButton(0, 0, 45, 12, 11, button("*")) + self:addPanel(0, 271, 382):makeButton(0, 0, 44, 11, 12, button("0")):setSound("Fax_0.wav") + self:addPanel(0, 326, 382):makeButton(0, 0, 44, 11, 13, button("#")) end function UIFax:updateChoices() @@ -98,7 +100,7 @@ if self.message then local last_y = y + 40 - for i, message in ipairs(self.message) do + for _, message in ipairs(self.message) do last_y = self.fax_font:drawWrapped(canvas, message.text, x + 190, last_y + (message.offset or 0), 330, "center") @@ -107,7 +109,7 @@ if choices then local orig_y = y + 190 for i = 1, #choices do - local last_y = orig_y + ((i-1) + (3-#choices)) * 48 + last_y = orig_y + ((i - 1) + (3 - #choices)) * 48 self.fax_font:drawWrapped(canvas, choices[i].text, x + 190, last_y + (choices[i].offset or 0), 300) end @@ -115,14 +117,26 @@ end end -function UIFax:choice(choice,additionalInfo) +--A choice was made for the fax. +--!param choice_number (integer) Number of the choice +function UIFax:choice(choice_number) + local choices = self.message.choices + local choice, additionalInfo + if choices and choice_number >= 1 and choice_number <= #choices then + choice = choices[choice_number].choice + additionalInfo = choices[choice_number].additionalInfo + else + choice = "disabled" + additionalInfo = nil + end + local owner = self.owner if owner then -- A choice was made, the patient is no longer waiting for a decision owner:setMood("patient_wait", "deactivate") owner.message_callback = nil if choice == "send_home" then - owner:goHome() + owner:goHome("kicked") if owner.diagnosed then -- No treatment rooms owner:updateDynamicInfo(_S.dynamic_info.patient.actions.no_treatment_available) @@ -141,20 +155,18 @@ owner:updateDynamicInfo(_S.dynamic_info.patient.actions.waiting_for_diagnosis_rooms) end elseif choice == "guess_cure" then - owner:setDiagnosed(true) - owner:setNextAction{ - name = "seek_room", - room_type = owner.disease.treatment_rooms[1], - treatment_room = true, - } + owner:setDiagnosed() + if owner:agreesToPay(owner.disease.id) then + owner:setNextAction(SeekRoomAction(owner.disease.treatment_rooms[1]):enableTreatmentRoom()) + else + owner:goHome("over_priced", owner.disease.id) + end elseif choice == "research" then owner:setMood("idea", "activate") - owner:setNextAction { - name = "seek_room", - room_type = "research", - } + owner:setNextAction(SeekRoomAction("research")) end end + local vip_ignores_refusal = math.random(1, 2) if choice == "accept_emergency" then self.ui.app.world:newObject("helicopter", self.ui.hospital, "north") self.ui:addWindow(UIWatch(self.ui, "emergency")) @@ -162,18 +174,44 @@ self.ui.adviser:say(_A.information.emergency) elseif choice == "refuse_emergency" then self.ui.app.world:nextEmergency() - elseif choice == "accept_vip" then - self.ui.hospital.num_vips = self.ui.hospital.num_vips+1 + -- VIP may choose to visit anyway if he is refused too often + elseif (self.ui.hospital.vip_declined > 2 and vip_ignores_refusal == 2) and choice == "refuse_vip" then + self.ui.hospital.num_vips = self.ui.hospital.num_vips + 1 self.ui.app.world:spawnVIP(additionalInfo.name) + self.ui.hospital.vip_declined = 0 elseif choice == "refuse_vip" then self.ui.app.world:nextVip() -- don't start an inspection + self.ui.hospital.vip_declined = self.ui.hospital.vip_declined + 1 + elseif choice == "accept_vip" then + self.ui.hospital.num_vips = self.ui.hospital.num_vips + 1 + self.ui.app.world:spawnVIP(additionalInfo.name) + elseif choice == "declare_epidemic" then + local epidemic = self.ui.hospital.epidemic + if epidemic then + epidemic:resolveDeclaration() + end + elseif choice == "cover_up_epidemic" then + local epidemic = self.ui.hospital.epidemic + if epidemic then + epidemic:startCoverUp() + end elseif choice == "accept_new_level" then -- Set the new salary. self.ui.hospital.player_salary = self.ui.hospital.salary_offer if tonumber(self.ui.app.world.map.level_number) then self.ui.app:loadLevel(self.ui.app.world.map.level_number + 1, self.ui.app.map.difficulty) else - -- TODO: Allow some kind of custom campaign with custom levels + for i, level in ipairs(self.ui.app.world.campaign_info.levels) do + if self.ui.app.world.map.level_number == level then + local next_level = self.ui.app.world.campaign_info.levels[i + 1] + local level_info, _ = self.ui.app:readLevelFile(next_level) + if level_info then + self.ui.app:loadLevel(next_level, nil, level_info.name, + level_info.map_file, level_info.briefing) + break + end + end + end end elseif choice == "return_to_main_menu" then self.ui.app.moviePlayer:playWinMovie() diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/graphs.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/graphs.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/graphs.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/graphs.lua 2018-07-21 11:13:17.000000000 +0000 @@ -22,7 +22,10 @@ --! Charts fullscreen window class "UIGraphs" (UIFullscreen) -local TH = require "TH" +---@type UIGraphs +local UIGraphs = _G["UIGraphs"] + +local TH = require("TH") -- These values are based on the background colours of the pen symbols local colours = { @@ -52,8 +55,7 @@ return end - local hosp = ui.hospital - self.hospital = hosp + self.hospital = ui.hospital -- Buttons self:addPanel(0, 63, 384):makeButton(0, 0, 26, 26, 3, self.close):setTooltip(_S.tooltip.graphs.close) @@ -88,98 +90,268 @@ self:updateLines() end -function UIGraphs:updateLines() +local TOP_Y = 85 -- Top of the graph area +local BOTTOM_Y = 353 -- Bottom of the graph area +local RIGHT_X = 346 -- Right side of the graph area +local VERT_DX = 25 -- Spacing between the vertical lines in the graph +local VERT_COUNT = 12 -- Number of vertical lines in the graph +local GRAPH_HEIGHT = BOTTOM_Y - TOP_Y + +--! Compute the vertical position of a value in the graph given the line extremes +--!param graph_line (table) Meta data of the line, including extreme values. +--!param value (number) Value to position vertically in the graph. +--!return Y position in the graph of the value. +local function computeVerticalValuePosition(graph_line, value) + -- 0 is always included in the range. + assert(graph_line.maximum >= 0 and graph_line.minimum <= 0) + local range = graph_line.maximum - graph_line.minimum + if range == 0 then return BOTTOM_Y end - local statistics = self.hospital.statistics - -- Make one line for each graph - local lines = {} - for stat, _ in pairs(statistics[1]) do - local line = TH.line() - line:setWidth(2) - local hue = colours[stat] - line:setColour(hue[1], hue[2], hue[3], 255) - lines[stat] = {line = line, maximum = 0, minimum = 0} + return BOTTOM_Y - math.floor(((value - graph_line.minimum) / range) * GRAPH_HEIGHT) +end + +--! Convert graph scale to a stepsize in months. +--!param graph_scale (int, 1 to 3) Graph scale to display. +--!return Number of months to jump between statistics values in the hospital statistics data. +local function getStatisticsStepsize(graph_scale) + local stepsize = 4 * 12 -- Four years + if graph_scale == 2 then + stepsize = 12 -- One year + elseif graph_scale == 3 then + stepsize = 1 -- A month end - self.lines = lines + return stepsize +end + +--! Get the statistics from the hospital that should be displayed. +--! Selection starts at the last (=newest) entry, and goes back in time. +--!return The values of all statistics to plot in the graph display. +function UIGraphs:getHospitalStatistics() + local statistics = self.hospital.statistics - -- Pick the relevant values starting from the end of the statistics table local values = {} - local decrements = -4 * 12 -- Four years - if self.graph_scale == 2 then - decrements = -12 -- One year - elseif self.graph_scale == 3 then - decrements = -1 -- A month - end - for i = #statistics, #statistics + decrements*11, decrements do - if i < 1 then - break - end + local i = #statistics -- Picking hospital statistics from right to left (recent to old). + local stats_stepsize = getStatisticsStepsize(self.graph_scale) + while #values < VERT_COUNT and i >= 1 do values[#values + 1] = statistics[i] + i = i - stats_stepsize end - self.values = values + return values +end - -- Decide maximum and minimum for normalisation of each line - for _, part in ipairs(values) do - if type(part) == "table" then - for stat, value in pairs(part) do - if value < lines[stat].minimum then - lines[stat].minimum = value - end - if value > lines[stat].maximum then - lines[stat].maximum = value +--! Reposition the given sequence of text entries vertically such that the maximum +-- absolute deviation from the ideal position is minimized. +--!param label_datas (array) Text entries +--!param start_index (int) First entry to move. +--!param last_index (int) Last entry to move. +local function moveSequence(label_datas, start_index, last_index) + -- min_y, max_y Smallest and biggest vertical position of the labels. Since + -- they are sorted on y, it's the position of the first and last visible entry. + -- min_y_shift, max_y_shift Vertical movement of the label of the first and + -- last visible entry for vertically centering the text. + -- min_dev, max_dev Smallest and biggest deviation from the optimal position, + -- for all visible labels. + local min_y = nil + local max_y, min_y_shift, max_y_shift, min_dev, max_dev + for i = start_index, last_index do + local label = label_datas[i] + if label.pos_y then -- Label is visible + local deviation = label.pos_y - label.ideal_y -- Positive if moved down + if min_y then -- Updating the max y, and deviations + max_y = label.pos_y + max_y_shift = label.shift_y + min_dev = math.min(min_dev, deviation) + max_dev = math.max(max_dev, deviation) + else -- First time entering the loop + min_y = label.pos_y + max_y = label.pos_y + min_y_shift = label.shift_y + max_y_shift = label.shift_y + min_dev = deviation + max_dev = deviation + end + end + end + + -- There should be at least one visible entry in the provided range. + assert(min_y ~= nil) + + local move = -math.floor((max_dev + min_dev) / 2) -- Suggested movement of the sequence. + + -- Verify the sequence will stay inside graph upper and lower limits, adjust otherwise. + if min_y + min_y_shift + move < TOP_Y then + move = TOP_Y - min_y - min_y_shift + elseif max_y + max_y_shift + move > BOTTOM_Y then + move = BOTTOM_Y - max_y - max_y_shift + end + + -- And update the positions. + for i = start_index, last_index do + local label = label_datas[i] + if label.pos_y then label.pos_y = label.pos_y + move end + end +end + +--! Compute new actual position of the labels. +--!param graph (UIGraphs) Graph window object +local function updateTextPositions(graph) + -- Reset vertical position of the text back to its ideal position. + -- Disable computations on invisible graphs by removing the actual y position of it. + for _, label in ipairs(graph.label_datas) do + if graph.hide_graph[label.stat] then + label.pos_y = nil + else + label.pos_y = label.ideal_y + end + end + + -- Move labels of the graphs such that they stay at the right of the graph + -- between their upper and lower boundaries. + local sequence_moved = true + local collision_count = 8 -- In theory the loop should terminate, but better safe than sorry. + while sequence_moved and collision_count > 0 do + collision_count = collision_count - 1 + sequence_moved = false + + -- Find sequences of text entries that partly overlap or have no vertical + -- space between them. Entries in such a sequence cannot be moved + -- individually, the sequence as a whole must move. + local start_index, last_index = nil, nil -- Start and end of the sequence. + local collision = false -- True collision detected in the sequence + local prev_index, prev_label = nil, nil + for i, label in ipairs(graph.label_datas) do + if label.pos_y then -- Label is visible + if prev_label then + -- Bottom y of previous label, top of current label + local bottom_prev = prev_label.pos_y + prev_label.shift_y + prev_label.size_y + local top_current = label.pos_y + label.shift_y + + if top_current < bottom_prev then + -- True collision, text has to move + collision = true + sequence_moved = true + label.pos_y = bottom_prev - label.shift_y + if not start_index then start_index = prev_index end + last_index = i + + elseif top_current == bottom_prev then + -- Entry is concatenated to the sequence, position is fine. + if not start_index then start_index = prev_index end + last_index = i + else + -- Entry is not part of the sequence, move previous sequence to its + -- optimal spot if required + if collision then + moveSequence(graph.label_datas, start_index, last_index) + end + + collision = false + start_index = nil + last_index = nil + -- Do not consider the current text in this round. The next entry may + -- see it as the start of a next sequence. + end end + prev_label = label + prev_index = i + end + end + + if collision then + moveSequence(graph.label_datas, start_index, last_index) + end + end +end + +function UIGraphs:updateLines() + self.values = self:getHospitalStatistics() + + -- Construct meta data about each graph line. + local graph_datas = {} -- Table ordered by statistics name. + self.graph_datas = graph_datas + for stat, _ in pairs(self.values[1]) do + graph_datas[stat] = {line = nil, maximum = 0, minimum = 0} + end + + -- Decide maximum and minimum for normalisation of each line. + -- 0 is always included in the computed range. + for _, stats in ipairs(self.values) do + for stat, value in pairs(stats) do + if value < graph_datas[stat].minimum then + graph_datas[stat].minimum = value + end + if value > graph_datas[stat].maximum then + graph_datas[stat].maximum = value end end end - -- Start from the right part of the graph window - local top_y = 85 - local bottom_y = 353 - local first_x = 346 - local dx = -25 - local text = {} - - -- First start at the correct place - local part = values[1] - for stat, value in pairs(part) do - -- The zero point may not be at the bottom of the graph for e.g. balance when it has been negative - local zero_point = lines[stat].minimum < 0 and lines[stat].minimum*(bottom_y-top_y)/(lines[stat].maximum - lines[stat].minimum) or 0 - local normalized_value = value == 0 and 0 or value*(bottom_y-top_y)/(lines[stat].maximum - lines[stat].minimum) - -- Save the starting point for text drawing purposes. - local start = top_y + (bottom_y - top_y) - normalized_value + zero_point - text[#text + 1] = {stat = stat, start_y = start, value = value} - lines[stat].line:moveTo(first_x, start) + -- Add the line objects of the graph. + for stat, graph_data in pairs(self.graph_datas) do + local line = TH.line() + line:setWidth(2) + local hue = colours[stat] + line:setColour(hue[1], hue[2], hue[3], 255) + graph_data.line = line end - -- Sort the y positions where to put text to draw the top text first. - local function compare(a,b) - return a.start_y < b.start_y + -- Add the graph line pieces. Doing this separately is more efficient as all + -- graph lines can be extended to the left in the same iteration. + local xpos = RIGHT_X + for i, stats in ipairs(self.values) do + for stat, value in pairs(stats) do + local line = graph_datas[stat].line + local ypos = computeVerticalValuePosition(graph_datas[stat], value) + if i == 1 then + line:moveTo(xpos, ypos) + else + line:lineTo(xpos, ypos) + end + end + xpos = xpos - VERT_DX end - table.sort(text, compare) - self.text_positions = text + -- Compute label data for each statistic, and order by vertical position. + -- The newest statistic values are displayed at the right edge of the graph, + -- which decides the optimal position of the graph label text and value. + local label_datas = {} + self.label_datas = label_datas + + for stat, value in pairs(self.values[1]) do + local ideal_y = computeVerticalValuePosition(graph_datas[stat], value) + local text = _S.graphs[stat] .. ":" + local _, size_y, _ = self.black_font:sizeOf(text) + label_datas[#label_datas + 1] = { + stat = stat, -- Name of the statistic it belongs to. + text = text, -- Translated label text. + ideal_y = ideal_y, -- Ideal vertical position. + pos_y = nil, -- Actual position for drawing. + size_y = size_y, -- Vertical size of the text. + shift_y = -math.floor(size_y / 2), -- Amount of shift to center the text. + value = value} -- Numeric value to display. + end + -- Sort the labels of the graph on ideal y position, and compute actual position. + local function compare(a,b) + return a.ideal_y < b.ideal_y + end + table.sort(label_datas, compare) + updateTextPositions(self) + + -- Create small lines going from the number of month name to the actual graph. + -- Like the lines, index runs from right to left at the screen. local aux_lines = {} - -- Then add all the nodes available for each graph - for i, part in ipairs(values) do - for stat, value in pairs(part) do - -- The zero point may not be at the bottom of the graph for e.g. balance when it has been negative - local zero_point = lines[stat].minimum < 0 and lines[stat].minimum*(bottom_y-top_y)/(lines[stat].maximum - lines[stat].minimum) or 0 - local normalized_value = value == 0 and 0 or value*(bottom_y-top_y)/(lines[stat].maximum - lines[stat].minimum) - lines[stat].line:lineTo(first_x, top_y + (bottom_y - top_y) - normalized_value + zero_point) - end - -- Also add a small line going from the number of month name to the actual graph. + self.aux_lines = aux_lines + + xpos = RIGHT_X + for _ = 1, #self.values do local line = TH.line() line:setWidth(1) - --local hue = colours[stat] - --line:setColour(hue[1], hue[2], hue[3], 255) - line:moveTo(first_x, bottom_y + 2) - line:lineTo(first_x, bottom_y + 8) + line:moveTo(xpos, BOTTOM_Y + 2) + line:lineTo(xpos, BOTTOM_Y + 8) aux_lines[#aux_lines + 1] = line - first_x = first_x + dx + xpos = xpos - VERT_DX end - self.aux_lines = aux_lines - end function UIGraphs:draw(canvas, x, y) @@ -197,49 +369,50 @@ self.white_font:draw(canvas, _S.graphs.reputation, x + 502, y + 405, 80, 27) -- Draw the different lines - for stat, values in pairs(self.lines) do + for stat, graph in pairs(self.graph_datas) do if not self.hide_graph[stat] then - values.line:draw(canvas, x, y) + graph.line:draw(canvas, x, y) end end - local first_x = 334 - -- Draw strings showing what values each entry has at the moment just to the right of the graph. -- TODO: These should be coloured according to the colour of the corresponding line. - local cur_y = 85 - for _, values in pairs(self.text_positions) do - if not self.hide_graph[values.stat] then - -- -5 makes the text appear just to the right of the line instead of just beneath it. - cur_y = (cur_y > values.start_y and cur_y or values.start_y - 5) - -- The last y compensates that draw returns the last y position relative to the top of the window, not the dialog. - -- To get all values in the same "column", draw them separately. - self.black_font:draw(canvas, _S.graphs[values.stat] .. ":", x + first_x + 15, y + cur_y) - cur_y = self.black_font:draw(canvas, values.value, x + first_x + 72, y + cur_y) - y + for _, label in pairs(self.label_datas) do + if label.pos_y then + local ypos = label.pos_y + label.shift_y + self.black_font:draw(canvas, label.text, x + RIGHT_X + 3, y + ypos) + self.black_font:draw(canvas, label.value, x + RIGHT_X + 60, y + ypos) end end - - local dx = -25 - local number = math.floor(#self.hospital.statistics / 12) - - local decrements = -4 -- Four years - if self.graph_scale == 2 then - decrements = -1 -- One year - elseif self.graph_scale == 3 then - decrements = -1 -- A month - number = #self.hospital.statistics - number * 12 - end - local no = 1 + local stats_stepsize = getStatisticsStepsize(self.graph_scale) + local xpos = x + RIGHT_X -- Draw numbers (or month names) below the graph - for _, _ in ipairs(self.values) do - self.black_font:drawWrapped(canvas, self.graph_scale == 3 and _S.months[(number - 1) % 12 + 1] or number, x + first_x, y + 363, 25, "center") - first_x = first_x + dx - number = number + decrements - -- And the small black line - self.aux_lines[no]:draw(canvas, x, y) - no = no + 1 + assert(#self.hospital.statistics > 0) -- Avoid negative months and years. + if stats_stepsize >= 12 then + -- Display years + local year_number = math.floor((#self.hospital.statistics - 1) / 12) + for i = 1, #self.values do + self.black_font:drawWrapped(canvas, year_number, xpos, y + BOTTOM_Y + 10, 25, "center") + xpos = xpos - VERT_DX + year_number = year_number - math.floor(stats_stepsize / 12) + + -- And the small black line + self.aux_lines[i]:draw(canvas, x, y) + end + else + -- Display months + local month_number = #self.hospital.statistics - math.floor((#self.hospital.statistics - 1) / 12) * 12 + for i = 1, #self.values do + self.black_font:drawWrapped(canvas, _S.months[month_number], xpos, y + BOTTOM_Y + 10, 25, "center") + xpos = xpos - VERT_DX + month_number = month_number - stats_stepsize + if month_number < 1 then month_number = month_number + 12 end + + -- And the small black line + self.aux_lines[i]:draw(canvas, x, y) + end end end @@ -253,6 +426,7 @@ function UIGraphs:toggleGraph(name) self.hide_graph[name] = not self.hide_graph[name] self.ui:playSound("selectx.wav") + updateTextPositions(self) end function UIGraphs:close() @@ -261,7 +435,7 @@ end function UIGraphs:afterLoad(old, new) - if old < 60 then + if old < 117 then self:close() end end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/hospital_policy.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/hospital_policy.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/hospital_policy.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/hospital_policy.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Hospital policy fullscreen window (set staff tiredness and patient cure thresholds, etc.). class "UIPolicy" (UIFullscreen) +---@type UIPolicy +local UIPolicy = _G["UIPolicy"] + function UIPolicy:UIPolicy(ui, disease_selection) self:UIFullscreen(ui) local gfx = ui.app.gfx @@ -59,9 +62,16 @@ end -- Buttons - self:addPanel(0, 607, 447):makeButton(0, 0, 26, 26, 6, self.close):setTooltip(_S.tooltip.policy.close) - self.allow_button = self:addPanel(0, 348, 379):makeToggleButton(0, 0, 48, 17, 4, allowStaff, "Allow"):setTooltip(_S.tooltip.policy.staff_leave) -- Allow staff to move - self.prohibit_button = self:addPanel(0, 395, 379):makeToggleButton(0, 0, 48, 17, 5, allowStaff, "Prohibit"):setTooltip(_S.tooltip.policy.staff_stay) -- Prohibit staff to move + self:addPanel(0, 607, 447):makeButton(0, 0, 26, 26, 6, self.close) + :setTooltip(_S.tooltip.policy.close) + + self.allow_button = self:addPanel(0, 348, 379) + :makeToggleButton(0, 0, 48, 17, 4, allowStaff, "Allow") + :setTooltip(_S.tooltip.policy.staff_leave) -- Allow staff to move + + self.prohibit_button = self:addPanel(0, 395, 379) + :makeToggleButton(0, 0, 48, 17, 5, allowStaff, "Prohibit") + :setTooltip(_S.tooltip.policy.staff_stay) -- Prohibit staff to move if self.hospital.policies["staff_allowed_to_move"] then self.allow_button:toggle() @@ -70,10 +80,10 @@ end -- Slider positions - local guess = 129 + hosp.policies["guess_cure"]*299 - local home = 129 + hosp.policies["send_home"]*299 - local stop = 124 + (hosp.policies["stop_procedure"] - 1)*299 - local staffroom = 149 + hosp.policies["goto_staffroom"]*250 + local guess = 129 + math.floor(hosp.policies["guess_cure"] * 299) + local home = 129 + math.floor(hosp.policies["send_home"] * 299) + local stop = 124 + math.floor((hosp.policies["stop_procedure"] - 1) * 299) + local staffroom = 149 + math.floor(hosp.policies["goto_staffroom"] * 250) -- Sliders self.sliders = {} @@ -81,9 +91,9 @@ self.sliders["send_home"] = self:addPanel(1, home, 135, 82, 28) self.sliders["stop_procedure"] = self:addPanel(3, stop, 210, 92, 28) self.sliders["goto_staffroom"] = self:addPanel(3, staffroom, 285, 92, 28) + self.sliders["guess_cure"].min_x = home - self.sliders["guess_cure"].total_min_x = 129 -- Needed to get the correct value set when - -- windows is closed. + self.sliders["guess_cure"].total_min_x = 129 -- Needed to get the correct value set when windows is closed. self.sliders["guess_cure"].max_x = 428 self.sliders["send_home"].min_x = 129 self.sliders["send_home"].max_x = guess @@ -94,6 +104,13 @@ self.sliders["goto_staffroom"].min_x = 149 self.sliders["goto_staffroom"].max_x = 399 + -- Z order of the sliders. + -- The small 'send_home' slider must be tested first in 'self:panelHit', + -- to ensure it can always be moved, even if the big 'guess_cure' is at the + -- same position. + self.sliders_z = {self.sliders["send_home"], self.sliders["guess_cure"], + self.sliders["stop_procedure"], self.sliders["goto_staffroom"]} + -- Tooltips for slider bars self:makeTooltip(_S.tooltip.policy.diag_procedure, 161, 119, 479, 174) self:makeTooltip(_S.tooltip.policy.diag_termination, 161, 210, 479, 249) @@ -109,13 +126,20 @@ local label = self.label_font -- Labels on the panels - local added_x, added_y = self.sliders["send_home"].x, self.sliders["send_home"].y + local added_x = self.sliders["send_home"].x + local added_y = self.sliders["send_home"].y label:draw(canvas, _S.policy.sliders.send_home, x + added_x, y + added_y + 2, 82, 0) - added_x, added_y = self.sliders["guess_cure"].x, self.sliders["guess_cure"].y + + added_x = self.sliders["guess_cure"].x + added_y = self.sliders["guess_cure"].y label:draw(canvas, _S.policy.sliders.guess, x + added_x, y + added_y + 2, 82, 0) - added_x, added_y = self.sliders["stop_procedure"].x, self.sliders["stop_procedure"].y + + added_x = self.sliders["stop_procedure"].x + added_y = self.sliders["stop_procedure"].y label:draw(canvas, _S.policy.sliders.stop, x + added_x, y + added_y + 2, 92, 0) - added_x, added_y = self.sliders["goto_staffroom"].x, self.sliders["goto_staffroom"].y + + added_x = self.sliders["goto_staffroom"].x + added_y = self.sliders["goto_staffroom"].y label:draw(canvas, _S.policy.sliders.staff_room, x + added_x, y + added_y + 2, 92, 0) -- All other text @@ -124,7 +148,6 @@ text:draw(canvas, _S.policy.diag_termination, x + 161, y + 181) text:draw(canvas, _S.policy.staff_rest, x + 161, y + 262) text:draw(canvas, _S.policy.staff_leave_rooms, x + 161, y + 374) - end function UIPolicy:onMouseMove(x, y, dx, dy) @@ -176,15 +199,22 @@ return UIFullscreen.onMouseUp(self, code, x, y) end +--! Detect which slider is clicked by the mouse. +--!param x (int) X position of the mouse. +--!param y (int) Y position of the mouse. +--!return Slider that was detected at the given position, or nil function UIPolicy:panelHit(x, y) - for name, panel in pairs(self.sliders) do + for _, panel in ipairs(self.sliders_z) do if x > panel.x and y > panel.y and x < panel.x + panel.w and y < panel.y + panel.h then return panel end end + return nil end +--! Close the window. function UIPolicy:close() + -- Save new slider positions in the hospital policies again for the next use. for key, s in pairs(self.sliders or {}) do local divider = (s.total_max_x or s.max_x) - (s.total_min_x or s.min_x) local number = (s.addition and 1 or 0) @@ -194,3 +224,11 @@ self.ui:getWindow(UIBottomPanel):updateButtonStates() end +function UIPolicy:afterLoad(old, new) + UIFullscreen.afterLoad(self, old, new) + + if old < 116 then -- Ensure panelHit tests the sliders in the right order. + self.sliders_z = {self.sliders["send_home"], self.sliders["guess_cure"], + self.sliders["stop_procedure"], self.sliders["goto_staffroom"]} + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/progress_report.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/progress_report.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/progress_report.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/progress_report.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,11 +18,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" - --! Progress Report fullscreen window (check level goals, competitors and alerts). class "UIProgressReport" (UIFullscreen) +---@type UIProgressReport +local UIProgressReport = _G["UIProgressReport"] + function UIProgressReport:UIProgressReport(ui) -- TODO: Refactor this file! self:UIFullscreen(ui) @@ -54,7 +55,7 @@ -- Add the icons for the criteria local x = 263 local world_goals = world.goals - for i, tab in ipairs(world_goals) do + for _, tab in ipairs(world_goals) do local crit_name = world.level_criteria[tab.criterion].name local res_value = world_goals[crit_name].win_value world_goals[crit_name].visible = true @@ -86,9 +87,9 @@ if res_value then local tooltip if world.level_criteria[tab.criterion].formats == 2 then - tooltip = _S.tooltip.status[crit_name]:format(res_value, cur_value) + tooltip = _S.tooltip.status[crit_name]:format(math.floor(res_value), math.floor(cur_value)) else - tooltip = _S.tooltip.status[crit_name]:format(res_value) + tooltip = _S.tooltip.status[crit_name]:format(math.floor(res_value)) end self:addPanel(world.level_criteria[tab.criterion].icon, x, 240) self:makeTooltip(tooltip, x, 180, x + 30, 180 + 90) @@ -138,16 +139,16 @@ local x_min = 455 local x_max = 551 local width = x_max - x_min - local happiness = self.ui.hospital:getAveragePatientAttribute("happiness") - local thirst = 1 - self.ui.hospital:getAveragePatientAttribute("thirst") - local warmth = self.ui.hospital:getAveragePatientAttribute("warmth") - local world = self.ui.app.world - + local happiness = self.ui.hospital:getAveragePatientAttribute("happiness", 0.5) + local thirst = 1 - self.ui.hospital:getAveragePatientAttribute("thirst", 0.5) + local warmth = self.ui.hospital:getAveragePatientAttribute("warmth", nil) warmth = UIPatient.normaliseWarmth(warmth) - self.panel_sprites:draw(canvas, 5, x + x_min + width * happiness, y + 193) - self.panel_sprites:draw(canvas, 5, x + x_min + width * thirst, y + 223) - self.panel_sprites:draw(canvas, 5, x + x_min + width * warmth, y + 254) + self.panel_sprites:draw(canvas, 5, math.floor(x + x_min + width * happiness), y + 193) + self.panel_sprites:draw(canvas, 5, math.floor(x + x_min + width * thirst), y + 223) + self.panel_sprites:draw(canvas, 5, math.floor(x + x_min + width * warmth), y + 254) + + local world = self.ui.app.world if world.free_build_mode then self.normal_font:drawWrapped(canvas, _S.progress_report.free_build, x + 265, y + 194, 150, "center") end @@ -181,7 +182,6 @@ UIFullscreen.draw(self, canvas, x, y) x, y = self.x + x, self.y + y - local app = self.ui.app local hospital = self.ui.hospital local world = hospital.world local world_goals = world.goals @@ -196,7 +196,7 @@ -- Draw the vertical bars for the winning conditions local lx = 270 - for i, tab in ipairs(world_goals) do + for _, tab in ipairs(world_goals) do local crit_name = world.level_criteria[tab.criterion].name if world_goals[crit_name].visible then local sprite_offset = world_goals[crit_name].red and 2 or 0 @@ -208,9 +208,9 @@ local height if world_goals[crit_name].red then local lose = world_goals[crit_name].lose_value - height = 1 + 49*(1 - ((cur_value - lose)/(world_goals[crit_name].boundary - lose))) + height = 1 + 49 * (1 - ((cur_value - lose)/(world_goals[crit_name].boundary - lose))) else - height = 1 + 49*(cur_value/world_goals[crit_name].win_value) + height = 1 + 49 * (cur_value/world_goals[crit_name].win_value) end if height > 50 then height = 50 end local result_y = 0 @@ -225,9 +225,9 @@ self:drawMarkers(canvas, x, y) - self.normal_font:draw(canvas, _S.progress_report.header .. " " - .. (world.year + 1999), x + 227, y + 40, 400, 0) + self.normal_font:draw(canvas, _S.progress_report.header .. " " .. + (world:date():year() + 1999), x + 227, y + 40, 400, 0) self.small_font:draw(canvas, _S.progress_report.win_criteria:upper(), x + 263, y + 172) - self.small_font:draw(canvas, _S.progress_report.percentage_pop:upper() .. " " - .. (hospital.population*100) .. "%", x + 450, y + 65) + self.small_font:draw(canvas, _S.progress_report.percentage_pop:upper() .. " " .. + (hospital.population * 100) .. "%", x + 450, y + 65) end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/research_policy.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/research_policy.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/research_policy.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/research_policy.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,6 +20,9 @@ class "UIResearch" (UIFullscreen) +---@type UIResearch +local UIResearch = _G["UIResearch"] + local research_categories = { "cure", "diagnosis", @@ -71,11 +74,10 @@ -- Add tooltips to progress of research. local lx = 165 local ly = 60 - for i, category in ipairs(research_categories) do + for _, category in ipairs(research_categories) do self:makeDynamicTooltip(--[[persistable:research_policy_research_progress_tooltip]] function() local research = self.research.research_policy - if research[category].current - and not research[category].current.dummy then + if research[category].current and not research[category].current.dummy then local required = self.research:getResearchRequired(research[category].current) local available = self.research.research_progress[research[category].current].points return _S.tooltip.research_policy.research_progress:format(math.round(available), required) @@ -96,8 +98,8 @@ local c2 = 450 local function handler_factory(area, mode) - return --[[persistable:research_policy_adjust_handler]] function(self) - self:adjustResearch(area, mode) + return --[[persistable:research_policy_adjust_handler]] function(window) + window:adjustResearch(area, mode) end end @@ -107,7 +109,7 @@ ]] local function get_localized_string(string_name) local var_table = _G["_S"] - for token in string.gfind(string_name, "[%w_]+") do + for token in string.gmatch(string_name, "[%w_]+") do var_table = var_table[token] end return var_table @@ -117,15 +119,19 @@ local current = self.hospital.research.research_policy[area].current if current then self.adjust_buttons[area] = { - less = self:addPanel(0, c1, topy+i*spacing):makeRepeatButton(0, 0, size, size, 1, handler_factory(area, "less")):setTooltip(get_localized_string("tooltip.research." .. area .. "_dec")), - more = self:addPanel(0, c2, topy+i*spacing):makeRepeatButton(0, 0, size, size, 2, handler_factory(area, "more")):setTooltip(get_localized_string("tooltip.research." .. area .. "_inc")), + less = self:addPanel(0, c1, topy + i * spacing) + :makeRepeatButton(0, 0, size, size, 1, handler_factory(area, "less")) + :setTooltip(get_localized_string("tooltip.research." .. area .. "_dec")), + more = self:addPanel(0, c2, topy + i * spacing) + :makeRepeatButton(0, 0, size, size, 2, handler_factory(area, "more")) + :setTooltip(get_localized_string("tooltip.research." .. area .. "_inc")), } else if self.adjust_buttons[area] then self.adjust_buttons[area].less.enabled = false self.adjust_buttons[area].more.enabled = false end - self:addColourPanel(c1, topy+i*spacing, 120, 30, col_bg.red, col_bg.green, col_bg.blue) + self:addColourPanel(c1, topy + i * spacing, 120, 30, col_bg.red, col_bg.green, col_bg.blue) end end end @@ -133,9 +139,9 @@ function UIResearch:adjustResearch(area, mode) local res = self.research local amount = 1 - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then amount = amount * 20 - elseif self.buttons_down.shift then + elseif self.ui.app.key_modifiers.shift then amount = amount * 5 end if mode == "less" then @@ -198,25 +204,23 @@ local ytop = 28 local spacing = 41 - local config = self.hospital.world.map.level_config local research = self.research.research_policy for i, category in ipairs(research_categories) do - local y = y + ytop + i * spacing - lbl_font:draw(canvas, _S.research.categories[category], x + 170, y) + local ypos = y + ytop + i * spacing + lbl_font:draw(canvas, _S.research.categories[category], x + 170, ypos) if not research[category].current then - num_font:draw(canvas, _S.misc.done, x + 270, y, 300, 0) + num_font:draw(canvas, _S.misc.done, x + 270, ypos, 300, 0) else - num_font:draw(canvas, research[category].frac, x + 270, y, 300, 0) + num_font:draw(canvas, research[category].frac, x + 270, ypos, 300, 0) end -- Display research progress. - if research[category].current - and not research[category].current.dummy then - local ly = y + 26 + if research[category].current and not research[category].current.dummy then + local ly = ypos + 26 local lx = x + 172 local required = self.research:getResearchRequired(research[category].current) local available = self.research.research_progress[research[category].current].points - local length = 290*available/required + local length = 290 * available / required local dx = 0 while dx + 10 < length do self.panel_sprites:draw(canvas, 3, lx + dx, ly) @@ -239,8 +243,8 @@ self.adjust_buttons = {} for i, area in ipairs(research_categories) do self.adjust_buttons[area] = { - less = self.buttons[2*i], - more = self.buttons[2*i+1], + less = self.buttons[2 * i], + more = self.buttons[2 * i + 1], } end end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/staff_management.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/staff_management.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/staff_management.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/staff_management.lua 2018-07-21 11:13:17.000000000 +0000 @@ -23,7 +23,10 @@ --! Staff management screen class "UIStaffManagement" (UIFullscreen) -function UIStaffManagement:UIStaffManagement(ui, disease_selection) +---@type UIStaffManagement +local UIStaffManagement = _G["UIStaffManagement"] + +function UIStaffManagement:UIStaffManagement(ui) self:UIFullscreen(ui) local gfx = ui.app.gfx if not pcall(function() @@ -93,7 +96,6 @@ -- Blankers for each row local row_blankers = {} - local i for i = 1, 10 do row_blankers[i] = self:addColourPanel(50, 55 + i*27, 580, 27, 60, 174, 203) end @@ -130,6 +132,12 @@ self:makeTooltip(_S.tooltip.staff_list.skills, 146, 406, 186, 460) self:setCategory("Doctor") + + -- Hotkeys. + self:addKeyHandler("left", self.previousCategory) + self:addKeyHandler("right", self.nextCategory) + self:addKeyHandler("up", self.previousStaff) + self:addKeyHandler("down", self.nextStaff) end function UIStaffManagement:updateTooltips() @@ -174,6 +182,11 @@ self.staff_members = staff_members if staff_member_removed then self:updateTooltips() + -- If we're viewing a page that no longer exists, go back a page + if self.page > math.ceil(#self.staff_members[self.category] / 10) then + self:scrollUp() + end + self:updateScrollDotVisibility() end end @@ -182,7 +195,7 @@ self.skill_blanker.visible = name ~= "Doctor" self.title_blanker.visible = name ~= "Doctor" self.category = name - for i, btn in ipairs(self.categories) do + for _, btn in ipairs(self.categories) do local should_be_toggled = btn.on_click_self == name if btn.toggled ~= should_be_toggled then btn:toggle() @@ -190,12 +203,7 @@ end self.selected_staff = nil self.page = 1 - if #self.staff_members[self.category] > 10 then - self.scroll_dot.visible = true - self.scroll_dot.y = 168 - else - self.scroll_dot.visible = false - end + self:updateScrollDotVisibility() self:updateTooltips() end @@ -203,6 +211,9 @@ -- Function to select given list index in the current category. -- Includes jumping to correct page. function UIStaffManagement:selectIndex(idx) + if idx > #self.staff_members[self.category] or idx <= 0 then + return + end self.page = math.floor((idx - 1) / 10) + 1 self.selected_staff = idx end @@ -419,14 +430,13 @@ return UIFullscreen.onMouseDown(self, code, x, y) end -function UIStaffManagement:onMouseUp(code, x, y) - if not UIFullscreen.onMouseUp(self, code, x, y) then - if self:hitTest(x, y) then - if code == 4 then - -- Mouse wheel, scroll. +function UIStaffManagement:onMouseWheel(x, y) + if not UIFullscreen.onMouseWheel(self, x, y) then + if self:hitTest(self.cursor_x, self.cursor_y) then + if y > 0 then self:scrollUp() return true - elseif code == 5 then + else self:scrollDown() return true end @@ -444,11 +454,49 @@ return x + px - (dx or 0), y + py - (dy or 0) end +function UIStaffManagement:previousCategory() + if self.category == "Nurse" then + self:setCategory("Doctor") + elseif self.category == "Handyman" then + self:setCategory("Nurse") + elseif self.category == "Receptionist" then + self:setCategory("Handyman") + end +end + +function UIStaffManagement:nextCategory() + if self.category == "Doctor" then + self:setCategory("Nurse") + elseif self.category == "Nurse" then + self:setCategory("Handyman") + elseif self.category == "Handyman" then + self:setCategory("Receptionist") + end +end + +function UIStaffManagement:previousStaff() + -- If nothing currently selected, select the last one, otherwise the previous. + if self.selected_staff == nil then + self:selectIndex(#self.staff_members[self.category]) + else + self:selectIndex(self.selected_staff - 1) + end +end + +function UIStaffManagement:nextStaff() + -- If nothing currently selected, select the first one, otherwise the next. + if self.selected_staff == nil then + self:selectIndex(1) + else + self:selectIndex(self.selected_staff + 1) + end +end + function UIStaffManagement:scrollUp() if self.scroll_dot.visible and self.page > 1 then self.selected_staff = nil self.page = self.page - 1 - self.scroll_dot.y = 168 + 83*((self.page - 1)/math.floor((#self.staff_members[self.category]-1)/10)) + self:updateScrollDot() end self:updateTooltips() end @@ -457,11 +505,28 @@ if self.scroll_dot.visible and self.page*10 < #self.staff_members[self.category] then self.selected_staff = nil self.page = self.page + 1 - self.scroll_dot.y = 168 + 83*((self.page - 1)/math.floor((#self.staff_members[self.category]-1)/10)) + self:updateScrollDot() end self:updateTooltips() end +--! Updates the position of the paging scroll indicator +function UIStaffManagement:updateScrollDot() + local numPages = math.ceil(#self.staff_members[self.category] / 10) + local yOffset = math_floor(83 * ((self.page - 1) / (numPages - 1))) + self.scroll_dot.y = 168 + yOffset +end + +--! Updates whether the paging scroll indicator is visible and its position if visible +function UIStaffManagement:updateScrollDotVisibility() + if #self.staff_members[self.category] > 10 then + self.scroll_dot.visible = true + self:updateScrollDot() + else + self.scroll_dot.visible = false + end +end + function UIStaffManagement:payBonus() local staff = self.staff_members[self.category][self.selected_staff] if self.selected_staff and self.hospital.balance > math_floor(staff.profile.wage*0.1) then diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/town_map.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/town_map.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen/town_map.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen/town_map.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,17 +18,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") --! Town map fullscreen window (purchase land, set radiator levels, map overview). class "UITownMap" (UIFullscreen) +---@type UITownMap +local UITownMap = _G["UITownMap"] + function UITownMap:UITownMap(ui) self:UIFullscreen(ui) - local app = self.ui.app - local hospital = self.ui.hospital - local gfx = app.gfx + local app = self.ui.app + local gfx = app.gfx self.app = app if not pcall(function() @@ -207,7 +209,7 @@ -- Draw entities local function draw_entities(list, color, size) - for i, ent in ipairs(list) do + for _, ent in ipairs(list) do -- 3 is the number of pixel that are used to represent one world tile in the map canvas:drawRect(color, town_map_offset_x + ent.tile_x * 3 - 2, town_map_offset_y + ent.tile_y * 3 + 1, size, size) @@ -215,7 +217,7 @@ end local function draw_entities_in_hospital(list, color, size) - for i, ent in ipairs(list) do + for _, ent in ipairs(list) do local tile_x, tile_y = ent.tile_x, ent.tile_y if tile_x and hospital:isInHospital(tile_x, tile_y) then -- 3 is the number of pixel that are used to represent one world tile in the map @@ -225,6 +227,21 @@ end end + --! Select entities of the world by their id. + --!param id Id of the objects to select. + --!return (list) The selected entities. + local function get_objects_by_id(id) + local ret = {} + for _, obj_list in pairs(world.objects) do + for _, obj in ipairs(obj_list) do + if obj.object_type.id == id then + table.insert(ret, obj) + end + end + end + return ret + end + if config.people_enabled then local staff_color = canvas:mapRGB(97, 109, 235) local patient_color = canvas:mapRGB(255, 255, 255) @@ -234,17 +251,17 @@ if config.radiators_enabled then local radiator_color = canvas:mapRGB(255, 0, 70) - draw_entities(world:getObjectsById("radiator"), radiator_color, 1) + draw_entities(get_objects_by_id("radiator"), radiator_color, 1) end if config.fire_ext_enabled then local fire_ext_color = canvas:mapRGB(216, 0, 0) - draw_entities(world:getObjectsById("extinguisher"), fire_ext_color, 2) + draw_entities(get_objects_by_id("extinguisher"), fire_ext_color, 2) end if config.plants_enabled then local plant_color = canvas:mapRGB(127, 180, 73) - draw_entities(world:getObjectsById("plant"), plant_color, 2) + draw_entities(get_objects_by_id("plant"), plant_color, 2) end if config.objects_enabled then diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen.lua corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/fullscreen.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/fullscreen.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,10 +21,12 @@ --! Base class for 640x480px dialogs (fullscreen in original game resolution). class "UIFullscreen" (Window) +---@type UIFullscreen +local UIFullscreen = _G["UIFullscreen"] + function UIFullscreen:UIFullscreen(ui) self:Window() - local app = ui.app self.esc_closes = true self.ui = ui self.modal_class = "fullscreen" @@ -60,15 +62,15 @@ end end - self.x = (app.config.width - self.width) / 2 + self.x = math.floor((app.config.width - self.width) / 2) -- NB: Bottom panel is 48 pixels high if app.config.height > 480 + 48 then - self.y = (app.config.height - 48 - self.height) / 2 + self.y = math.floor((app.config.height - 48 - self.height) / 2) elseif app.config.height >= 480 then self.y = 0 else - self.y = (app.config.height - self.height) / 2 + self.y = math.floor((app.config.height - self.height) / 2) end end @@ -76,20 +78,20 @@ local sprites = self.border_sprites if sprites then local draw = sprites.draw - local x = self.x + x - local y = self.y + y + local scr_x = self.x + x + local scr_y = self.y + y canvas:nonOverlapping(true) - draw(sprites, canvas, 10, x - 9, y - 9) - draw(sprites, canvas, 12, x + 600, y - 9) - draw(sprites, canvas, 15, x - 9, y + 440) - draw(sprites, canvas, 17, x + 600, y + 440) - for x = x + 40, x + 560, 40 do - draw(sprites, canvas, 11, x, y - 9) - draw(sprites, canvas, 16, x, y + 480) + draw(sprites, canvas, 10, scr_x - 9, scr_y - 9) + draw(sprites, canvas, 12, scr_x + 600, scr_y - 9) + draw(sprites, canvas, 15, scr_x - 9, scr_y + 440) + draw(sprites, canvas, 17, scr_x + 600, scr_y + 440) + for loop_x = scr_x + 40, scr_x + 560, 40 do + draw(sprites, canvas, 11, loop_x, scr_y - 9) + draw(sprites, canvas, 16, loop_x, scr_y + 480) end - for y = y + 40, y + 400, 40 do - draw(sprites, canvas, 13, x - 9, y) - draw(sprites, canvas, 14, x + 640, y) + for loop_y = scr_y + 40, scr_y + 400, 40 do + draw(sprites, canvas, 13, scr_x - 9, loop_y) + draw(sprites, canvas, 14, scr_x + 640, loop_y) end canvas:nonOverlapping(false) end @@ -99,7 +101,7 @@ function UIFullscreen:onMouseDown(button, x, y) local repaint = Window.onMouseDown(self, button, x, y) if button == "left" and not repaint and not (x >= 0 and y >= 0 and - x < self.width and y < self.height) and self:hitTest(x, y) then + x < self.width and y < self.height) and self:hitTest(x, y) then return self:beginDrag(x, y) end return repaint @@ -119,11 +121,11 @@ if (0 <= x and x < self.width) or (0 <= y and y < self.height) then return true end - local test = sprites.hitTest - return test(sprites, 10, x + 9, y + 9) - or test(sprites, 12, x - 600, y + 9) - or test(sprites, 15, x + 9, y - 440) - or test(sprites, 17, x - 600, y - 440) + + return sprites.hitTest(sprites, 10, x + 9, y + 9) or + sprites.hitTest(sprites, 12, x - 600, y + 9) or + sprites.hitTest(sprites, 15, x + 9, y - 440) or + sprites.hitTest(sprites, 17, x - 600, y - 440) end function UIFullscreen:afterLoad(old, new) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/furnish_corridor.lua corsix-th-0.62/CorsixTH/Lua/dialogs/furnish_corridor.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/furnish_corridor.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/furnish_corridor.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,13 +18,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") local math_floor = math.floor --! Dialog for purchasing `Object`s (for the corridor or for rooms). class "UIFurnishCorridor" (Window) +---@type UIFurnishCorridor +local UIFurnishCorridor = _G["UIFurnishCorridor"] + function UIFurnishCorridor:UIFurnishCorridor(ui, objects, edit_dialog) self:Window() @@ -57,7 +60,7 @@ } if objects then for _, object in pairs(objects) do - self.objects[#self.objects + 1] = {object = object.object, start_qty = object.qty, qty = object.qty, min_qty = object.min_qty} -- Had to make a copy of objects list. Otherwise, we will modify the original variable (Opening dialog twice keeps memory of previously choosen quantities) + self.objects[#self.objects + 1] = {object = object.object, start_qty = object.qty, qty = object.qty, min_qty = object.min_qty} -- Had to make a copy of objects list. Otherwise, we will modify the original variable (Opening dialog twice keeps memory of previously chosen quantities) end else for _, object in ipairs(app.objects) do @@ -87,16 +90,16 @@ self:addPanel(237, 154, 238):makeButton(0, 0, 197, 28, 238, self.confirm):setTooltip(_S.tooltip.buy_objects_window.confirm) local i = 1 local function item_callback(index, qty) - local is_negative_quantity = qty < 0 - return --[[persistable:furnish_corridor_item_callback]] function(self) - if self:purchaseItem(index, qty) == 0 and not is_negative_quantity then + local is_negative_quantity = qty < 0 + return --[[persistable:furnish_corridor_item_callback]] function(window) + if window:purchaseItem(index, qty) == 0 and not is_negative_quantity then -- give visual warning that player doesn't have enough $ to buy - self.ui.adviser:say(_A.warnings.cannot_afford_2, false, true) - self.ui:playSound "wrong2.wav" + window.ui.adviser:say(_A.warnings.cannot_afford_2, false, true) + window.ui:playSound("wrong2.wav") elseif qty > 0 then - self.ui:playSound "AddItemJ.wav" + window.ui:playSound("AddItemJ.wav") else - self.ui:playSound "DelItemJ.wav" + window.ui:playSound("DelItemJ.wav") end end end @@ -105,8 +108,8 @@ self:addPanel(239, x, y) -- List body if i <= #self.objects then self:addPanel(240, x + 12, y):makeButton(0, 0, 125, 19, 241, item_callback(i, 1), nil, item_callback(i, -1)):setTooltip(self.objects[i].object.tooltip) - self:addPanel(244, x + 139, y + 1):makeButton(0, 0, 17, 17, 245, item_callback(i, -1)):setTooltip(_S.tooltip.buy_objects_window.decrease) - self:addPanel(246, x + 183, y + 1):makeButton(0, 0, 17, 17, 247, item_callback(i, 1)):setTooltip(_S.tooltip.buy_objects_window.increase) + self:addPanel(244, x + 139, y + 1):makeRepeatButton(0, 0, 17, 17, 245, item_callback(i, -1)):setTooltip(_S.tooltip.buy_objects_window.decrease) + self:addPanel(246, x + 183, y + 1):makeRepeatButton(0, 0, 17, 17, 247, item_callback(i, 1)):setTooltip(_S.tooltip.buy_objects_window.increase) end i = i + 1 end @@ -114,15 +117,16 @@ self:makeTooltip(_S.tooltip.buy_objects_window.price, 20, 168, 127, 187) self:makeTooltip(_S.tooltip.buy_objects_window.total_value, 20, 196, 127, 215) - self:addKeyHandler("Enter", self.confirm) + self:addKeyHandler("return", self.confirm) + self:addKeyHandler("keypad enter", self.confirm) end function UIFurnishCorridor:purchaseItem(index, quantity) local o = self.objects[index] local is_negative_quantity = quantity < 0 - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then quantity = quantity * 10 - elseif self.buttons_down.shift then + elseif self.ui.app.key_modifiers.shift then quantity = quantity * 5 end quantity = quantity + o.qty @@ -154,7 +158,7 @@ local to_purchase = {} local to_sell = {} - for i, o in ipairs(self.objects) do + for _, o in ipairs(self.objects) do local build_cost = self.ui.hospital:getObjectBuildCost(o.object.id) if o.qty - o.start_qty > 0 then local diff_qty = o.qty - o.start_qty @@ -228,3 +232,13 @@ return repaint end + +function UIFurnishCorridor:afterLoad(old, new) + if old < 101 then + self:removeKeyHandler("enter") + self:addKeyHandler("return", self.confirm) + end + if old < 104 then + self:addKeyHandler("keypad enter", self.confirm) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/hire_staff.lua corsix-th-0.62/CorsixTH/Lua/dialogs/hire_staff.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/hire_staff.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/hire_staff.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,6 +20,9 @@ class "UIHireStaff" (Window) +---@type UIHireStaff +local UIHireStaff = _G["UIHireStaff"] + function UIHireStaff:UIHireStaff(ui) self:Window() self.modal_class = "main" @@ -32,7 +35,8 @@ self.panel_sprites = ui.app.gfx:loadSpriteTable("QData", "Req11V", true) self.white_font = ui.app.gfx:loadFont("QData", "Font01V") self.face_parts = ui.app.gfx:loadRaw("Face01V", 65, 1350, nil, "Data", "MPalette.dat") - self:addKeyHandler("Enter", self.hire) + self:addKeyHandler("return", self.hire) + self:addKeyHandler("keypad enter", self.hire) -- Left hand side tab backgrounds self:addPanel(253, 0, 0) @@ -43,12 +47,12 @@ -- Left hand side tabs local --[[persistable:hire_staff_category]] function category(name, state, btn) if #self.world.available_staff[name] == 0 then - self.ui:playSound "wrong2.wav" + self.ui:playSound("wrong2.wav") if state then btn:toggle() end else - self.ui:playSound "selectx.wav" + self.ui:playSound("selectx.wav") self:setCategory(state and name or nil) end end @@ -124,15 +128,15 @@ profile = profile and profile[self.current_index] end if not profile then - self.ui:playSound "wrong2.wav" + self.ui:playSound("wrong2.wav") return end if self.ui.hospital.balance < profile.wage then self:cannotAfford() - self.ui:playSound "wrong2.wav" + self.ui:playSound("wrong2.wav") return end - self.ui:playSound "YesX.wav" + self.ui:playSound("YesX.wav") table.remove(self.world.available_staff[self.category], self.current_index) self.ui:addWindow(UIPlaceStaff(self.ui, profile, self.mouse_up_x, self.mouse_up_y)) end @@ -172,8 +176,8 @@ local px, py = self.skill_bg_panel.x, self.skill_bg_panel.y px = px + x py = py + y - for x = 0, skill_bar_width - 1 do - self.panel_sprites:draw(canvas, 3, px + 22 + x, py + 9) + for dx = 0, skill_bar_width - 1 do + self.panel_sprites:draw(canvas, 3, px + 22 + dx, py + 9) end end end @@ -223,12 +227,12 @@ elseif self.current_index > #category then self.current_index = #category else - self.ui:playSound "selectx.wav" + self.ui:playSound("selectx.wav") self:updateTooltips() return true end end - self.ui:playSound "wrong2.wav" + self.ui:playSound("wrong2.wav") return false end @@ -247,7 +251,7 @@ self.complete_blanker.visible = not name self.abilities_blanker.visible = name ~= "Doctor" self.category = name - for i, btn in ipairs(self.tabs) do + for _, btn in ipairs(self.tabs) do local should_be_toggled = btn.on_click_self == name if btn.toggled ~= should_be_toggled then btn:toggle() @@ -262,3 +266,13 @@ self.ui:tutorialStep(4, {2, 3}, 1) return Window.close(self) end + +function UIHireStaff:afterLoad(old, new) + if old < 101 then + self:removeKeyHandler("enter") + self:addKeyHandler("return", self.hire) + end + if old < 104 then + self:addKeyHandler("keypad enter", self.hire) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/information.lua corsix-th-0.62/CorsixTH/Lua/dialogs/information.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/information.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/information.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Dialog that informs the player of for example what the goals for the level are. class "UIInformation" (Window) +---@type UIInformation +local UIInformation = _G["UIInformation"] + --! Constructor for the Information Dialog. --!param text The text to show, held in a table. All elements of the table will be written -- beneath each other. If instead a table within the table is supplied the texts @@ -42,9 +45,10 @@ self.black_font = app.gfx:loadBuiltinFont() self.black_background = true end + if type(text[1]) == "table" then - self.text = text[1][1] - table.remove(text[1], 1) + self.text = text[1] + table.remove(text, 1) self.additional_text = text else self.text = text @@ -62,19 +66,19 @@ self:onChangeLanguage() -- Enter closes the window - self:addKeyHandler("Enter", self.close) + self:addKeyHandler("return", self.close) + self:addKeyHandler("keypad enter", self.close) end function UIInformation:onChangeLanguage() - local rows = 0 - for i, text in ipairs(self.text) do - local old_rows = rows - rows = rows + math.floor(self.black_font:sizeOf(text) / 300 + 1) - rows = rows + 1 + local total_req_height = 0 + for _, text in ipairs(self.text) do + local _, req_height = self.black_font:sizeOf(text, self.text_width) + total_req_height = total_req_height + req_height end self.width = self.spacing.l + self.text_width + self.spacing.r - self.height = self.spacing.t + rows*12 + self.spacing.b + self.height = self.spacing.t + total_req_height + self.spacing.b self:setDefaultPosition(0.5, 0.5) self:removeAllPanels() @@ -101,9 +105,8 @@ local background = self.black_background and canvas:mapRGB(0, 0, 0) or canvas:mapRGB(255, 255, 255) canvas:drawRect(background, dx + 4, dy + 4, self.width - 8, self.height - 8) local last_y = dy + self.spacing.t - for i, text in ipairs(self.text) do - last_y = self.black_font:drawWrapped(canvas, text:gsub("//", ""), dx + self.spacing.l, last_y, self.text_width) - last_y = self.black_font:drawWrapped(canvas, " ", dx + self.spacing.l, last_y, self.text_width) + for _, text in ipairs(self.text) do + last_y = self.black_font:drawWrapped(canvas, text, dx + self.spacing.l, last_y, self.text_width) end Window.draw(self, canvas, x, y) @@ -120,7 +123,17 @@ function UIInformation:close() self.ui:tutorialStep(3, 16, "next") Window.close(self) - if self.additional_text and #self.additional_text[1] > 0 then + if self.additional_text and #self.additional_text > 0 then self.ui:addWindow(UIInformation(self.ui, self.additional_text)) end end + +function UIInformation:afterLoad(old, new) + if old < 101 then + self:removeKeyHandler("enter") + self:addKeyHandler("return", self.close) + end + if old < 104 then + self:addKeyHandler("keypad enter", self.close) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/jukebox.lua corsix-th-0.62/CorsixTH/Lua/dialogs/jukebox.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/jukebox.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/jukebox.lua 2018-07-21 11:13:17.000000000 +0000 @@ -23,6 +23,9 @@ class "UIJukebox" (Window) +---@type UIJukebox +local UIJukebox = _G["UIJukebox"] + function UIJukebox:UIJukebox(app) self:Window() self.modal_class = "jukebox" @@ -65,8 +68,8 @@ if not info.enabled then self.track_buttons[i]:toggle() end - self.track_buttons[i].on_click = --[[persistable:jukebox_toggle_track]] function(self, off) - self:toggleTrack(i, info, not off) + self.track_buttons[i].on_click = --[[persistable:jukebox_toggle_track]] function(window, off) + window:toggleTrack(i, info, not off) end end @@ -154,16 +157,16 @@ local playing = self.audio.background_music or "" for i, info in ipairs(self.audio.background_playlist) do - local y = y + 47 + i * 30 + local ypos = y + 47 + i * 30 local font = self.white_font if info.music == playing then font = self.blue_font end local str = info.title - while font:sizeOf(str, font) > 185 do + while font:sizeOf(str) > 185 do str = string.sub(str, 1, string.len(str) - 5) .. "..." end - font:draw(canvas, str, x + 24, y + 11) + font:draw(canvas, str, x + 24, ypos + 11) if info.music == playing then font:draw(canvas, str, x + 24, self.y + 27) end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/machine_dialog.lua corsix-th-0.62/CorsixTH/Lua/dialogs/machine_dialog.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/machine_dialog.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/machine_dialog.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,6 +20,9 @@ class "UIMachine" (Window) +---@type UIMachine +local UIMachine = _G["UIMachine"] + function UIMachine:UIMachine(ui, machine, room) self:Window() @@ -86,13 +89,13 @@ function UIMachine:callHandyman() if self.machine.times_used ~= 0 then - local taskIndex = self.machine.hospital:getIndexOfTask(self.machine.tile_x, self.machine_tile_y, "repairing") - if taskIndex == -1 then - local call = self.ui.app.world.dispatcher:callForRepair(self.machine, false, true) - self.machine.hospital:addHandymanTask(self.machine, "repairing", 2, self.machine.tile_x, self.machine.tile_y, call) - else - self.machine.hospital:modifyHandymanTaskPriority(taskIndex, 2, "repairing") - end + local taskIndex = self.machine.hospital:getIndexOfTask(self.machine.tile_x, self.machine.tile_y, "repairing") + if taskIndex == -1 then + local call = self.ui.app.world.dispatcher:callForRepair(self.machine, false, true) + self.machine.hospital:addHandymanTask(self.machine, "repairing", 2, self.machine.tile_x, self.machine.tile_y, call) + else + self.machine.hospital:modifyHandymanTaskPriority(taskIndex, 2, "repairing") + end end end @@ -103,23 +106,17 @@ if self.ui.hospital.balance < cost then -- give visual warning that player doesn't have enough $ to buy self.ui.adviser:say(_A.warnings.cannot_afford_2, false, true) - self.ui:playSound "wrong2.wav" + self.ui:playSound("wrong2.wav") return end - local strength = hosp.research.research_progress[machine.object_type].start_strength self.ui:addWindow(UIConfirmDialog(self.ui, _S.confirmation.replace_machine:format(machine.object_type.name, cost), --[[persistable:replace_machine_confirm_dialog]]function() - + -- Charge for new machine hosp:spendMoney(cost, _S.transactions.machine_replacement) - machine.total_usage = 0 - machine.times_used = 0 - self.machine.strength = strength - local index = machine.hospital:getIndexOfTask(machine.tile_x, machine.tile_y, "repairing") - if index ~= -1 then - machine.hospital:removeHandymanTask(index, "repairing") - end - machine:setRepairing(nil) + + -- Tell the machine to pretend it's a shiny new one + machine:machineReplaced() end )) end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/map_editor.lua corsix-th-0.62/CorsixTH/Lua/dialogs/map_editor.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/map_editor.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/map_editor.lua 1970-01-01 00:00:00.000000000 +0000 @@ -1,660 +0,0 @@ ---[[ Copyright (c) 2010 Peter "Corsix" Cawley - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. --]] - -dofile "command_stack" -dofile "command" -dofile "commands/set_map_cell" -dofile "commands/set_map_cell_flags" -dofile "commands/compound" - -class "UIMapEditor" (Window) - -local math_floor - = math.floor - -function UIMapEditor:UIMapEditor(ui) - -- Put ourselves in an easily findable global for the UI code to find. - _MAP_EDITOR = self - self:Window() - self.x = 0 - self.y = 0 - self.width = math.huge - self.height = math.huge - self.ui = ui - - self.command_stack = CommandStack() - - - - -- For when there are multiple things which could be sampled from a tile, - -- keep track of the index of which one was most recently sampled, so that - -- next time a different one is sampled. - self.sample_i = 1 - - -- The block to put on the UI layer as a preview for what will be placed - -- by the current drawing operation. - self.block_brush_preview = 0 - - self:classifyBlocks() - - -- A sprite table containing a "cell outline" sprite - self.cell_outline = TheApp.gfx:loadSpriteTable("Bitmap", "aux_ui", true) - - -- Coordinates in Lua tile space of the mouse cursor. - self.mouse_cell_x = 0 - self.mouse_cell_y = 0 -end - -function UIMapEditor:classifyBlocks() - -- Classify each block / tile with a type, subtype, and category. - -- Type and subtype are used by this file, and by the UI code to determine - -- which gallery to put the block in. Category is used purely by the UI to - -- allow subsets of a gallery to be hidden. - local block_info = {} - for i = 1, 15 do - block_info[i] = {"floor", "simple", "Outside"} - end - for i = 16, 23 do - block_info[i] = {"floor", "simple", "Inside"} - end - for i = 24, 40 do - block_info[i] = {"object"} - end - for i = 41, 58 do - block_info[i] = {"floor", "simple", "Road"} - end - block_info[59] = {"floor", "decorated", "Pond"} - block_info[60] = {"floor", "decorated", "Pond"} - for i = 61, 64 do - block_info[i] = {"floor", "simple", "Outside"} - end - block_info[65] = {"floor", "decorated", "Pond"} - block_info[66] = {"floor", "simple", "Inside"} -- 67 is UI. - block_info[68] = {"floor", "decorated", "Pond"} - block_info[69] = {"floor", "decorated", "Pond"} - block_info[70] = {"floor", "simple", "Inside"} - for i = 71, 73 do - block_info[i] = {"floor", "decorated", "Pond", base = 69} - end - block_info[76] = {"floor", "simple", "Inside"} - for i = 77, 80 do - block_info[i] = {"floor", "decorated", "Pond"} - end - for i = 114, 164 do -- 82-113 are internal walls - local pair - local category = "External" - local dir = i % 2 == 0 and "north" or "west" - if 114 <= i and i <= 127 then - if 114 <= i and i <= 119 then - pair = i + 8 - elseif 122 <= i and i < 127 then - pair = i - 8 - end - elseif 157 <= i and i <= 164 then - category = "Doorway" - if 157 <= i and i <= 160 then - pair = i + 4 - elseif 161 <= i and i < 164 then - pair = i - 4 - end - dir = dir == "north" and "west" or "north" - end - for i = 128, 156 do - block_info[i] = {"object"} - end - for i = 120, 121 do -- removes the complete windows as they disappear in the game - block_info[i] = {"object"} - end - if i ~= 144 and i ~= 145 and i ~= 156 then - block_info[i] = {"wall", dir, category, pair = pair} - end - end - for i = 176, 191 do - block_info[i] = {"floor", "decorated", "Hegderow", base = 2} - end - for i = 192, 196 do - block_info[i] = {"floor", "decorated", "Foliage", base = 2} - end - for i = 197, 204 do - block_info[i] = {"floor", "decorated", "Foliage", base = 2} - end - for i = 205, 208 do - block_info[i] = {"floor", "simple", "Outside"} - end - block_info[208].base = 3 --- adds street lights, could do with mirrors of these to have lamps facing different directions - for i = 209, 210 do - local pair - local category = "External" - local dir = i % 2 == 0 and "north" or "west" - if i ~= 209 then - pair = i - 1 - end - block_info[i] = {"wall", dir, category, pair = pair} - end - - MapEditorSetBlocks(self.ui.app.map.blocks, block_info) -- pass data to UI - self.block_info = block_info -end - -function UIMapEditor:draw(canvas, ...) - local ui = self.ui - local x, y = ui:WorldToScreen(self.mouse_cell_x, self.mouse_cell_y) - self.cell_outline:draw(canvas, 2, x - 32, y) - - Window.draw(self, canvas, ...) -end - - -function UIMapEditor:onMouseMove(x, y, dx, dy) - local repaint = Window.onMouseMove(self, x, y, dx, dy) - - local ui = self.ui - local wxr, wyr = ui:ScreenToWorld(self.x + x, self.y + y) - local wx = math_floor(wxr) - local wy = math_floor(wyr) - local map = self.ui.app.map - - -- Update the stored state of cursor position, and trigger a repaint as the - -- cell outline sprite should track the cursor position. - if wx ~= self.mouse_cell_x or wy ~= self.mouse_cell_y then - repaint = true - self.mouse_cell_x = wx - self.mouse_cell_y = wy - -- Right button down: sample the block under the cursor (unless left is - -- held, as that indicates a paint in progress). - if self.buttons_down.mouse_right and not self.buttons_down.mouse_left then - self:sampleBlock(x, y) - end - end - - -- Left button down: Expand / contract the rectangle which will be painted to - -- include the original mouse down cell and the current cell, or clear the - -- rectangle if the cursor is returned to where the mouse down position. - if self.buttons_down.mouse_left and self.paint_rect and 1 <= wx and 1 <= wy - and wx <= map.width and wy <= map.height then - local p1x = math_floor(self.paint_start_wx) - local p1y = math_floor(self.paint_start_wy) - local p2x = wx - local p2y = wy - local x, y, w, h - if p1x < p2x then - x = p1x - w = p2x - p1x + 1 - else - x = p2x - w = p1x - p2x + 1 - end - if p1y < p2y then - y = p1y - h = p2y - p1y + 1 - else - y = p2y - h = p1y - p2y + 1 - end - if w*h > 1 then - -- The paint rectangle extends beyond the original mouse down cell, so - -- make the area in the middle of said cell into a "null area" so that - -- the paint operation can be cancelled by returning the cursor to this - -- area and ending the drag. - self.has_paint_null_area = true - elseif w == 1 and h == 1 and self.has_paint_null_area then - if ((wxr % 1) - 0.5)^2 + ((wyr % 1) - 0.5)^2 < 0.25^2 then - w = 0 - h = 0 - end - end - local rect = self.paint_rect - if x ~= rect.x or y ~= rect.y or w ~= rect.w or h ~= rect.h then - self:setPaintRect(x, y, w, h) - repaint = true - end - end - - return repaint -end - -function UIMapEditor:onMouseDown(button, x, y) - local repaint = false - local map = self.ui.app.map.th - if button == "right" then - if self.buttons_down.mouse_left then - -- Right click while left is down: set paint step size - local wx, wy = self.ui:ScreenToWorld(x, y) - local xstep = math.max(1, math.abs(math.floor(wx) - math.floor(self.paint_start_wx))) - local ystep = math.max(1, math.abs(math.floor(wy) - math.floor(self.paint_start_wy))) - local rect = self.paint_rect - self:setPaintRect(rect.x, rect.y, rect.w, rect.h, xstep, ystep) - repaint = true - else - -- Normal right click: sample the block under the cursor - self:sampleBlock(x, y) - end - elseif button == "left" then - self.current_command = CompoundCommand() - self.current_command_cell = SetMapCellCommand(map) - self.current_command_cell_flags = SetMapCellFlagsCommand(map) - self:startPaint(x, y) - repaint = true - elseif button == "left_double" then - self.current_command = CompoundCommand() - self.current_command_cell = SetMapCellCommand(map) - self.current_command_cell_flags = SetMapCellFlagsCommand(map) - self:doLargePaint(x, y) - -- Set a dummy paint rect for the mouse up event. - self:setPaintRect(0, 0, 0, 0) - repaint = true - end - - return Window.onMouseDown(self, button, x, y) or repaint -end - -function UIMapEditor:onMouseUp(button, x, y) - local repaint = false - if button == "left" and self.paint_rect then - self:finishPaint(true) - if #self.current_command_cell.paint_list ~=0 then - self.current_command:addCommand(self.current_command_cell) - end - if #self.current_command_cell_flags.paint_list ~= 0 then - self.current_command:addCommand(self.current_command_cell_flags) - end - self.command_stack:add(self.current_command) - repaint = true - end - - return Window.onMouseUp(self, button, x, y) or repaint -end - -function UIMapEditor:startPaint(x, y) - -- Save the Lua world coordinates of where the painting started. - self.paint_start_wx, self.paint_start_wy = self.ui:ScreenToWorld(x, y) - -- Initialise an empty paint rectangle. - self.paint_rect = { - x = math_floor(self.paint_start_wx), - y = math_floor(self.paint_start_wy), - w = 0, h = 0, - } - self.has_paint_null_area = false - -- Check that starting point isn't out of bounds - local map = self.ui.app.map - if self.paint_rect.x < 1 or self.paint_rect.y < 1 - or self.paint_rect.x > map.width or self.paint_rect.y > map.height then - self.paint_rect = nil - return - end - -- Reset the paint step. - self.paint_step_x = 1 - self.paint_step_y = 1 - -- Extend the paint rectangle to the single cell. - self:setPaintRect(self.paint_rect.x, self.paint_rect.y, 1, 1) -end - --- Injective function from NxN to N which allows for a pair of positive --- integers to be combined into a single value suitable for use as a key in a --- table. -local function combine_ints(x, y) - local sum = x + y - return y + sum * (sum + 1) / 2 -end - -function UIMapEditor:doLargePaint(x, y) - -- Perform a "large" paint. At the moment, this is triggered by a double - -- left click, and results in a floor tile "flood fill" operation. - - -- Get the Lua tile coordinate of the tile to start filling from. - x, y = self.ui:ScreenToWorld(x, y) - x = math_floor(x) - y = math_floor(y) - if x <= 0 or y <= 0 then - return - end - - -- The click which preceeded the double click should have set "old_floors" - -- with the contents of the tile prior to the single click. - if not self.old_floors then - return - end - -- brush_f is the tile which is to be painted - local brush_f = self.block_brush_f - if not brush_f or brush_f == 0 then - return - end - local map = self.ui.app.map.th - local key = combine_ints(x, y) - -- match_f is the tile which is to be replaced by brush_f - local match_f = self.old_floors[key] - if not match_f then - return - end - match_f = match_f % 256 -- discard shadow flags, etc. - -- If the operation wouldn't change anything, don't do it. - if match_f == brush_f then - return - end - - -- Reset the starting tile as to simplify the upcoming loop. - self.current_command_cell:addTile(x, y, 1, match_f) - map:setCell(x, y, 1, match_f) - - - local to_visit = {[key] = {x, y}} - local visited = {[key] = true} - -- Mark the tiles beyond the edge of the map as visited, as to prevent the - -- pathfinding from exceeding the bounds of the map. - local size = map:size() - for i = 1, size do - visited[combine_ints(0, i)] = true - visited[combine_ints(i, 0)] = true - visited[combine_ints(size + 1, i)] = true - visited[combine_ints(i, size + 1)] = true - end - -- When a tile is added to "visited" to the first time, also add it to - -- "to_visit". This ensures each tile is visited no more than once. - setmetatable(visited, {__newindex = function(t, k, v) - rawset(t, k, v) - to_visit[k] = v - end}) - -- Iterate over the tiles to visit, and if they are suitable for replacement, - -- do the replacement and add their neighbours to the list of things to do. - repeat - x = to_visit[key][1] - y = to_visit[key][2] - to_visit[key] = nil - local f = map:getCell(x, y) - if f % 256 == match_f then - self.current_command_cell:addTile(x, y, 1, f - match_f + brush_f) - map:setCell(x, y, 1, f - match_f + brush_f) - visited[combine_ints(x, y + 1)] = {x, y + 1} - visited[combine_ints(x, y - 1)] = {x, y - 1} - visited[combine_ints(x + 1, y)] = {x + 1, y} - visited[combine_ints(x - 1, y)] = {x - 1, y} - end - to_visit[key] = nil - key = next(to_visit) - until not key -end - --- Remove the paint preview from the UI layer, and optionally apply the paint --- to the actual layers. -function UIMapEditor:finishPaint(apply) - -- Grab local copies of all the fields which we need - local map = self.ui.app.map.th - local brush_f = self.block_brush_f - local brush_parcel = self.block_brush_parcel - if brush_parcel then - brush_parcel = {parcelId = brush_parcel} - end - local brush_w1 = self.block_brush_w1 - local brush_w1p = (self.block_info[brush_w1] or '').pair - local brush_w2 = self.block_brush_w2 - local brush_w2p = (self.block_info[brush_w2] or '').pair - local x_first, x_last = self.paint_rect.x, self.paint_rect.x + self.paint_rect.w - 1 - local y_first, y_last = self.paint_rect.y, self.paint_rect.y + self.paint_rect.h - 1 - local step_base_x = math.floor(self.paint_start_wx) - local step_base_y = math.floor(self.paint_start_wy) - local xstep = self.paint_step_x - local ystep = self.paint_step_y - - -- Determine what kind of thing is being painted. - local is_wall = self.block_info[self.block_brush_preview] - is_wall = is_wall and is_wall[1] == "wall" and is_wall[2] - local is_simple_floor = self.block_info[self.block_brush_preview] - is_simple_floor = is_simple_floor and is_simple_floor[1] == "floor" and is_simple_floor[2] == "simple" - - -- To allow the double click handler to know what was present before the - -- single click which preceeds it, the prior contents of the floor layer is - -- saved. - local old_floors = {} - self.old_floors = old_floors - for tx = x_first, x_last do - for ty = y_first, y_last do - -- Grab and save the contents of the tile - local f, w1, w2 = map:getCell(tx, ty) - old_floors[combine_ints(tx, ty)] = f - local flags - -- Change the contents according to what is being painted - repeat - -- If not painting, do not change anything (apart from UI layer). - if not apply then - break - end - -- If the paint is happening at an interval, do not change things - -- apart from at the occurances of the interval. - if ((tx - step_base_x) % xstep) ~= 0 then - break - end - if ((ty - step_base_y) % ystep) ~= 0 then - break - end - flags = brush_parcel - -- If painting walls, only apply to the two edges which get painted. - if is_wall == "north" and ty ~= y_first and ty ~= y_last then - break - end - if is_wall == "west" and tx ~= x_first and tx ~= x_last then - break - end - -- If painting a floor component, apply it. - if not brush_parcel and brush_f and brush_f ~= 0 then - f = f - (f % 256) + brush_f - -- If painting just a floor component, then remove any decoration - -- and/or walls which get painted over. - if is_simple_floor then - local w1b = self.block_info[w1 % 256] - if not w1b or w1b[1] ~= "wall" or ty ~= y_first then - w1 = w1 - (w1 % 256) - end - local w2b = self.block_info[w2 % 256] - if not w2b or w2b[1] ~= "wall" or tx ~= x_first then - w2 = w2 - (w2 % 256) - end - end - end - -- If painting wall components, apply them. - if brush_w1 and brush_w1 ~= 0 then - w1 = w1 - (w1 % 256) + (ty ~= step_base_y and brush_w1p or brush_w1) - end - if brush_w2 and brush_w2 ~= 0 then - w2 = w2 - (w2 % 256) + (tx ~= step_base_x and brush_w2p or brush_w2) - end - until true - -- Remove the UI layer and perform the adjustment of the other layers. - self.current_command_cell:addTile(tx,ty,f,w1,w2,0) - map:setCell(tx, ty, f, w1, w2, 0) - if flags then - self.current_command_cell_flags:addTile(tx, ty, flags) - map:setCellFlags(tx, ty, flags) - end - end - end - map:updateShadows() - -end - --- Move/resize the rectangle to be painted, and update the UI preview layer --- to reflect the new rectangle. -function UIMapEditor:setPaintRect(x, y, w, h, xstep, ystep) - local map = self.ui.app.map.th - local rect = self.paint_rect - local old_xstep = self.paint_step_x or 1 - local old_ystep = self.paint_step_y or 1 - local step_base_x = math.floor(self.paint_start_wx) - local step_base_y = math.floor(self.paint_start_wy) - xstep = xstep or old_xstep - ystep = ystep or old_ystep - - -- Create a rectangle which contains both the old and new rectangles, as - -- this contains all tiles which may need to change. - local left, right, top, bottom = x, x + w - 1, y, y + h - 1 - if rect then - if rect.x < left then - left = rect.x - end - if rect.x + rect.w - 1 > right then - right = rect.x + rect.w - 1 - end - if rect.y < top then - top = rect.y - end - if rect.y + rect.h - 1 > bottom then - bottom = rect.y + rect.h - 1 - end - end - - -- Determine what kind of thing is being painted - local is_wall = self.block_info[self.block_brush_preview] - local block_brush_preview_pair = is_wall and is_wall.pair - is_wall = is_wall and is_wall[1] == "wall" and is_wall[2] - - for tx = left, right do - for ty = top, bottom do - local now_in, was_in - -- Non-walls: paint at every tile within the rectangle - if not is_wall then - now_in = (x <= tx and tx < x + w and y <= ty and ty < y + h) - was_in = (rect.x <= tx and tx < rect.x + rect.w and rect.y <= ty and ty < rect.y + rect.h) - -- Walls: paint at two edges of the rectangle - elseif is_wall == "north" then - now_in = (x <= tx and tx < x + w and (y == ty or ty == y + h - 1)) - was_in = (rect.x <= tx and tx < rect.x + rect.w and (rect.y == ty or ty == rect.y + rect.h - 1)) - elseif is_wall == "west" then - now_in = ((x == tx or tx == x + w - 1) and y <= ty and ty < y + h) - was_in = ((rect.x == tx or tx == rect.x + rect.w - 1) and rect.y <= ty and ty < rect.y + rect.h) - end - -- Restrict the paint to tiles which fall on the appropriate intervals - now_in = now_in and ((tx - step_base_x) % xstep) == 0 - now_in = now_in and ((ty - step_base_y) % ystep) == 0 - was_in = was_in and ((tx - step_base_x) % old_xstep) == 0 - was_in = was_in and ((ty - step_base_y) % old_ystep) == 0 - -- Update the tile, but only if it needs changing - if now_in ~= was_in then - local ui_layer = 0 - if now_in then - local brush = self.block_brush_preview - if is_wall == "north" and ty ~= step_base_y then - brush = block_brush_preview_pair or brush - end - if is_wall == "west" and tx ~= step_base_x then - brush = block_brush_preview_pair or brush - end - ui_layer = brush + 256 * DrawFlags.Alpha50 - end - self.current_command_cell:addTile(tx, ty, 4, ui_layer) - map:setCell(tx, ty, 4, ui_layer) - end - end - end - - -- Save the details of the new rectangle - if not rect then - rect = {} - self.paint_rect = rect - end - rect.x = x - rect.y = y - rect.w = w - rect.h = h - self.paint_step_x = xstep - self.paint_step_y = ystep -end - -function UIMapEditor:sampleBlock(x, y) - local ui = self.ui - local wx, wy = self.ui:ScreenToWorld(x, y) - wx = math_floor(wx) - wy = math_floor(wy) - local map = self.ui.app.map - if wx < 1 or wy < 1 or wx > map.width or wy > map.height then - return - end - local floor, wall1, wall2 = map.th:getCell(wx, wy) - local set = {} - set[floor % 256] = true - set[wall1 % 256] = true - set[wall2 % 256] = true - if wx < map.width then - floor, wall1, wall2 = map.th:getCell(wx + 1, wy) - set[wall2 % 256] = true - end - if wy < map.height then - floor, wall1, wall2 = map.th:getCell(wx, wy + 1) - set[wall1 % 256] = true - end - set[0] = nil - local floor_list = {} - local wall_list = {} - for i in pairs(set) do - if self.block_info[i] then - if self.block_info[i][1] == "floor" then - floor_list[#floor_list + 1] = i - elseif self.block_info[i][1] == "wall" then - wall_list[#wall_list + 1] = i - end - end - end - - if wx == self.recent_sample_x and wy == self.recent_sample_y then - self.sample_i = self.sample_i + 1 - else - self.sample_i = 1 - self.recent_sample_x = wx - self.recent_sample_y = wy - end - MapEditorSetBlockBrush( - floor_list[1 + (self.sample_i - 1) % #floor_list] or 0, - wall_list [1 + (self.sample_i - 1) % #wall_list ] or 0 - ) -end - --- Called by the UI to set what should be painted. -function UIMapEditor:setBlockBrush(f, w1, w2) - local preview = f - if w2 ~= 0 then - preview = w2 - elseif w1 ~= 0 then - preview = w1 - end - self.block_brush_preview = preview - self.block_brush_parcel = nil - self.block_brush_f = f - self.block_brush_w1 = w1 - self.block_brush_w2 = w2 -end - -function UIMapEditor:setBlockBrushParcel(parcel) - self.block_brush_preview = 24 - self.block_brush_parcel = parcel - self.block_brush_f = self.block_brush_preview - self.block_brush_w1 = 0 - self.block_brush_w2 = 0 -end - -function UIMapEditor:undo() - local last = self.command_stack:undo() - self.ui.app.map.th:updateShadows() - return last -end - -function UIMapEditor:redo() - local last = self.command_stack:redo() - self.ui.app.map.th:updateShadows() - return last -end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/menu.lua corsix-th-0.62/CorsixTH/Lua/dialogs/menu.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/menu.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/menu.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,12 +20,15 @@ local ipairs, math_floor, unpack, select, assert = ipairs, math.floor, unpack, select, assert -local TH = require "TH" +local TH = require("TH") --! The ingame menu bar which sits (nominally hidden) at the top of the screen. class "UIMenuBar" (Window) -function UIMenuBar:UIMenuBar(ui) +---@type UIMenuBar +local UIMenuBar = _G["UIMenuBar"] + +function UIMenuBar:UIMenuBar(ui, map_editor) self:Window() local app = ui.app @@ -42,13 +45,17 @@ -- The list of top-level menus, from left to right self.menus = {} -- The menu which the cursor was most recently over - -- This should be present in self.open_menus, else it wont be drawn + -- This should be present in self.open_menus, else it won't be drawn self.active_menu = false -- The list of menus which should be displayed -- This list satifies: open_menus[x] == nil or open_menus[x].level == x self.open_menus = {} - self:makeMenu(app) + if map_editor then + self:makeMapeditorMenu(app) + else + self:makeGameMenu(app) + end end function UIMenuBar:onTick() @@ -58,9 +65,9 @@ -- item in its parent corresponding to it. local deepest = self.open_menus[#self.open_menus] local parent = deepest.parent - if deepest == self.active_menu or (parent and parent == self.active_menu - and parent.items[parent.hover_index] - and parent.items[parent.hover_index].submenu == deepest) then + if deepest == self.active_menu or + (parent and parent == self.active_menu and parent.items[parent.hover_index] and + parent.items[parent.hover_index].submenu == deepest) then self.menu_disappear_counter = nil else if self.menu_disappear_counter == 0 then @@ -120,9 +127,12 @@ end end +--! Add a menu to the menu bar. +--!param title Title of the menu (at the bar). +--!param menu Menu to add. function UIMenuBar:addMenu(title, menu) assign_menu_levels(menu, 1) - local menu = { + local menu_item = { title = title, menu = menu, x = 0, @@ -130,10 +140,10 @@ height = 16, } if self.menus[1] then - menu.x = self.menus[#self.menus].x + self.menus[#self.menus].width + menu_item.x = self.menus[#self.menus].x + self.menus[#self.menus].width end - menu.width = self.white_font:sizeOf(title) + 32 - self.menus[#self.menus + 1] = menu + menu_item.width = self.white_font:sizeOf(title) + 32 + self.menus[#self.menus + 1] = menu_item end function UIMenuBar:draw(canvas) @@ -185,8 +195,8 @@ canvas:nonOverlapping(false) local btmy = y + h - 6 panel_sprites_draw(panel_sprites, canvas, 3, x + w - 10, y) - for y = y + 6, y + h - 6, 4 do - panel_sprites_draw(panel_sprites, canvas, 6, x + w - 10, y) + for ypos = y + 6, y + h - 6, 4 do + panel_sprites_draw(panel_sprites, canvas, 6, x + w - 10, ypos) end panel_sprites_draw(panel_sprites, canvas, 9, x + w - 10, btmy) @@ -350,7 +360,7 @@ self.open_menus = {new_active} self.active_menu = new_active repaint = true - self.ui:playSound "selectx.wav" + self.ui:playSound("selectx.wav") end return repaint end @@ -402,7 +412,7 @@ end self.active_menu = false end - self.ui:playSound "selectx.wav" + self.ui:playSound("selectx.wav") repaint = true break end @@ -455,6 +465,9 @@ class "UIMenu" +---@type UIMenu +local UIMenu = _G["UIMenu"] + function UIMenu:UIMenu() self.items = {} self.parent = false @@ -466,8 +479,8 @@ -- number -> hit that item -- true -> hit menu, but not an item -- false -> no hit - if self.x - padding <= x and x < self.x + self.width + padding - and self.y - padding <= y and y < self.y + self.height + padding then + if self.x - padding <= x and x < self.x + self.width + padding and + self.y - padding <= y and y < self.y + self.height + padding then if self.x <= x and x < self.x + self.width then local index = math_floor((y - self.y + 12) / 14) if 1 <= index and index <= #self.items then @@ -512,7 +525,26 @@ } end -function UIMenuBar:makeMenu(app) +--! Make a menu for the map editor. +--!param app Application. +function UIMenuBar:makeMapeditorMenu(app) + local menu = UIMenu() + menu:appendItem(_S.menu_file.load, function() self.ui:addWindow(UILoadMap(self.ui, "map")) end) + :appendItem(_S.menu_file.save, function() self.ui:addWindow(UISaveMap(self.ui)) end) + :appendItem(_S.menu_file.quit, function() self.ui:quit() end) + self:addMenu(_S.menu.file, menu) + + menu = UIMenu() + menu:appendItem(_S.menu_player_count.players_1, function() self.ui.map_editor:setPlayerCount(1) end) + :appendItem(_S.menu_player_count.players_2, function() self.ui.map_editor:setPlayerCount(2) end) + :appendItem(_S.menu_player_count.players_3, function() self.ui.map_editor:setPlayerCount(3) end) + :appendItem(_S.menu_player_count.players_4, function() self.ui.map_editor:setPlayerCount(4) end) + self:addMenu(_S.menu.player_count, menu) +end + +--! Make a menu for the game. +--!param app Application. +function UIMenuBar:makeGameMenu(app) local menu = UIMenu() menu:appendItem(_S.menu_file.load, function() self.ui:addWindow(UILoadGame(self.ui, "game")) end) :appendItem(_S.menu_file.save, function() self.ui:addWindow(UISaveGame(self.ui)) end) @@ -548,11 +580,11 @@ end local function appendVolume(setting) - local menu = UIMenu() -- The three Volume menus + local volume_menu = UIMenu() -- The three Volume menus for level = 10, 100, 10 do - menu:appendCheckItem(_S.menu_options_volume[level], vol(level / 100, setting)) + volume_menu:appendCheckItem(_S.menu_options_volume[level], vol(level / 100, setting)) end - return menu + return volume_menu end options:appendCheckItem(_S.menu_options.sound, @@ -578,10 +610,6 @@ return app.config.play_announcements end) - local function musicStatus(item) - return not not app.audio.background_music and not app.audio.background_paused - end - options:appendCheckItem(_S.menu_options.music, app.config.play_music, function(item) @@ -594,7 +622,7 @@ return app.config.play_music end) - options + options :appendMenu(_S.menu_options.sound_vol, appendVolume("sound")) :appendMenu(_S.menu_options.announcements_vol, appendVolume("announcement")) :appendMenu(_S.menu_options.music_vol, appendVolume("music")) @@ -608,12 +636,21 @@ end options:appendCheckItem(_S.menu_options.lock_windows, boolean_runtime_config"lock_windows") + -- Edge Scrolling options:appendCheckItem(_S.menu_options.edge_scrolling, not app.config.prevent_edge_scrolling, function(item) app.config.prevent_edge_scrolling = not item.checked end, nil, function() return not app.config.prevent_edge_scrolling end) + -- Mouse Capture + options:appendCheckItem(_S.menu_options.capture_mouse, + app.config.capture_mouse, + function(item) app.config.capture_mouse = item.checked + app:saveConfig() + app:setCaptureMouse() + end) + options:appendCheckItem(_S.menu_options.adviser_disabled, not app.config.adviser_disabled, function(item) @@ -700,7 +737,7 @@ end local function overlay(...) local args = {n = select('#', ...), ...} - return function(item, menu) + return function(item, m) if args.n > 0 then app.map:loadDebugText(unpack(args, 1, args.n)) else @@ -722,20 +759,22 @@ if self.ui.app.config.debug then self:addMenu(_S.menu.debug, UIMenu() -- Debug :appendMenu(_S.menu_debug.jump_to_level, levels_menu) + :appendItem(_S.menu_debug.connect_debugger, function() self.ui:connectDebugger() end) :appendCheckItem(_S.menu_debug.limit_camera, true, limit_camera, nil, function() return self.ui.limit_to_visible_diamond end) :appendCheckItem(_S.menu_debug.disable_salary_raise, false, disable_salary_raise, nil, function() return self.ui.app.world.debug_disable_salary_raise end) :appendItem(_S.menu_debug.make_debug_fax, function() self.ui:makeDebugFax() end) :appendItem(_S.menu_debug.make_debug_patient, function() self.ui:addWindow(UIMakeDebugPatient(self.ui)) end) :appendItem(_S.menu_debug.cheats, function() self.ui:addWindow(UICheats(self.ui)) end) :appendItem(_S.menu_debug.lua_console, function() self.ui:addWindow(UILuaConsole(self.ui)) end) + :appendItem(_S.menu_debug.debug_script, function() self.ui:runDebugScript() end) :appendItem(_S.menu_debug.calls_dispatcher, function() self.ui:addWindow(UICallsDispatcher(self.ui)) end) :appendItem(_S.menu_debug.dump_strings, function() self.ui.app:dumpStrings() end) :appendItem(_S.menu_debug.dump_gamelog, function() self.ui.app.world:dumpGameLog() end) :appendMenu(_S.menu_debug.map_overlay, UIMenu() :appendCheckItem(_S.menu_debug_overlay.none, true, overlay(), "") - :appendCheckItem(_S.menu_debug_overlay.flags, false, overlay"flags", "") - :appendCheckItem(_S.menu_debug_overlay.positions, false, overlay"positions", "") - :appendCheckItem(_S.menu_debug_overlay.heat, false, overlay"heat", "") + :appendCheckItem(_S.menu_debug_overlay.flags, false, overlay("flags"), "") + :appendCheckItem(_S.menu_debug_overlay.positions, false, overlay("positions"), "") + :appendCheckItem(_S.menu_debug_overlay.heat, false, overlay("heat"), "") :appendCheckItem(_S.menu_debug_overlay.byte_0_1, false, overlay(35, 8, 0, 1, false), "") :appendCheckItem(_S.menu_debug_overlay.byte_floor, false, overlay(35, 8, 2, 2, false), "") :appendCheckItem(_S.menu_debug_overlay.byte_n_wall, false, overlay(35, 8, 3, 3, false), "") @@ -743,9 +782,9 @@ :appendCheckItem(_S.menu_debug_overlay.byte_5, false, overlay(35, 8, 5, 5, true), "") :appendCheckItem(_S.menu_debug_overlay.byte_6, false, overlay(35, 8, 6, 6, true), "") :appendCheckItem(_S.menu_debug_overlay.byte_7, false, overlay(35, 8, 7, 7, true), "") - :appendCheckItem(_S.menu_debug_overlay.parcel, false, overlay(131107, 2, 0, 0, false), "") + :appendCheckItem(_S.menu_debug_overlay.parcel, false, overlay("parcel"), "") ) - :appendItem(_S.menu_debug.sprite_viewer, function() dofile "sprite_viewer" end) + :appendItem(_S.menu_debug.sprite_viewer, function() corsixth.require("sprite_viewer") end) ) end end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/message.lua corsix-th-0.62/CorsixTH/Lua/dialogs/message.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/message.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/message.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Small fax notification window which sits on the bottom bar. class "UIMessage" (Window) +---@type UIMessage +local UIMessage = _G["UIMessage"] + function UIMessage:UIMessage(ui, x, stop_x, onClose, type, message, owner, timeout, default_choice, callback) self:Window() @@ -59,15 +62,15 @@ self.type = type local types = { emergency = 43, epidemy = 45, strike = 47, personality = 49, information = 51, disease = 53, report = 55 } - local type = types[type] + local kind = types[type] self.can_dismiss = self.type ~= "strike" and #self.message.choices == 1 - self.button = self:addPanel(type, 0, 0) + self.button = self:addPanel(kind, 0, 0) :setTooltip(self.can_dismiss and _S.tooltip.message.button_dismiss or _S.tooltip.message.button) -- FIXME: tooltip doesn't work very well here - :makeToggleButton(0, 0, 30, 28, type + 1, self.openMessage, nil, self.dismissMessage) + :makeToggleButton(0, 0, 30, 28, kind + 1, self.openMessage, nil, self.dismissMessage) -- The emergency has a rotating siren - if type == 43 then + if kind == 43 then self.rotator = {} for i = 57, 60 do self.rotator[i] = self:addPanel(i, 10, 8) @@ -95,8 +98,8 @@ -- Adjust the toggle state to match if the message is open or not function UIMessage:adjustToggle() - if self.button.toggled and not self.fax - or not self.button.toggled and self.fax then + if (self.button.toggled and not self.fax) or + (not self.button.toggled and self.fax) then self.button:toggle() end end @@ -132,7 +135,7 @@ if not self.fax then self.fax = UIFax(self.ui, self) -- NB: just create, don't add to ui end - self.fax:choice(self.message.choices[choice_number].choice) + self.fax:choice(choice_number) else if self.fax then self.fax:close() diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/patient.lua corsix-th-0.62/CorsixTH/Lua/dialogs/patient.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/patient.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/patient.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,9 +18,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" -local math_floor - = math.floor +local TH = require("TH") -- Test for hit within the view circle local --[[persistable:patient_window_is_in_view_circle]] function is_in_view_circle(x, y) @@ -30,6 +28,9 @@ --! Individual patient information dialog class "UIPatient" (Window) +---@type UIPatient +local UIPatient = _G["UIPatient"] + function UIPatient:UIPatient(ui, patient) self:Window() @@ -95,7 +96,12 @@ self:addKeyHandler("H", self.goHome) end +--! Normalise warmth of a patient. +--!param warmth (number or nil) If given, the fraction of warmth of the patient. +--!return (float) Normalized warmth level. function UIPatient.normaliseWarmth(warmth) + if not warmth then return 0.5 end -- Return 1/2 if unknown. + if warmth < 0.08 then warmth = 0 elseif warmth > 0.50 then @@ -106,6 +112,20 @@ return warmth end +--! Draw a bar in the patient dialogue window. +--!param canvas Canvas to draw at. +--!param xbase Horizontal base position. +--!param ybase Vertical base position. +--!param xpos Horizontal offset. +--!param ypos Vertical offset. +--!param value Fraction to draw. +function UIPatient:drawBar(canvas, xbase, ybase, xpos, ypos, value) + local width = math.floor(value * 40 + 0.5) + for dx = 0, width - 1 do + self.panel_sprites:draw(canvas, xbase, xpos + 58 + dx, ypos + ybase) + end +end + function UIPatient:draw(canvas, x_, y_) local x, y = self.x + x_, self.y + y_ local map = self.ui.app.map @@ -133,51 +153,68 @@ self.ui.app.map:draw(canvas, px, py, 75, 76, x + 17, y + 216) Window.draw(self, canvas, x_, y_) - -- The patients happiness. Each bar is by default half way if the actual value - -- cannot be found. - local happiness_bar_width = 22 - if patient.attributes["happiness"] then - happiness_bar_width = math_floor(patient.attributes["happiness"] * 40 + 0.5) - end - if happiness_bar_width ~= 0 then - for dx = 0, happiness_bar_width - 1 do - self.panel_sprites:draw(canvas, 348, x + 58 + dx, y + 126) - end - end - -- The patients thirst level - local thirst_bar_width = 22 - if patient.attributes["thirst"] then - thirst_bar_width = math_floor((1 - patient.attributes["thirst"]) * 40 + 0.5) - end - if thirst_bar_width ~= 0 then - for dx = 0, thirst_bar_width - 1 do - self.panel_sprites:draw(canvas, 351, x + 58 + dx, y + 154) - end - end - -- How warm the patient feels - local warmth_bar_width = 22 - local warmth = patient.attributes["warmth"] - if warmth then - warmth = self.normaliseWarmth(warmth) - warmth_bar_width = math_floor(warmth * 40 + 0.5) - end - if warmth_bar_width ~= 0 then - for dx = 0, warmth_bar_width - 1 do - self.panel_sprites:draw(canvas, 349, x + 58 + dx, y + 183) - end - end + -- The patient bars (happiness, thirst, and warmth). + local warmth = self.normaliseWarmth(patient.attributes["warmth"]) + + self:drawBar(canvas, 348, 126, x, y, patient.attributes["happiness"] or 0.5) + self:drawBar(canvas, 351, 154, x, y, 1 - (patient.attributes["thirst"] or 0.5)) + self:drawBar(canvas, 349, 183, x, y, warmth) if self.history_panel.visible then self:drawTreatmentHistory(canvas, x + 40, y + 25) + elseif patient.health_history then + self:drawHealthHistory(canvas, x, y) end end +--! List the treatments that were performed on the patient. +--!param canvas Destination to draw on. +--!param x (int) X position of the top of the list. +--!param y (int) Y position of the top of the list. function UIPatient:drawTreatmentHistory(canvas, x, y) for _, room in ipairs(self.patient.treatment_history) do y = self.font:drawWrapped(canvas, room, x, y, 95) end end +--! Draw the health graph of the patient. +--!param canvas Destination to draw on. +--!param x (int) X position of the top-left of the graph. +--!param y (int) Y position of the top-left of the graph. +function UIPatient:drawHealthHistory(canvas, x, y) + -- Sizes and positions of the graph in the window. + local hor_length = 76 + local vert_length = 70 + local startx = 58 + local starty = 27 + + -- Health history information. + local hh = self.patient.health_history + local index = hh["last"] + local size = hh["size"] + + local dx = hor_length / size + local line = nil -- Make a line the first time we find a non-nil value. + for _ = 1, size do + index = (index == size) and 1 or (index + 1) + if hh[index] then + local posy = starty + (1.0 - hh[index]) * vert_length + + if not line then + line = TH.line() + line:setWidth(2) + line:setColour(200, 55, 30, 255) + line:moveTo(startx, posy) + else + line:lineTo(startx, posy) + end + end + startx = startx + dx + end + + if line then line:draw(canvas, x, y) end +end + function UIPatient:onMouseDown(button, x, y) self.do_scroll = button == "left" and is_in_view_circle(x, y) return Window.onMouseDown(self, button, x, y) @@ -213,13 +250,18 @@ return Window.onMouseMove(self, x, y, dx, dy) end +--[[! Scrolls the map to the position of the patient which this dialog belongs to ]] +function UIPatient:scrollToPatient() + local ui = self.ui + local patient = self.patient + local px, py = ui.app.map:WorldToScreen(patient.tile_x, patient.tile_y) + local dx, dy = patient.th:getPosition() + ui:scrollMapTo(px + dx, py + dy) +end + function UIPatient:onTick() if self.do_scroll then - local ui = self.ui - local patient = self.patient - local px, py = ui.app.map:WorldToScreen(patient.tile_x, patient.tile_y) - local dx, dy = patient.th:getPosition() - ui:scrollMapTo(px + dx, py + dy) + self:scrollToPatient() end return Window.onTick(self) end @@ -256,14 +298,14 @@ end function UIPatient:viewQueue() - for i, action in ipairs(self.patient.action_queue) do + for _, action in ipairs(self.patient.action_queue) do if action.name == "queue" then self.ui:addWindow(UIQueue(self.ui, action.queue)) - self.ui:playSound "selectx.wav" + self.ui:playSound("selectx.wav") return end end - self.ui:playSound "wrong2.wav" + self.ui:playSound("wrong2.wav") end function UIPatient:goHome() @@ -271,8 +313,8 @@ return end self:close() - self.patient:playSound "sack.wav" - self.patient:goHome() + self.patient:playSound("sack.wav") + self.patient:goHome("kicked") self.patient:updateDynamicInfo(_S.dynamic_info.patient.actions.sent_home) end @@ -284,17 +326,18 @@ function UIPatient:guessDisease() local patient = self.patient -- NB: the first line of conditions should already be ruled out by button being disabled, but just in case - if patient.is_debug or patient.diagnosis_progress == 0 or patient.diagnosed or patient.going_home - or patient:getRoom() or not patient.hospital.disease_casebook[patient.disease.id].discovered then + if patient.is_debug or patient.diagnosis_progress == 0 or patient.diagnosed or + patient.going_home or patient:getRoom() or + not patient.hospital.disease_casebook[patient.disease.id].discovered then self.ui:playSound("wrong2.wav") return end - patient:setDiagnosed(true) - patient:setNextAction({ - name = "seek_room", - room_type = patient.disease.treatment_rooms[1], - treatment_room = true, - }, 1) + patient:setDiagnosed() + if patient:agreesToPay(patient.disease.id) then + patient:setNextAction(SeekRoomAction(patient.disease.treatment_rooms[1]):enableTreatmentRoom(), 1) + else + patient:goHome("over_priced") + end end function UIPatient:hitTest(x, y) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/place_objects.lua corsix-th-0.62/CorsixTH/Lua/dialogs/place_objects.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/place_objects.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/place_objects.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,7 +18,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") local ipairs, math_floor = ipairs, math.floor @@ -30,6 +30,9 @@ --! The dialog shown when placing objects. class "UIPlaceObjects" (Window) +---@type UIPlaceObjects +local UIPlaceObjects = _G["UIPlaceObjects"] + --[[ Constructor for the class. !param ui (UI) The active ui. !param object_list (table) a list of tables with objects to place. Keys are "object", "qty" and @@ -63,8 +66,8 @@ self:addPanel(113, 0, y) -- Desc text box end self:addPanel(114, 0, 90) -- Dialog mid-piece - self:addPanel(115, 0, 100):makeButton(9, 8, 41, 42, 116, self.cancel):setSound"no4.wav":setTooltip(_S.tooltip.place_objects_window.cancel) - self:addKeyHandler("esc", self.cancel) + self:addPanel(115, 0, 100):makeButton(9, 8, 41, 42, 116, self.cancel):setSound("no4.wav"):setTooltip(_S.tooltip.place_objects_window.cancel) + self:addKeyHandler("escape", self.cancel) self.purchase_button = self:addPanel(117, 50, 100):makeButton(1, 8, 41, 42, 118, self.purchaseItems):setTooltip(_S.tooltip.place_objects_window.buy_sell) :setDisabledSprite(127):enable(false) -- Disabled purchase items button @@ -73,7 +76,7 @@ :setDisabledSprite(128):enable(false):makeToggle() -- Disabled pick up items button self.confirm_button = self:addPanel(121, 134, 100):makeButton(1, 8, 43, 42, 122, self.confirm):setTooltip(_S.tooltip.place_objects_window.confirm) - :setDisabledSprite(129):enable(false):setSound"YesX.wav" -- Disabled confirm button + :setDisabledSprite(129):enable(false):setSound("YesX.wav") -- Disabled confirm button self.list_header = self:addPanel(123, 0, 146) -- Object list header self.list_header.visible = false @@ -83,7 +86,7 @@ self.num_slots = 0 self:addObjects(object_list, pay_for) - self:addKeyHandler(" ", self.tryNextOrientation) + self:addKeyHandler("space", self.tryNextOrientation) ui:setWorldHitTest(false) end @@ -101,14 +104,14 @@ end local function idx(i) - return --[[persistable:place_objects_idx1]] function(self) - if i == self.active_index then - self:nextOrientation() + return --[[persistable:place_objects_idx1]] function(window) + if i == window.active_index then + window:nextOrientation() else - self.place_objects = true - self:setActiveIndex(i) + window.place_objects = true + window:setActiveIndex(i) -- Stop picking up items when user presses object in list - local edit_room_window = self.ui:getWindow(UIEditRoom) + local edit_room_window = window.ui:getWindow(UIEditRoom) if edit_room_window and edit_room_window.in_pickup_mode then edit_room_window:stopPickupItems() end @@ -136,7 +139,7 @@ :preservePanel() else -- remove buttons - for i = self.num_slots, num_slots + 1, -1 do + for _ = self.num_slots, num_slots + 1, -1 do -- NB: Two panels per item, the latter being a dummy for the button self.panels[#self.panels] = nil self.panels[#self.panels] = nil @@ -164,27 +167,19 @@ return end - local function idx(i) - return --[[persistable:place_objects_idx2]] function(self) - if i == self.active_index then - self:nextOrientation() - else - self:setActiveIndex(i) - end - end - end - - -- Detect objects already existing in self.objects and increment its quantity rather than adding new objects lines + -- Detect objects already existing in self.objects and increment its quantity + -- rather than adding new objects lines. local new_index = 1 while true do local new_object = object_list[new_index] if not new_object then break end - for index, object in ipairs(self.objects) do + for _, object in ipairs(self.objects) do if new_object.qty > 0 and new_object.object.thob == object.object.thob then object.qty = object.qty + new_object.qty if pay_for then local build_cost = self.ui.hospital:getObjectBuildCost(new_object.object.id) - self.ui.hospital:spendMoney(new_object.qty * build_cost, _S.transactions.buy_object .. ": " .. object.object.name, new_object.qty * build_cost) + local msg = _S.transactions.buy_object .. ": " .. object.object.name + self.ui.hospital:spendMoney(new_object.qty * build_cost, msg, new_object.qty * build_cost) end -- If this is an object that has been created in the world already, add it to the -- associated list of objects to re-place. @@ -218,16 +213,17 @@ self.objects[#self.objects + 1] = object if pay_for then local build_cost = self.ui.hospital:getObjectBuildCost(object.object.id) - self.ui.hospital:spendMoney(object.qty * build_cost, _S.transactions.buy_object .. ": " .. object.object.name, object.qty * build_cost) + local msg = _S.transactions.buy_object .. ": " .. object.object.name + self.ui.hospital:spendMoney(object.qty * build_cost, msg, object.qty * build_cost) end end -- sort list by size of object (number of tiles in the first existing orientation (usually north)) table.sort(self.objects, function(o1, o2) - local orient1 = o1.object.orientations.north or o1.object.orientations.east - or o1.object.orientations.south or o1.object.orientations.west - local orient2 = o2.object.orientations.north or o2.object.orientations.east - or o2.object.orientations.south or o2.object.orientations.west + local orient1 = o1.object.orientations.north or o1.object.orientations.east or + o1.object.orientations.south or o1.object.orientations.west + local orient2 = o2.object.orientations.north or o2.object.orientations.east or + o2.object.orientations.south or o2.object.orientations.west return #orient1.footprint > #orient2.footprint end) @@ -238,9 +234,10 @@ -- precondition: self.active_index has to correspond to the object to be removed function UIPlaceObjects:removeObject(object, dont_close_if_empty, refund) - local build_cost = self.ui.hospital:getObjectBuildCost(object.object.id) if refund then - self.ui.hospital:receiveMoney(build_cost, _S.transactions.sell_object .. ": " .. object.object.name, build_cost) + local build_cost = self.ui.hospital:getObjectBuildCost(object.object.id) + local msg = _S.transactions.sell_object .. ": " .. object.object.name + self.ui.hospital:receiveMoney(build_cost, msg, build_cost) end object.qty = object.qty - 1 @@ -255,7 +252,8 @@ if object.qty == 0 then if #self.objects == 1 then self:clearBlueprint() - self.object_cell_x, self.object_cell_y = nil + self.object_cell_x = nil + self.object_cell_y = nil if dont_close_if_empty then self.list_header.visible = false self.place_objects = false -- No object to place @@ -280,8 +278,8 @@ function UIPlaceObjects:removeAllObjects(refund) -- There is surely a nicer way to implement this than the current hack. Rewrite it sometime later. self:setActiveIndex(1) - for i = 1, #self.objects do - for j = 1, self.objects[1].qty do + for _ = 1, #self.objects do + for _ = 1, self.objects[1].qty do self:removeObject(self.objects[1], true, refund) end end @@ -293,11 +291,11 @@ object_list = {} end - for i, o in ipairs(object_list) do + for _, o in ipairs(object_list) do for j, p in ipairs(self.objects) do if o.object.id == p.object.id then self.active_index = j - for k = 1, o.qty do + for _ = 1, o.qty do self:removeObject(p, true, refund) end end @@ -330,13 +328,14 @@ self.ui:tutorialStep(1, {4, 5}, 6) end local anims = self.anims + local grey_scale = anims.Alt32_GreyScale local _, ghost = self.ui.app.gfx:loadPalette() for _, anim in pairs(object.idle_animations) do - anims:setAnimationGhostPalette(anim, ghost) + anims:setAnimationGhostPalette(anim, ghost, grey_scale) end if object.slave_type then for _, anim in pairs(object.slave_type.idle_animations) do - anims:setAnimationGhostPalette(anim, ghost) + anims:setAnimationGhostPalette(anim, ghost, grey_scale) end end @@ -439,8 +438,8 @@ function UIPlaceObjects:tryNextOrientation() if #self.objects > 0 then - self.ui:playSound "swoosh.wav" - self.objects[self.active_index].orientation_before = self.object_orientation; + self.ui:playSound("swoosh.wav") + self.objects[self.active_index].orientation_before = self.object_orientation self:nextOrientation() end end @@ -474,23 +473,27 @@ end function UIPlaceObjects:placeObject(dont_close_if_empty) - if not self.place_objects then -- We don't want to place objects because we are selecting new objects for adding in a room being built/edited + if not self.place_objects then + -- We don't want to place objects because we are selecting new objects for adding in a room being built/edited return end local object = self.objects[self.active_index] if object.object.id == "reception_desk" then self.ui:tutorialStep(1, 4, "next") end + local real_obj -- There might be an existing object that has been picked up. if object.existing_objects and #object.existing_objects > 0 then real_obj = object.existing_objects[1] table.remove(object.existing_objects, 1) end + local room = self.room or self.world:getRoom(self.object_cell_x, self.object_cell_y) if real_obj then -- If there is such an object then we don't want to make a new one, but move this one instead. if real_obj.orientation_before and real_obj.orientation_before ~= self.object_orientation then real_obj:initOrientation(self.object_orientation) end + self.world:prepareFootprintTilesForBuild(real_obj.footprint, self.object_cell_x, self.object_cell_y) real_obj:setTile(self.object_cell_x, self.object_cell_y) self.world:objectPlaced(real_obj) if real_obj.slave then @@ -498,16 +501,22 @@ end -- Some objects (e.g. the plant) uses this flag to avoid doing stupid things when picked up. real_obj.picked_up = false + -- Machines may have smoke, recalculate it to ensure the animation is in the correct state + if real_obj.strength then + real_obj:calculateSmoke(room) + end else - real_obj = self.world:newObject(object.object.id, self.object_cell_x, - self.object_cell_y, self.object_orientation) + local object_footprint = object.object.orientations[self.object_orientation].footprint + self.world:prepareFootprintTilesForBuild(object_footprint, self.object_cell_x, self.object_cell_y) + real_obj = self.world:newObject(object.object.id, + self.object_cell_x, self.object_cell_y, self.object_orientation) + real_obj:setState(object.state) end - local room = self.room or self.world:getRoom(self.object_cell_x, self.object_cell_y) if room then room.objects[real_obj] = true end - self.ui:playSound "place_r.wav" + self.ui:playSound("place_r.wav") self:removeObject(object, dont_close_if_empty) object.orientation_before = nil @@ -522,15 +531,15 @@ -- Don't show the object if the game is paused if self.world.user_actions_allowed then if not ATTACH_BLUEPRINT_TO_TILE and self.object_cell_x and self.object_anim then - local x, y = self.ui:WorldToScreen(self.object_cell_x, self.object_cell_y) + local xpos, ypos = self.ui:WorldToScreen(self.object_cell_x, self.object_cell_y) local zoom = self.ui.zoom_factor if canvas:scale(zoom) then - x = x / zoom - y = y / zoom + xpos = math.floor(xpos / zoom) + ypos = math.floor(ypos / zoom) end - self.object_anim:draw(canvas, x, y) + self.object_anim:draw(canvas, xpos, ypos) if self.objects[self.active_index].object.slave_type then - self.object_slave_anim:draw(canvas, x, y) + self.object_slave_anim:draw(canvas, xpos, ypos) end canvas:scale(1) end @@ -544,12 +553,12 @@ for i, o in ipairs(self.objects) do local font = self.white_font - local y = y + 136 + i * 29 + local ypos = y + 136 + i * 29 if i == self.active_index then font = self.blue_font end - font:draw(canvas, o.object.name, x + 15, y, 130, 0) - font:draw(canvas, o.qty, x + 151, y, 19, 0) + font:draw(canvas, o.object.name, x + 15, ypos, 130, 0) + font:draw(canvas, o.qty, x + 151, ypos, 19, 0) end end @@ -578,7 +587,6 @@ if x and y and #self.objects > 0 then local object = self.objects[self.active_index].object local object_footprint = object.orientations[self.object_orientation].footprint - local w, h = self.map.width, self.map.height local map = self.map.th if #object_footprint ~= #self.object_footprint then self.object_footprint = {} @@ -596,6 +604,7 @@ local allgood = true local opt_tiles_blocked = 0 local world = self.ui.app.world + local player_id = self.ui.hospital:getPlayerIndex() local roomId = self.room and self.room.id local passable_flag local direction = self.object_orientation @@ -606,6 +615,8 @@ west = { x = -1, y = 0, buildable_flag = "buildableWest", passable_flag = "travelWest", needed_side = "need_west_side"} } + -- The given footprint tile is not usable, update the external 'allgood' + -- variable accordingly. local function setAllGood(xy) if xy.optional then opt_tiles_blocked = opt_tiles_blocked + 1 @@ -617,21 +628,22 @@ end end - for i, xy in ipairs(object_footprint) do - local x = x + xy[1] - local y = y + xy[2] - if x < 1 or x > w or y < 1 or y > h then - setAllGood(xy) - x = 0 - y = 0 + for i, tile in ipairs(object_footprint) do + local xpos = x + tile[1] + local ypos = y + tile[2] + -- Check 1: Does the tile have valid map coordinates?: + if not world:isOnMap(xpos, ypos) then + setAllGood(tile) + xpos = 0 + ypos = 0 else local flag = "buildable" local good_tile = 24 + flag_alpha75 local bad_tile = 67 + flag_alpha75 - if xy.only_passable then + if tile.only_passable then flag = "passable" end - if xy.only_side then + if tile.only_side then if object.thob == 50 and direction == "east" then direction = "west" end @@ -639,121 +651,45 @@ passable_flag = direction_parameters[direction]["passable_flag"] end - local cell_flags = map:getCellFlags(x, y, flags)[flag] - local is_object_allowed = false - if roomId and flags.roomId ~= roomId then - is_object_allowed = false - elseif flags.roomId == 0 and object.corridor_object then - is_object_allowed = true - roomId = flags.roomId - elseif flags.roomId == 0 and not object.corridor_object then - is_object_allowed = false - else - roomId = flags.roomId - for _, o in pairs(world.rooms[roomId].room_info.objects_additional) do - if TheApp.objects[o].thob == object.thob then - is_object_allowed = true - break - end - end - for o, num in pairs(world.rooms[roomId].room_info.objects_needed) do - if TheApp.objects[o].thob == object.thob then - is_object_allowed = true - break - end - end - end - - local function isTileValid(x, y, complete_cell, flags, flag_name, need_side) - if complete_cell or need_side then - return flags[flag_name] - end - for i, xy in ipairs(object_footprint) do - if(xy[1] == x and xy[2] == y) then - return flags[flag_name] - end - end - return true - end - - if cell_flags and not xy.only_side then - for _, value in pairs(direction_parameters) do - local x1, y1 = xy[1] + value["x"], xy[2] + value["y"] - if not isTileValid(x1, y1, xy.complete_cell, flags, value["buildable_flag"], xy[value["needed_side"]]) then - is_object_allowed = false - break - end - end - end - - if cell_flags and is_object_allowed then - if not xy.invisible then - map:setCell(x, y, 4, good_tile) + -- Check 2: Is the tile in the object's allowed room?: + local result = world:willObjectsFootprintTileBeWithinItsAllowedRoomIfLocatedAt(xpos, ypos, object, roomId) + local is_object_allowed = result.within_room + roomId = result.roomId + + -- Check 3: The footprint tile should either be buildable or passable, is it?: + if not tile.only_side and is_object_allowed then + is_object_allowed = world:isFootprintTileBuildableOrPassable(xpos, ypos, tile, object_footprint, flag, player_id) + elseif is_object_allowed then + is_object_allowed = map:getCellFlags(xpos, ypos, flags)[flag] and (player_id == 0 or flags.owner == player_id) + end + + -- ignore placed object tile if it is shareable + if not tile.shareable and is_object_allowed then + -- Check 4: only one object per tile allowed original TH + -- can build on litter and unoccupied tiles and only placeable if not on another objects passable footprint unless that too is a shareable tile + local objchk = map:getCellFlags(xpos, ypos, flags)["thob"] + is_object_allowed = objchk == 0 or objchk == 62 or objchk == 64 -- no object, litter/puke, ratholes + is_object_allowed = is_object_allowed and world:isTileExclusivelyPassable(xpos, ypos, 10) + end + + -- Having checked if the tile is good set its blueprint appearance flag: + if is_object_allowed then + if not tile.invisible then + map:setCell(xpos, ypos, 4, good_tile) end else - if not xy.invisible then - map:setCell(x, y, 4, bad_tile) + if not tile.invisible then + map:setCell(xpos, ypos, 4, bad_tile) end - setAllGood(xy) + setAllGood(tile) end end - self.object_footprint[i][1] = x - self.object_footprint[i][2] = y + self.object_footprint[i][1] = xpos + self.object_footprint[i][2] = ypos end if self.object_anim and object.class ~= "SideObject" then if allgood then - -- Check that pathfinding still works, i.e. that placing the object - -- wouldn't disconnect one part of the hospital from another. To do - -- this, we provisionally mark the footprint as unpassable (as it will - -- become when the object is placed), and then check that the cells - -- surrounding the footprint have not had their connectedness changed. - local function setPassable(passable) - local flags_to_set = {passable = passable} - for _, xy in ipairs(object_footprint) do - local x = x + xy[1] - local y = y + xy[2] - if not xy.only_passable then - map:setCellFlags(x, y, flags_to_set) - end - end - end - local function isIsolated(x, y) - setPassable(true) - local result = not world.pathfinder:isReachableFromHospital(x, y) - setPassable(false) - return result - end - setPassable(false) - local prev_x, prev_y - for _, xy in ipairs(object.orientations[self.object_orientation].adjacent_to_solid_footprint) do - local x = x + xy[1] - local y = y + xy[2] - if map:getCellFlags(x, y, flags).roomId == roomId and flags.passable then - if prev_x then - if not world.pathfinder:findDistance(x, y, prev_x, prev_y) then - -- There is no route between the two map nodes. In most cases, - -- this means that connectedness has changed, though there is - -- one rare situation where the above test is insufficient. If - -- (x, y) is a passable but isolated node outside the hospital - -- and (prev_x, prev_y) is in the corridor, then the two will - -- not be connected now, but critically, neither were they - -- connected before. - if not isIsolated(x, y) then - if not isIsolated(prev_x, prev_y) then - allgood = false - break - end - else - x = prev_x - y = prev_y - end - end - end - prev_x = x - prev_y = y - end - end - setPassable(true) + allgood = not world:wouldNonSideObjectBreakPathfindingIfSpawnedAt(x, y, object, self.object_orientation, roomId) end if ATTACH_BLUEPRINT_TO_TILE then self.object_anim:setTile(map, x, y) @@ -821,7 +757,7 @@ local object = self.objects[self.active_index].object local room = self.room local wx, wy = self.ui:ScreenToWorld(self.x + x, self.y + y) - local bestd + local bestd = nil local bestx, besty = wx, wy local besto = self.object_orientation if room and object.locked_to_wall then @@ -838,15 +774,15 @@ room.x + 0.5, room.y + room.height - 0.5, wx, wy) local d = ((px - wx)^2 + (py - wy)^2)^0.5 if not bestd or d < bestd then - bestd, bestx, besty, besto = d, px, py, object.locked_to_wall.west + bestx, besty, besto = px, py, object.locked_to_wall.west end end -- TODO: East, South end bestx, besty = math_floor(bestx), math_floor(besty) - if bestx < 1 or besty < 1 - or bestx > self.map.width or besty > self.map.height then - bestx, besty = nil + if bestx < 1 or besty < 1 or + bestx > self.map.width or besty > self.map.height then + bestx, besty = nil, nil end return bestx, besty, besto end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/place_staff.lua corsix-th-0.62/CorsixTH/Lua/dialogs/place_staff.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/place_staff.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/place_staff.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,11 +20,14 @@ local math_floor = math.floor -local TH = require "TH" +local TH = require("TH") --! Invisible window which handles placing a `Staff` member in the world. class "UIPlaceStaff" (Window) +---@type UIPlaceStaff +local UIPlaceStaff = _G["UIPlaceStaff"] + function UIPlaceStaff:UIPlaceStaff(ui, profile, x, y) self.ui = ui self.world = ui.app.world @@ -43,7 +46,8 @@ local idle_anim = Humanoid.getIdleAnimation(profile.humanoid_class) self.anim:setAnimation(self.world.anims, idle_anim) local _, ghost = ui.app.gfx:loadPalette() - self.world.anims:setAnimationGhostPalette(idle_anim, ghost) + local grey_scale = self.world.anims.Alt32_GreyScale + self.world.anims:setAnimationGhostPalette(idle_anim, ghost, grey_scale) self:onCursorWorldPositionChange(x, y) self:Window() end @@ -52,8 +56,8 @@ if self.staff then self.staff.pickup = false self.staff.going_to_staffroom = nil - self.staff.action_queue[1].window = nil - self.staff:setNextAction{name = "meander"} + self.staff:getCurrentAction().window = nil + self.staff:setNextAction(MeanderAction()) elseif self.profile then self.ui:tutorialStep(2, {6, 7}, 1) self.ui:tutorialStep(4, {4, 5}, 1) @@ -61,7 +65,7 @@ local staff_pool = self.world.available_staff[self.profile.humanoid_class] staff_pool[#staff_pool + 1] = self.profile end - self.ui:playSound "plac_st2.wav" + self.ui:playSound("plac_st2.wav") Window.close(self) end @@ -77,14 +81,16 @@ if self.world.user_actions_allowed then self.world.map.th:getCellFlags(self.tile_x, self.tile_y, flag_cache) local room = self.world:getRoom(self.tile_x, self.tile_y) + local player_id = self.ui.hospital:getPlayerIndex() local valid = flag_cache.hospital and flag_cache.passable and - (self.allow_in_rooms or flag_cache.roomId == 0) and - (not room and true or not room.crashed) + (self.allow_in_rooms or flag_cache.roomId == 0) and + (not room and true or not room.crashed) and + flag_cache.owner == player_id self.anim:setFlag(valid and 0 or flag_altpal) local zoom = self.ui.zoom_factor if canvas:scale(zoom) then local x, y = self.ui:WorldToScreen(self.tile_x, self.tile_y) - self.anim:draw(canvas, x / zoom, y / zoom) + self.anim:draw(canvas, math.floor(x / zoom), math.floor(y / zoom)) canvas:scale(1) else self.anim:draw(canvas, self.ui:WorldToScreen(self.tile_x, self.tile_y)) @@ -103,9 +109,11 @@ self:onMouseMove(x, y) self.world.map.th:getCellFlags(self.tile_x, self.tile_y, flag_cache) local room = self.world:getRoom(self.tile_x, self.tile_y) - if flag_cache.hospital and flag_cache.passable - and (self.allow_in_rooms or flag_cache.roomId == 0) - and (not room and true or not room.crashed) then + local player_id = self.ui.hospital:getPlayerIndex() + if flag_cache.hospital and flag_cache.passable and + (self.allow_in_rooms or flag_cache.roomId == 0) and + (not room or not room.crashed) and + flag_cache.owner == player_id then if self.staff then self.staff:setTile(self.tile_x, self.tile_y) else @@ -115,9 +123,9 @@ entity:setTile(self.tile_x, self.tile_y) self.ui.hospital:addStaff(entity) entity:setHospital(self.ui.hospital) - local room = entity:getRoom() - if room then - room:onHumanoidEnter(entity) + local entity_room = entity:getRoom() + if entity_room then + entity_room:onHumanoidEnter(entity) else entity:onPlaceInCorridor() end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/queue_dialog.lua corsix-th-0.62/CorsixTH/Lua/dialogs/queue_dialog.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/queue_dialog.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/queue_dialog.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,13 +18,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" -local math_floor - = math.floor +local TH = require("TH") --! Room / door / reception desk queue visualisation dialog. class "UIQueue" (Window) +---@type UIQueue +local UIQueue = _G["UIQueue"] + function UIQueue:UIQueue(ui, queue) self:Window() @@ -60,14 +61,14 @@ self:makeTooltip(_S.tooltip.queue_window.front_of_queue, 168, 25, 213, 105) self:makeTooltip(_S.tooltip.queue_window.end_of_queue, 543, 51, 586, 105) - self:makeTooltip(_S.tooltip.queue_window.patient .. " " .. _S.misc.not_yet_implemented, 218, 15, 537, 107) + self:makeTooltip(_S.tooltip.queue_window.patient .. " " .. _S.misc.not_yet_implemented, 218, 15, 537, 107) end function UIQueue:decreaseMaxSize() local amount = 1 - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then amount = amount * 10 - elseif self.buttons_down.shift then + elseif self.ui.app.key_modifiers.shift then amount = amount * 5 end self.queue:decreaseMaxSize(amount) @@ -75,9 +76,9 @@ function UIQueue:increaseMaxSize() local amount = 1 - if self.buttons_down.ctrl then + if self.ui.app.key_modifiers.ctrl then amount = amount * 10 - elseif self.buttons_down.shift then + elseif self.ui.app.key_modifiers.shift then amount = amount * 5 end self.queue:increaseMaxSize(amount) @@ -95,7 +96,7 @@ font:draw(canvas, num_patients, x + 140, y + 22) font:draw(canvas, _S.queue_window.num_expected, x + 22, y + 45) - font:draw(canvas, queue.expected_count, x + 140, y + 45) + font:draw(canvas, queue:expectedSize(), x + 140, y + 45) font:draw(canvas, _S.queue_window.num_entered, x + 22, y + 68) font:draw(canvas, queue.visitor_count, x + 140, y + 68) @@ -111,7 +112,7 @@ end end -function UIQueue:isInsideQueueBoundingBox(x, y) +local function isInsideQueueBoundingBox(x, y) local x_min = 219 local x_max = 534 local y_min = 15 @@ -121,7 +122,7 @@ function UIQueue:onMouseDown(button, x, y) -- Allow normal window operations if the mouse is outside the listing of patients - if not self:isInsideQueueBoundingBox(x, y) then + if not isInsideQueueBoundingBox(x, y) then return Window.onMouseDown(self, button, x, y) end local x_min = 219 @@ -179,10 +180,10 @@ queue:move(index, 1) -- move to front elseif x > 542 and x < 585 and y > 50 and y < 105 then -- Inside exit sign bounding box queue:move(index, num_patients) -- move to back - elseif self:isInsideQueueBoundingBox(x, y) then -- Inside queue bounding box + elseif isInsideQueueBoundingBox(x, y) then local dx = 1 if num_patients ~= 1 then - dx = width / (num_patients - 1) + dx = math.floor(width / (num_patients - 1)) end queue:move(index, math.floor((x - 220) / dx) + 1) -- move to dropped position self:onMouseMove(x, y, 0, 0) @@ -226,7 +227,7 @@ self.ui:setCursor(self.ui.app.gfx:loadMainCursor("queue_drag")) end end - if not self:isInsideQueueBoundingBox(x, y) then + if not isInsideQueueBoundingBox(x, y) then self.hovered = nil Window:onMouseMove(x, y, dx, dy) return @@ -255,7 +256,7 @@ local dx = 0 if num_patients ~= 1 then - dx = width / (num_patients - 1) + dx = math.floor(width / (num_patients - 1)) end local offset = 0 @@ -295,7 +296,7 @@ if not self.hovered then if num_patients ~= 1 then - dx = width / (num_patients - 1) + dx = math.floor(width / (num_patients - 1)) end for index = 1, num_patients do @@ -304,7 +305,7 @@ end else if num_patients ~= 1 then - dx = (width - 2 * gap) / (num_patients - 1) + dx = math.floor((width - 2 * gap) / (num_patients - 1)) end x = x + 239 @@ -340,6 +341,9 @@ class "UIQueuePopup" (Window) +---@type UIQueuePopup +local UIQueuePopup = _G["UIQueuePopup"] + function UIQueuePopup:UIQueuePopup(ui, x, y, patient) self:Window() self.esc_closes = true @@ -354,27 +358,10 @@ -- Background sprites self:addPanel(375, 0, 0) - local function send_to_hospital(i) - return --[[persistable:queue_dialog_popup_hospital_button]] function() - -- TODO: Actually send to another hospital (when they exist) - self.patient:goHome() - local str = _S.dynamic_info.patient.actions.sent_to_other_hospital - self.patient:updateDynamicInfo(str) - self:close() - end - end - -- Buttons self:addPanel(0, 12, 12):makeButton(0, 0, 81, 54, 378, self.sendToReception) self:addPanel(0, 95, 12):makeButton(0, 0, 81, 54, 379, self.sendHome) - local bottom = 58 - -- TODO: Add this when there are other hospitals to send patients to. - --[[for i, hospital in ipairs(ui.app.world.hospitals) do - self:addPanel(376, 0, 68 + (i-1)*34) - self:addPanel(0, 12, 34 + i*34):makeButton(0, 0, 164, 32, 380, send_to_hospital(i)) - bottom = bottom + 34 - end]] - self:addPanel(377, 0, bottom) + self:addPanel(377, 0, 58) self.panel_sprites = app.gfx:loadSpriteTable("QData", "Req06V", true) self.white_font = app.gfx:loadFont("QData", "Font01V") @@ -382,19 +369,19 @@ function UIQueuePopup:draw(canvas, x, y) Window.draw(self, canvas, x, y) - x, y = self.x + x, self.y + y -- TODO: Same as above. + -- x, y = self.x + x, self.y + y --[[for i, hospital in ipairs(self.ui.app.world.hospitals) do self.white_font:draw(canvas, hospital.name:upper() , x + 74, y + 78 + (i-1)*34, 92, 0) end]] end function UIQueuePopup:sendToReception() - self.patient:setNextAction{name = "seek_reception"} + self.patient:setNextAction(SeekReceptionAction()) self:close() end function UIQueuePopup:sendHome() - self.patient:goHome() + self.patient:goHome("kicked") self:close() end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizable.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizable.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizable.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizable.lua 2018-07-21 11:13:17.000000000 +0000 @@ -23,6 +23,9 @@ --any of the corners. class "UIResizable" (Window) +---@type UIResizable +local UIResizable = _G["UIResizable"] + local border_offset_x = 9 local border_offset_y = 9 local border_size_x = 40 @@ -84,22 +87,22 @@ local sprites = self.border_sprites if sprites then local draw = sprites.draw - local x = self.x + x - local y = self.y + y + local xabs = self.x + x + local yabs = self.y + y canvas:nonOverlapping(true) - draw(sprites, canvas, 10, x + self.border_pos.left , y + self.border_pos.upper) -- upper left corner - draw(sprites, canvas, 12, x + self.border_pos.corner_right, y + self.border_pos.upper) -- upper right corner - draw(sprites, canvas, 15, x + self.border_pos.left , y + self.border_pos.corner_lower) -- lower left corner - draw(sprites, canvas, 17, x + self.border_pos.corner_right, y + self.border_pos.corner_lower) -- lower right corner - - for x = x + border_size_x, x + self.border_pos.corner_right - 1, border_size_x do - draw(sprites, canvas, 11, x, y + self.border_pos.upper) -- upper edge - draw(sprites, canvas, 16, x, y + self.border_pos.lower) -- lower edge + draw(sprites, canvas, 10, xabs + self.border_pos.left , yabs + self.border_pos.upper) -- upper left corner + draw(sprites, canvas, 12, xabs + self.border_pos.corner_right, yabs + self.border_pos.upper) -- upper right corner + draw(sprites, canvas, 15, xabs + self.border_pos.left , yabs + self.border_pos.corner_lower) -- lower left corner + draw(sprites, canvas, 17, xabs + self.border_pos.corner_right, yabs + self.border_pos.corner_lower) -- lower right corner + + for xpos = xabs + border_size_x, xabs + self.border_pos.corner_right - 1, border_size_x do + draw(sprites, canvas, 11, xpos, yabs + self.border_pos.upper) -- upper edge + draw(sprites, canvas, 16, xpos, yabs + self.border_pos.lower) -- lower edge end - for y = y + border_size_y, y + self.border_pos.corner_lower - 1, border_size_y do - draw(sprites, canvas, 13, x + self.border_pos.left, y) -- left edge - draw(sprites, canvas, 14, x + self.border_pos.right, y) -- right edge + for ypos = yabs + border_size_y, yabs + self.border_pos.corner_lower - 1, border_size_y do + draw(sprites, canvas, 13, xabs + self.border_pos.left, ypos) -- left edge + draw(sprites, canvas, 14, xabs + self.border_pos.right, ypos) -- right edge end canvas:nonOverlapping(false) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/calls_dispatcher.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/calls_dispatcher.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/calls_dispatcher.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/calls_dispatcher.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Calls Dispatcher Window class "UICallsDispatcher" (UIResizable) +---@type UICallsDispatcher +local UICallsDispatcher = _G["UICallsDispatcher"] + local col_bg = { red = 154, green = 146, @@ -68,13 +71,13 @@ if rows ~= self.rows_shown then local function assigned_factory(num) - return --[[persistable:calls_dispatcher_assigned_button]] function(self) - self:itemButtonClicked(num) + return --[[persistable:calls_dispatcher_assigned_button]] function(window) + window:itemButtonClicked(num) end end local function task_factory(num) - return --[[persistable:calls_dispatcher_task_button]] function(self) - self:itemButtonClicked(num) + return --[[persistable:calls_dispatcher_task_button]] function(window) + window:itemButtonClicked(num) end end local callback = --[[persistable:calls_dispatcher_scrollbar]] function() @@ -112,8 +115,8 @@ function UICallsDispatcher:update() self.call_list = {} local assigned = 0 - for object, queue in pairs(self.dispatcher.call_queue) do - for key, call in pairs(queue) do + for _, queue in pairs(self.dispatcher.call_queue) do + for _, call in pairs(queue) do table.insert(self.call_list, call) if call.assigned then assigned = assigned + 1 diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/cheats.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/cheats.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/cheats.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/cheats.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! A dialog for activating cheats class "UICheats" (UIResizable) +---@type UICheats +local UICheats = _G["UICheats"] + local col_bg = { red = 154, green = 146, @@ -59,6 +62,8 @@ {name = "money", func = self.cheatMoney}, {name = "all_research", func = self.cheatResearch}, {name = "emergency", func = self.cheatEmergency}, + {name = "epidemic", func = self.cheatEpidemic}, + {name = "toggle_infected", func = self.cheatToggleInfected}, {name = "vip", func = self.cheatVip}, {name = "earthquake", func = self.cheatEarthquake}, {name = "create_patient", func = self.cheatPatient}, @@ -66,6 +71,8 @@ {name = "end_year", func = self.cheatYear}, {name = "lose_level", func = self.cheatLose}, {name = "win_level", func = self.cheatWin}, + {name = "increase_prices", func = self.cheatIncreasePrices}, + {name = "decrease_prices", func = self.cheatDecreasePrices}, } @@ -73,7 +80,6 @@ self.default_button_sound = "selectx.wav" - local app = ui.app self.modal_class = "cheats" self.esc_closes = true self.resizable = false @@ -90,8 +96,8 @@ self.cheated_panel = self:addBevelPanel(20, y, 260, 18, col_cheated_no, col_border, col_border) local function button_clicked(num) - return --[[persistable:cheats_button]] function(self) - self:buttonClicked(num) + return --[[persistable:cheats_button]] function(window) + window:buttonClicked(num) end end @@ -158,6 +164,31 @@ end end +--[[ Creates a new contagious patient in the hospital - potentially an epidemic]] +function UICheats:cheatEpidemic() + self.ui.hospital:spawnContagiousPatient() +end + +--[[ Before an epidemic has been revealed toggle the infected icons +to easily distinguish the infected patients -- will toggle icons +for ALL future epidemics you cannot distingush between epidemics +by disease ]] +function UICheats:cheatToggleInfected() + local hospital = self.ui.hospital + if hospital.future_epidemics_pool and #hospital.future_epidemics_pool > 0 then + for _, future_epidemic in ipairs(hospital.future_epidemics_pool) do + local show_mood = future_epidemic.cheat_always_show_mood + future_epidemic.cheat_always_show_mood = not show_mood + local mood_action = show_mood and "deactivate" or "activate" + for _, patient in ipairs(future_epidemic.infected_patients) do + patient:setMood("epidemy4",mood_action) + end + end + else + print("Unable to toggle icons - no epidemics in progress that are not revealed") + end +end + function UICheats:cheatVip() self.ui.hospital:createVip() end @@ -186,6 +217,30 @@ self.ui.app.world:winGame(1) -- TODO adjust for multiplayer end +function UICheats:cheatIncreasePrices() + local hosp = self.ui.app.world.hospitals[1] + for _, casebook in pairs(hosp.disease_casebook) do + local new_price = casebook.price + 0.5 + if new_price > 2 then + casebook.price = 2 + else + casebook.price = new_price + end + end +end + +function UICheats:cheatDecreasePrices() + local hosp = self.ui.app.world.hospitals[1] + for _, casebook in pairs(hosp.disease_casebook) do + local new_price = casebook.price - 0.5 + if new_price < 0.5 then + casebook.price = 0.5 + else + casebook.price = new_price + end + end +end + function UICheats:buttonBack() self:close() end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/customise.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/customise.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/customise.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/customise.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,30 +21,15 @@ --! Customise window used in the main menu and ingame. class "UICustomise" (UIResizable) +---@type UICustomise +local UICustomise = _G["UICustomise"] + local col_bg = { red = 154, green = 146, blue = 198, } -local col_button = { - red = 84, - green = 200, - blue = 84, -} - -local col_textbox = { - red = 0, - green = 0, - blue = 0, -} - -local col_highlight = { - red = 174, - green = 166, - blue = 218, -} - local col_shadow = { red = 134, green = 126, diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/directory_browser.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/directory_browser.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/directory_browser.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/directory_browser.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,12 +18,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local lfs = require "lfs" +local lfs = require("lfs") +local TH = require("TH") +local lfsext = TH.lfsExt() --! A tree node representing a directory in the physical file-system. class "DirTreeNode" (FileTreeNode) -local pathsep = package.config:sub(1, 1) +---@type DirTreeNode +local DirTreeNode = _G["DirTreeNode"] function DirTreeNode:DirTreeNode(path) self:FileTreeNode(path) @@ -31,10 +34,10 @@ function DirTreeNode:isValidFile(name) -- Check parent criteria and that it's a directory. - if FileTreeNode.isValidFile(self, name) - and lfs.attributes(self:childPath(name), "mode") == "directory" then + if FileTreeNode.isValidFile(self, name) and + lfs.attributes(self:childPath(name), "mode") == "directory" then -- Make sure that we are allowed to read the directory. - local status, result = pcall(lfs.dir, self:childPath(name)) + local status, _ = pcall(lfs.dir, self:childPath(name)) return status end end @@ -53,6 +56,9 @@ --! This tree only shows directories and highlights valid TH directories. class "InstallDirTreeNode" (DirTreeNode) +---@type InstallDirTreeNode +local InstallDirTreeNode = _G["InstallDirTreeNode"] + function InstallDirTreeNode:InstallDirTreeNode(path) self:FileTreeNode(path) end @@ -97,6 +103,9 @@ --! Prompter for Theme Hospital install directory class "UIDirectoryBrowser" (UIResizable) +---@type UIDirectoryBrowser +local UIDirectoryBrowser = _G["UIDirectoryBrowser"] + --! Creates a new directory browser window --!param ui The active UI to hook into. --!param mode Whether the dialog has been opened from the main_menu or somewhere else. Currently @@ -137,14 +146,14 @@ else self.font = ui.app.gfx:loadBuiltinFont() self:setDefaultPosition(0.05, 0.5) - self:addKeyHandler("esc", self.exit) + self:addKeyHandler("escape", self.exit) self.exit_button:setLabel(_S.install.exit, self.font):makeButton(0, 0, 100, 18, nil, self.exit) end -- Create the root item (or items, on Windows), and set it as the -- first_visible_node. local root - local roots = lfs.volumes() + local roots = lfsext.volumes() if #roots > 1 then for k, v in pairs(roots) do roots[k] = _G[treenode_class](v) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/dropdown.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/dropdown.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/dropdown.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/dropdown.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Dropdown "window" used for selection of one item from a list. class "UIDropdown" (UIResizable) +---@type UIDropdown +local UIDropdown = _G["UIDropdown"] + --! Constructor for the dropdown "window" --!param ui (UI) The ui the window is created in --!param parent_window (Window) The window that this dropdown will be attached to @@ -34,7 +37,6 @@ local col = colour or parent_window.colour self:UIResizable(ui, 1, 1, col, true, true) - local app = ui.app self.modal_class = "dropdown" self.esc_closes = true self.resizable = false diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browser.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browser.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browser.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browser.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,13 +18,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local lfs = require "lfs" +local lfs = require("lfs") --! A tree node representing a file (or directory) in the physical file-system -- that meets a given file extension criterion. class "FilteredFileTreeNode" (FileTreeNode) -local pathsep = package.config:sub(1, 1) +---@type FilteredFileTreeNode +local FilteredFileTreeNode = _G["FilteredFileTreeNode"] function FilteredFileTreeNode:FilteredFileTreeNode(path, filter) self:FileTreeNode(path) @@ -75,10 +76,13 @@ return label end ---! A sortable tree control that accomodates a certain file type and also possibly shows +--! A sortable tree control that accommodates a certain file type and also possibly shows -- their last modification dates. class "FilteredTreeControl" (TreeControl) +---@type FilteredTreeControl +local FilteredTreeControl = _G["FilteredTreeControl"] + function FilteredTreeControl:FilteredTreeControl(root, x, y, width, height, col_bg, col_fg, has_font, show_dates) self:TreeControl(root, x, y, width, height, col_bg, col_fg, 14, has_font) @@ -146,18 +150,15 @@ --! A file browser with a scrollbar. Used by load_game and save_game. class "UIFileBrowser" (UIResizable) +---@type UIFileBrowser +local UIFileBrowser = _G["UIFileBrowser"] + local col_caption = { red = 174, green = 166, blue = 218, } -local col_scrollbar = { - red = 164, - green = 156, - blue = 208, -} - --[[ Constructs the dialog. !param ui (UI) The active ui. !param mode (string) Either "menu" or "game" depending on which mode the game is in right now. @@ -179,7 +180,6 @@ self.default_button_sound = "selectx.wav" - local app = ui.app self.mode = mode self.modal_class = mode == "menu" and "main menu" or "saveload" self.on_top = mode == "menu" @@ -194,12 +194,7 @@ self.control = FilteredTreeControl(root, 5, 35, h_size - 10, vertical_size, self.col_bg, self.col_scrollbar, true, show_dates) :setSelectCallback(--[[persistable:file_browser_select_callback]] function(node) if node.is_valid_file and (lfs.attributes(node.path, "mode") ~= "directory") then - local name = node.label - while (node.parent.parent) do - name = node.parent.label .. pathsep .. name - node = node.parent - end - self:choiceMade(name) + self:choiceMade(node.path) end end) self:addWindow(self.control) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/choose_font.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/choose_font.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/choose_font.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/choose_font.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,33 +18,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +local TH = require("TH") +local lfsext = TH.lfsExt() + --! Window where the user can choose a font file. class "UIChooseFont" (UIFileBrowser) -local pathsep = package.config:sub(1, 1) - -local col_textbox = { - red = 0, - green = 0, - blue = 0, -} - -local col_highlight = { - red = 174, - green = 166, - blue = 218, -} - -local col_shadow = { - red = 134, - green = 126, - blue = 178, -} +---@type UIChooseFont +local UIChooseFont = _G["UIChooseFont"] function UIChooseFont:UIChooseFont(ui, mode) -- Create the root item (or items, on Windows). local root - local roots = lfs.volumes() + local roots = lfsext.volumes() if #roots > 1 then for k, v in pairs(roots) do roots[k] = FilteredFileTreeNode(v, {".ttc", ".otf", ".ttf"}) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/load_game.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/load_game.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/load_game.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/load_game.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Load Game Window class "UILoadGame" (UIFileBrowser) +---@type UILoadGame +local UILoadGame = _G["UILoadGame"] + function UILoadGame:UILoadGame(ui, mode) local treenode = FilteredFileTreeNode(ui.app.savegame_dir, ".sav") treenode.label = "Saves" diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/load_map.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/load_map.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/load_map.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/load_map.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,56 @@ +--[[ Copyright (c) 2010 Manuel "Roujin" Wolf + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +--! Load Map Window +class "UILoadMap" (UIFileBrowser) + +---@type UILoadMap +local UILoadMap = _G["UILoadMap"] + +function UILoadMap:UILoadMap(ui, mode) + local path = ui.app.user_level_dir + local treenode = FilteredFileTreeNode(path, ".map") + treenode.label = "Maps" + self:UIFileBrowser(ui, mode, _S.load_game_window.caption:format(".map"), 295, treenode, true) + -- The most probable preference of sorting is by date - what you played last + -- is the thing you want to play soon again. + self.control:sortByDate() +end + +function UILoadMap:choiceMade(name) + local app = self.ui.app + -- Make sure there is no blue filter active. + app.video:setBlueFilterActive(false) + name = name:sub(app.user_level_dir:len() + 1) + local status, err = pcall(app.loadLevel, app, name, nil, nil, nil, nil, true) + if not status then + err = _S.errors.load_prefix .. err + print(err) + app:loadMainMenu() + app.ui:addWindow(UIInformation(self.ui, {err})) + end +end + +function UILoadMap:close() + UIResizable.close(self) + if self.mode == "menu" then + self.ui:addWindow(UIMainMenu(self.ui)) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/save_game.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/save_game.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/save_game.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/save_game.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,7 +21,8 @@ --! Save Game Window class "UISaveGame" (UIFileBrowser) -local pathsep = package.config:sub(1, 1) +---@type UISaveGame +local UISaveGame = _G["UISaveGame"] local col_textbox = { red = 0, @@ -65,11 +66,12 @@ --! Function called when textbox is confirmed (e.g. by pressing enter) function UISaveGame:confirmName() local filename = self.new_savegame_textbox.text + local app = self.ui.app if filename == "" then self:abortName() return end - self:trySave(filename .. ".sav") + self:trySave(app.savegame_dir .. filename .. ".sav") end --! Function called by clicking button of existing save #num @@ -79,7 +81,7 @@ --! Try to save the game with given filename; if already exists, create confirmation window first. function UISaveGame:trySave(filename) - if lfs.attributes(self.ui.app.savegame_dir .. filename, "size") ~= nil then + if lfs.attributes(filename, "size") ~= nil then self.ui:addWindow(UIConfirmDialog(self.ui, _S.confirmation.overwrite_save, --[[persistable:save_game_confirmation]] function() self:doSave(filename) end)) else self:doSave(filename) diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/save_map.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/save_map.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/file_browsers/save_map.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/file_browsers/save_map.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,104 @@ +--[[ Copyright (c) 2015 Stephen E. Baker et al. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +--! Save Map Window +class "UISaveMap" (UIFileBrowser) + +---@type UISaveMap +local UISaveMap = _G["UISaveMap"] + +local col_textbox = { + red = 0, + green = 0, + blue = 0, +} + +local col_highlight = { + red = 174, + green = 166, + blue = 218, +} + +local col_shadow = { + red = 134, + green = 126, + blue = 178, +} + +function UISaveMap:UISaveMap(ui) + local treenode = FilteredFileTreeNode(ui.app.user_level_dir, ".map") + treenode.label = "Maps" + self:UIFileBrowser(ui, "map", _S.save_map_window.caption:format(".map"), 265, treenode, true) + -- The most probable preference of sorting is by date - what you played last + -- is the thing you want to play soon again. + self.control:sortByDate() + + -- Textbox for entering new save name + self.new_map_textbox = self:addBevelPanel(5, 310, self.width - 10, 17, col_textbox, col_highlight, col_shadow) + :setLabel(_S.save_map_window.new_map, nil, "left"):setTooltip(_S.tooltip.save_map_window.new_map) + :makeTextbox(--[[persistable:save_map_new_map_textbox_confirm_callback]] function() self:confirmName() end, + --[[persistable:save_map_new_map_textbox_abort_callback]] function() self:abortName() end) +end + +--! Function called when textbox is aborted (e.g. by pressing escape) +function UISaveMap:abortName() + self.new_map_textbox.text = "" + self.new_map_textbox.panel:setLabel(_S.save_map_window.new_map) +end + +--! Function called when textbox is confirmed (e.g. by pressing enter) +function UISaveMap:confirmName() + local filename = self.new_map_textbox.text + local app = self.ui.app + if filename == "" then + self:abortName() + return + end + self:trySave(app.user_level_dir .. filename .. ".map") +end + +--! Function called by clicking button of existing save #num +function UISaveMap:choiceMade(name) + self:trySave(name) +end + +--! Try to save the game with given filename; if already exists, create confirmation window first. +function UISaveMap:trySave(filename) + if lfs.attributes(filename, "size") ~= nil then + self.ui:addWindow(UIConfirmDialog(self.ui, _S.confirmation.overwrite_save, --[[persistable:save_map_confirmation]] function() self:doSave(filename) end)) + else + self:doSave(filename) + end +end + +--! Actually do save the map with given filename. +function UISaveMap:doSave(filename) + filename = filename + local ui = self.ui + local map = ui.app.map + self:close() + + local status, err = pcall(map.save, map, filename) + if not status then + err = _S.errors.save_prefix .. err + print(err) + ui:addWindow(UIInformation(ui, {err})) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/folder_settings.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/folder_settings.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/folder_settings.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/folder_settings.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,30 +21,15 @@ --! Customise window used in the main menu and ingame. class "UIFolder" (UIResizable) +---@type UIFolder +local UIFolder = _G["UIFolder"] + local col_bg = { red = 154, green = 146, blue = 198, } -local col_button = { - red = 84, - green = 200, - blue = 84, -} - -local col_textbox = { - red = 0, - green = 0, - blue = 0, -} - -local col_highlight = { - red = 174, - green = 166, - blue = 218, -} - local col_shadow = { red = 134, green = 126, @@ -76,7 +61,8 @@ .lowered = true -- Location of original game - local built_in = app.gfx:loadBuiltinFont() + local built_in = app.gfx:loadMenuFont() + self:addBevelPanel(20, 50, 130, 20, col_shadow, col_bg, col_bg) :setLabel(_S.folders_window.data_label):setTooltip(_S.tooltip.folders_window.data_location) .lowered = true @@ -118,9 +104,10 @@ :setLabel(_S.folders_window.music_label):setTooltip(_S.tooltip.folders_window.music_location) .lowered = true local tooltip_audio = app.config.audio_mp3 and _S.tooltip.folders_window.browse_music:format(app.config.audio_mp3) or _S.tooltip.folders_window.not_specified - self:addBevelPanel(160, 150, 180, 20, col_bg) - :setLabel(app.config.audio_mp3 and app.config.audio_mp3 or tooltip_audio, built_in):setAutoClip(true) - :makeButton(0, 0, 180, 20, nil, self.buttonBrowseForAudio_mp3):setTooltip(tooltip_audio) + self.mp3_panel = self:addBevelPanel(160, 150, 180, 20, col_bg) + self.mp3_panel:setLabel(app.config.audio_mp3 and app.config.audio_mp3 or tooltip_audio, built_in):setAutoClip(true) + :makeButton(0, 0, 160, 20, nil, self.buttonBrowseForAudio_mp3):setTooltip(tooltip_audio) + self:addBevelPanel(320, 150, 20, 20, col_bg):setLabel("X"):makeButton(0, 0, 20, 20, nil, self.resetMp3Dir):setTooltip(_S.tooltip.folders_window.reset_to_default) -- "Back" button self:addBevelPanel(20, 180, 320, 40, col_bg):setLabel(_S.folders_window.back) @@ -144,6 +131,14 @@ self.screenshots_panel:setLabel(_S.tooltip.folders_window.default, self.built_in_font) end +function UIFolder:resetMp3Dir() + local app = TheApp + app.config.audio_mp3 = nil + app:saveConfig() + app.audio:init() + self.mp3_panel:setLabel(_S.tooltip.folders_window.not_specified, self.built_in_font) +end + function UIFolder:buttonBrowseForFont() local browser = UIChooseFont(self.ui, self.mode) self.ui:addWindow(browser) @@ -157,7 +152,7 @@ app.config.savegames = path app:saveConfig() app:initSavegameDir() - self.saves_panel:setLabel(app.config.savegames and app.config.savegames or tooltip_saves , self.built_in_font) + self.saves_panel:setLabel(app.config.savegames, self.built_in_font) end end local browser = UIDirectoryBrowser(self.ui, self.mode, _S.folders_window.savegames_location, "DirTreeNode", callback) @@ -184,7 +179,7 @@ app.config.screenshots = path app:saveConfig() app:initScreenshotsDir() - self.screenshots_panel:setLabel(app.config.screenshots and app.config.screenshots or tooltip_screenshots, self.built_in_font) + self.screenshots_panel:setLabel(app.config.screenshots, self.built_in_font) end end local browser = UIDirectoryBrowser(self.ui, self.mode, _S.folders_window.screenshots_location, "DirTreeNode", callback) @@ -196,8 +191,8 @@ local app = TheApp app.config.audio_mp3 = path app:saveConfig() - debug.getregistry()._RESTART = true - app.running = false + app.audio:init() + self.mp3_panel:setLabel(app.config.audio_mp3, self.built_in_font) end local browser = UIDirectoryBrowser(self.ui, self.mode, _S.folders_window.music_location, "DirTreeNode", callback) self.ui:addWindow(UIConfirmDialog(self.ui, diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/lua_console.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/lua_console.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/lua_console.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/lua_console.lua 2018-07-21 11:13:17.000000000 +0000 @@ -24,6 +24,9 @@ --! Interactive Lua Console for ingame debugging. class "UILuaConsole" (UIResizable) +---@type UILuaConsole +local UILuaConsole = _G["UILuaConsole"] + local col_bg = { red = 46, green = 186, @@ -93,7 +96,7 @@ function UILuaConsole:buttonExecute() print("Loading UserFunction...") - local func, err + local func, err, s _ = TheApp.ui and TheApp.ui.debug_cursor_entity @@ -110,13 +113,14 @@ if not func then print("Error while loading UserFunction:") print(err) - else - print("Executing UserFunction...") - local s, err = pcall(func) - if not s then - print("Error while executing UserFunction:") - print(err) - end + return + end + + print("Executing UserFunction...") + s, err = pcall(func) + if not s then + print("Error while executing UserFunction:") + print(err) end end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/main_menu.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/main_menu.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/main_menu.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/main_menu.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010 Manuel "Roujin" Wolf +--[[ Copyright (c) 2010-2014 Manuel "Roujin" Wolf, Edvin "Lego3" Linge Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -21,16 +21,34 @@ --! Class for main menu window. class "UIMainMenu" (UIResizable) +---@type UIMainMenu +local UIMainMenu = _G["UIMainMenu"] + local col_bg = { red = 154, green = 146, blue = 198, } +local menu_item_height = 40 + function UIMainMenu:UIMainMenu(ui) - self:UIResizable(ui, 200, 300, col_bg) - local app = ui.app + -- First define all menu entries with a label, a callback and a tooltip. + -- That way we can call the UIResizable constructor with a good height argument. + local menu_items = { + {_S.main_menu.new_game, self.buttonNewGame, _S.tooltip.main_menu.new_game}, + {_S.main_menu.custom_campaign, self.buttonCustomCampaign, _S.tooltip.main_menu.custom_campaign}, + {_S.main_menu.custom_level, self.buttonCustomGame, _S.tooltip.main_menu.custom_level}, + {_S.main_menu.continue, self.buttonContinueGame, _S.tooltip.main_menu.continue}, + {_S.main_menu.load_game, self.buttonLoadGame, _S.tooltip.main_menu.load_game}, + {_S.main_menu.options, self.buttonOptions, _S.tooltip.main_menu.options}, + {_S.main_menu.map_edit, self.buttonMapEdit, _S.tooltip.main_menu.map_edit}, + {_S.main_menu.exit, self.buttonExit, _S.tooltip.main_menu.exit} + } + self.no_menu_entries = #menu_items + self:UIResizable(ui, 200, (menu_item_height + 10) * (#menu_items + 1), col_bg) + self.esc_closes = false self.modal_class = "main menu" self.on_top = true @@ -42,25 +60,37 @@ -- individual buttons self.default_button_sound = "selectx.wav" - self:addBevelPanel(20, 20, 160, 40, col_bg):setLabel(_S.main_menu.new_game):makeButton(0, 0, 160, 40, nil, self.buttonNewGame):setTooltip(_S.tooltip.main_menu.new_game) - self:addBevelPanel(20, 65, 160, 40, col_bg):setLabel(_S.main_menu.custom_level):makeButton(0, 0, 160, 40, nil, self.buttonCustomGame):setTooltip(_S.tooltip.main_menu.custom_level) - self:addBevelPanel(20, 110, 160, 40, col_bg):setLabel(_S.main_menu.load_game):makeButton(0, 0, 160, 40, nil, self.buttonLoadGame):setTooltip(_S.tooltip.main_menu.load_game) - self:addBevelPanel(20, 155, 160, 40, col_bg):setLabel(_S.main_menu.options):makeButton(0, 0, 160, 40, nil, self.buttonOptions):setTooltip(_S.tooltip.main_menu.options) - self:addBevelPanel(20, 220, 160, 40, col_bg):setLabel(_S.main_menu.exit):makeButton(0, 0, 160, 40, nil, self.buttonExit):setTooltip(_S.tooltip.main_menu.exit) + + local next_y = 20 + for _, item in ipairs(menu_items) do + next_y = self:addMenuItem(item[1], item[2], item[3], next_y) + end +end + +--! Adds a single menu item to the main menu. +--!param label (string) The (localized) label to use for the new button. +--!param callback (function) Function to call when the user clicks the button. +--!param tooltip (string) Text to show when the player hovers over the button. +--!param y_pos (integer) Y-position from where to add the menu item. +--!return (integer) Y-position below which more items can be added. +-- This function has added a menu item between y_pos and the return value. +function UIMainMenu:addMenuItem(label, callback, tooltip, y_pos) + self:addBevelPanel(20, y_pos, 160, menu_item_height, col_bg) + :setLabel(label):makeButton(0, 0, 160, menu_item_height, nil, callback) + :setTooltip(tooltip) + return y_pos + menu_item_height + 10 end function UIMainMenu:getSavedWindowPositionName() return "main_menu_group" end -local label_y = { 27, 75, 123, 171, 231 } - function UIMainMenu:draw(canvas, x, y) UIResizable.draw(self, canvas, x, y) x, y = self.x + x, self.y + y -- Move the version string up a bit if also showing the savegame version. - local ly = y + 285 + local ly = y + (menu_item_height + 10) * (self.no_menu_entries + 1) - 15 if TheApp.config.debug then self.label_font:draw(canvas, _S.main_menu.savegame_version .. TheApp.savegame_version, x + 5, ly, 190, 0, "right") ly = ly - 15 @@ -71,7 +101,15 @@ function UIMainMenu:buttonNewGame() local window = UINewGame(self.ui) self.ui:addWindow(window) +end +function UIMainMenu:buttonCustomCampaign() + if TheApp.using_demo_files then + self.ui:addWindow(UIInformation(self.ui, {_S.information.no_custom_game_in_demo})) + else + local window = UICustomCampaign(self.ui) + self.ui:addWindow(window) + end end function UIMainMenu:buttonCustomGame() @@ -83,6 +121,24 @@ end end +function UIMainMenu:buttonContinueGame() + local most_recent_saved_game = FileTreeNode(self.ui.app.savegame_dir):getMostRecentlyModifiedChildFile(".sav") + if most_recent_saved_game then + local path = most_recent_saved_game.path + local app = self.ui.app + local status, err = pcall(app.load, app, path) + if not status then + err = _S.errors.load_prefix .. err + print(err) + app.ui:addWindow(UIInformation(self.ui, {err})) + end + else + local error = _S.errors.load_prefix .. _S.errors.no_games_to_contine + print(error) + self.ui.app.ui:addWindow(UIInformation(self.ui, {error})) + end +end + function UIMainMenu:buttonLoadGame() local window = UILoadGame(self.ui, "menu") self.ui:addWindow(window) @@ -93,6 +149,10 @@ self.ui:addWindow(window) end +function UIMainMenu:buttonMapEdit() + self.ui.app:mapEdit() +end + function UIMainMenu:buttonExit() self.ui:addWindow(UIConfirmDialog(self.ui, _S.tooltip.main_menu.quit, diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/map_editor.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/map_editor.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/map_editor.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/map_editor.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,1559 @@ +--[[ Copyright (c) 2010 Peter "Corsix" Cawley +Copyright (c) 2014 Stephen Baker + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +class "UIMapEditor" (UIResizable) + +---@type UIMapEditor +local UIMapEditor = _G["UIMapEditor"] + +local col_bg = {red = 154, green = 146, blue = 198} + +-- {{{ Editor sprites. + +-- Unfortunately, current map file format does not support flags like FLIP_H. +-- Commented this out until flags can be stored in the file created by the map editor. +-- -- High byte sprite constants. +-- local FLIP_H = DrawFlags.FlipHorizontal * 256 + +-- Each variable below is an array of multi-tile sprites, which is translated +-- to a list of buttons at a page. +-- The generic form of a multi-tile sprite (see the helipad for an example) is +-- a table {sprites = .., height = .., objects = ..}. The 'height' defines the +-- height of the displayed button (between 1 and MAX_HEIGHT). The 'sprites' is +-- an array of single sprites, a table of {sprite = ..., xpos = ..., ypos = +-- ..., type = ...}. It defines which sprite to display at which relative +-- position. Positions run from 1 upward, sprites are numbers 0..255 (the low +-- byte). +-- The high byte is reserved for adding DrawFlags flags in the future, eg FLIP_H. +-- +-- The type defines where the sprite is stored. 'north' and 'west' mean north +-- respectively west wall. 'floor' means it is a floor sprite. 'hospital' is +-- also a floor sprite but it also states that the tile is part of the +-- hospital. Similarly, 'road' is a floor sprite outside the hospital that can +-- be walked on. Finally, the 'objects' defines the position of objects in the +-- shape. At this time, only an entrance door can be placed. +-- +-- As there are a lot of single tile sprite buttons, there is a simplified +-- form to specify those (and they get expanded to the generic multi-tile +-- sprite form automagically). The short form for a single sprite button is a +-- table {sprite = ..., height = ..., type = ...}, where all the fields have +-- the same meaning as described above for the generic form. +-- +-- {{{ Foliage sprites. +local foliage = { + {sprite=192, height=3, type="floor"}, -- Regular European shrub 1 + {sprite=193, height=2, type="floor"}, -- Ground plant, green 1 + {sprite=194, height=2, type="floor"}, -- Bush + {sprite=195, height=3, type="floor"}, -- Ground plant, red flowers + {sprite=196, height=3, type="floor"}, -- Shrub + {sprite=197, height=4, type="floor"}, -- Dead tree (very high) + {sprite=198, height=2, type="floor"}, -- Low ground plant + {sprite=199, height=3, type="floor"}, -- Regular European shrub 2 + {sprite=200, height=2, type="floor"}, -- Ground plant, flowers + {sprite=201, height=1, type="floor"}, -- Flowerbed East/South + {sprite=202, height=1, type="floor"}, -- Flowerbed West/South + {sprite=203, height=1, type="floor"}, -- Flowerbed West/North + {sprite=204, height=1, type="floor"}, -- Flowerbed North/South +} +-- }}} +-- {{{ Hedge row sprites. +local hedgerow={ + {sprite=176, height=2, type="floor"}, -- Hedge West-North + {sprite=177, height=2, type="floor"}, -- Hedge West-South + {sprite=178, height=2, type="floor"}, -- Hedge East-South + {sprite=179, height=2, type="floor"}, -- Hedge East-North + {sprite=180, height=2, type="floor"}, -- Hedge West-East + {sprite=181, height=2, type="floor"}, -- Hedge North-South + {sprite=182, height=2, type="floor"}, -- Hedge East-West-South + {sprite=183, height=2, type="floor"}, -- Hedge East-West-North + {sprite=184, height=2, type="floor"}, -- Hedge West-North-South + {sprite=185, height=2, type="floor"}, -- Hedge East-North-South + {sprite=186, height=2, type="floor"}, -- Hedge East-West-North-South + {sprite=187, height=2, type="floor"}, -- Hedge North-South with shrub + {sprite=188, height=2, type="floor"}, -- Hedge North-South with holes + {sprite=189, height=2, type="floor"}, -- Hedge East-West with shrub 1 + {sprite=190, height=2, type="floor"}, -- Hedge East-West with holes + {sprite=191, height=2, type="floor"}, -- Hedge East-West with shrub 2 +} +-- }}} +-- {{{ Pond sprites. +local pond={ + {sprite= 60, height=1, type="floor"}, -- South edge of a pond + {sprite= 65, height=1, type="floor"}, -- West edge of a pond + {sprite= 68, height=1, type="floor"}, -- North edge of a pond + {sprite= 78, height=1, type="floor"}, -- East edge of a pond + {sprite= 59, height=1, type="floor"}, -- South-West corner of a pond + {sprite= 77, height=1, type="floor"}, -- North-East corner of a pond + {sprite= 79, height=1, type="floor"}, -- South-East corner of a pond + {sprite= 80, height=1, type="floor"}, -- North-West corner of a pond + {sprite= 69, height=1, type="floor"}, -- Water tile of a pond + {sprite= 71, height=1, type="floor"}, -- Water tile of a pond with water lilies + {sprite= 72, height=2, type="floor"}, -- Water tile of a pond with water plant 1 + {sprite= 73, height=2, type="floor"} -- Water tile of a pond with water plant 2 +} +-- }}} +-- {{{ Inside floor sprites. +local inside={ + {sprite= 17, height=1, type="hospital"}, -- Dark blue/purple carpet tile + {sprite= 70, height=1, type="hospital"}, -- Duplicate of 017 + {sprite= 18, height=1, type="hospital"}, -- Red-Blue floor tile 1 + {sprite= 19, height=1, type="hospital"}, -- Red-Blue floor tile 2 + {sprite= 23, height=1, type="hospital"}, -- Red-Blue floor tile 3 + {sprite= 16, height=1, type="hospital"}, -- Dark big checker pattern tile + {sprite= 21, height=1, type="hospital"}, -- Small checker pattern tile + {sprite= 22, height=1, type="hospital"}, -- Big checker pattern tile + {sprite= 66, height=1, type="hospital"}, -- Floor tile with light center + {sprite= 76, height=1, type="hospital"}, -- Floor tile with light center and corners + {sprite= 20, height=1, type="hospital"} -- Wooden floor tile +} +-- }}} +-- {{{ Outside floor sprites. +local outside={ + {sprite= 1, height=1, type="floor"}, -- Grass tile 1 + {sprite= 2, height=1, type="floor"}, -- Grass tile 2 + {sprite= 3, height=1, type="floor"}, -- Grass tile 3 + {sprite= 4, height=1, type="road" }, -- Light concrete tile + {sprite= 15, height=1, type="road" }, -- Concrete tile + {sprite= 5, height=1, type="road" }, -- Dark concrete tile + {sprite= 6, height=1, type="floor"}, -- Grass tile with South-East concrete corner + {sprite= 8, height=1, type="floor"}, -- Grass tile with South-West concrete corner + {sprite= 10, height=1, type="floor"}, -- Grass tile with North-West concrete corner + {sprite= 12, height=1, type="floor"}, -- Grass tile with North-East concrete corner + {sprite= 7, height=1, type="floor"}, -- Grass tile with South concrete edge + {sprite= 9, height=1, type="floor"}, -- Grass tile with West concrete edge + {sprite= 11, height=1, type="floor"}, -- Grass tile with North concrete edge + {sprite= 13, height=1, type="floor"}, -- Grass tile with East concrete edge + {sprite= 14, height=1, type="floor"}, -- Concrete tile with North-East grass corner + {sprite= 61, height=1, type="floor"}, -- Concrete tile with South-West grass corner + {sprite= 62, height=1, type="floor"}, -- Concrete tile with South-East grass corner + {sprite= 63, height=1, type="floor"}, -- Concrete tile with North-West grass corner + {sprite= 64, height=1, type="floor"}, -- Grass tile with rocks + {sprite=205, height=1, type="floor"}, -- Fully cracked garden marble tile + {sprite=206, height=1, type="floor"}, -- Broken garden marble tile + {sprite=207, height=1, type="floor"}, -- Partially cracked garden marble tile + {sprite=208, height=1, type="floor"}, -- Garden marble tile +} +-- }}} +-- {{{ Road floor sprites. +local road_spr = { + {sprite= 41, height=1, type="road"}, -- Road with white discontinuous line North-South + {sprite= 45, height=1, type="road"}, -- Road with double yellow lines at West edge merging at South +--{sprite= 46, height=1, type="road"}, -- Duplicate of 45 + {sprite= 42, height=1, type="road"}, -- Road with double yellow lines at West with black orthogonal lines + {sprite= 43, height=1, type="road"}, -- Road with double yellow lines at West edge + {sprite= 44, height=1, type="road"}, -- Road with double yellow lines at West edge merging at North + {sprite= 47, height=1, type="road"}, -- Road with red line at East linked to yellow discontinuous line at South + {sprite= 49, height=1, type="road"}, -- Road with red braking line at the East pointing to the West + {sprite= 48, height=1, type="road"}, -- Road with red line at East linked to yellow discontinuous line at North + {sprite= 53, height=1, type="road"}, -- Road with double yellow lines at East edge merging at the south + {sprite= 52, height=1, type="road"}, -- Road with double yellow lines at East with black orthogonal lines +--{sprite= 54, height=1, type="road"}, -- Duplicate of 52 + {sprite= 51, height=1, type="road"}, -- Road with double yellow lines at East edge + {sprite= 57, height=1, type="road"}, -- Road with red line at West linked to yellow discontinuous line at South + {sprite= 55, height=1, type="road"}, -- Road with red braking line at the West pointing to the East + {sprite= 56, height=1, type="road"}, -- Road with red line at West linked to yellow discontinuous line at North + {sprite= 50, height=1, type="road"}, -- Road with grey edge at the East + {sprite= 58, height=1, type="road"}, -- Road with grey edge at the West +} +local road = {} -- All sprites get horizontally flipped as well, for roads running north-south. +for _, spr in ipairs(road_spr) do + road[#road + 1] = spr + + -- Unfortunately, current map file format does not support flags like FLIP_H. + -- Commented this out until flags can be stored in the file created by the map editor. + -- road[#road + 1] = {sprite = spr.sprite + FLIP_H, height = spr.height, type = spr.type} +end +-- }}} +-- {{{ North wall layout and floor sprites. +local north_wall = { + {sprites = { + {sprite=159, xpos=1, ypos=1, type="north"}, -- External doorway North outside left part + {sprite=157, xpos=3, ypos=1, type="north"}, -- External doorway North outside right part + }, + height = 3, + objects = {{type="entrance_door", xpos=2, ypos=1, direction="north"}}, + }, + + {sprites = { + {sprite=163, xpos=1, ypos=1, type="north"}, -- External doorway North inside left part + {sprite=161, xpos=3, ypos=1, type="north"}, -- External doorway North inside right part + }, + height = 3, + objects = {{type="entrance_door", xpos=2, ypos=1, direction="north"}}, + }, + + {sprite=114, height=3, type="north"}, -- External North wall outside + {sprite=116, height=3, type="north"}, -- External North wall outside left part of window + {sprite=120, height=3, type="north"}, -- External North wall with window + {sprite=118, height=3, type="north"}, -- External North wall outside right part of window + {sprite=122, height=3, type="north"}, -- External North wall inside + {sprite=124, height=3, type="north"}, -- External North wall inside left part of window + {sprite=126, height=3, type="north"}, -- External North wall inside right part of window +-- Unfortunately, current map file format does not support flags like FLIP_H. +-- Commented this out until flags can be stored in the file created by the map editor. +-- {sprite=209 + FLIP_H, height=3, type="north"}, -- Lamp post pointing East +-- {sprite=210 + FLIP_H, height=3, type="north"}, -- Lamp post pointing West +} +-- }}} +-- {{{ West wall layout and floor sprites. +local west_wall = { + {sprites = { + {sprite=158, xpos=1, ypos=3, type="west"}, -- External doorway West outside left part + {sprite=160, xpos=1, ypos=1, type="west"}, -- External doorway West outside right part + }, + height = 3, + objects = {{type="entrance_door", xpos=1, ypos=2, direction="west"}}, + }, + + {sprites = { + {sprite=162, xpos=1, ypos=3, type="west"}, -- External doorway West inside left part + {sprite=164, xpos=1, ypos=1, type="west"}, -- External doorway West inside right part + }, + height = 3, + objects = {{type="entrance_door", xpos=1, ypos=2, direction="west"}}, + }, + + {sprite=115, height=3, type="west"}, -- External West wall outside + {sprite=119, height=3, type="west"}, -- External West wall outside left part of window +-- No external west-wall with just glass. 121 (below) isn't finished, 120 (north above) has different lighting +-- {sprite=121, height=3, type="west"}, -- External West wall with window glass (UNFINISHED?) + {sprite=117, height=3, type="west"}, -- External West wall outside right part of window + {sprite=123, height=3, type="west"}, -- External West wall inside + {sprite=127, height=3, type="west"}, -- External West wall inside left part of window + {sprite=125, height=3, type="west"}, -- External West wall inside right part of window + {sprite=210, height=3, type="west"}, -- Lamp post pointing South + {sprite=209, height=3, type="west"}, -- Lamp post pointing North +} +-- }}} +-- {{{ Helipad layout. +local helipad = { + {sprites = { + -- Dark tiles around the edges. + {sprite=5, xpos=1, ypos=1, type="road"}, + {sprite=5, xpos=2, ypos=1, type="road"}, + {sprite=5, xpos=3, ypos=1, type="road"}, + {sprite=5, xpos=4, ypos=1, type="road"}, + {sprite=5, xpos=5, ypos=1, type="road"}, + + {sprite=5, xpos=1, ypos=2, type="road"}, + {sprite=5, xpos=1, ypos=3, type="road"}, + {sprite=5, xpos=1, ypos=4, type="road"}, + {sprite=5, xpos=1, ypos=5, type="road"}, + + {sprite=5, xpos=2, ypos=5, type="road"}, + {sprite=5, xpos=3, ypos=5, type="road"}, + {sprite=5, xpos=4, ypos=5, type="road"}, + + {sprite=5, xpos=5, ypos=5, type="road"}, + {sprite=5, xpos=5, ypos=2, type="road"}, + {sprite=5, xpos=5, ypos=3, type="road"}, + {sprite=5, xpos=5, ypos=4, type="road"}, + -- Dark tiles in the 'H' + {sprite=5, xpos=3, ypos=2, type="road"}, + {sprite=5, xpos=3, ypos=4, type="road"}, + -- Light tiles in the 'H' + {sprite=4, xpos=2, ypos=2, type="road"}, + {sprite=4, xpos=2, ypos=3, type="road"}, + {sprite=4, xpos=2, ypos=4, type="road"}, + {sprite=4, xpos=4, ypos=2, type="road"}, + {sprite=4, xpos=4, ypos=3, type="road"}, + {sprite=4, xpos=4, ypos=4, type="road"}, + {sprite=4, xpos=3, ypos=3, type="road"} + }, + height=5 + } +} +-- }}} + +local MAX_HEIGHT = 5 -- Biggest height in above sprites +local PAGES = { + {name = _S.map_editor_window.pages.inside, spr_data = inside}, + {name = _S.map_editor_window.pages.outside, spr_data = outside}, + {name = _S.map_editor_window.pages.foliage, spr_data = foliage}, + {name = _S.map_editor_window.pages.hedgerow, spr_data = hedgerow}, + {name = _S.map_editor_window.pages.pond, spr_data = pond}, + {name = _S.map_editor_window.pages.road, spr_data = road}, + {name = _S.map_editor_window.pages.north_wall, spr_data = north_wall}, + {name = _S.map_editor_window.pages.west_wall, spr_data = west_wall}, + {name = _S.map_editor_window.pages.helipad, spr_data = helipad} +} +-- {{{ Functions +--! Normalize the editor sprite in the table to always have a 'sprites' field, as well as have sizes and a column width (for the display). +--!param (table) Sprite from the 'PAGES[#].spr_data' table. +--!return (table 'sprites', 'xsize', 'ysize', 'width', and 'height') +local function normalizeEditSprite(spr) + assert(MAX_HEIGHT >= spr.height) -- Verify that sprite fits in the maximum height. + + if spr.sprites == nil then -- {sprite = xxx, height = y} case + return {sprites = {{sprite = spr.sprite, xpos = 1, ypos = 1, type=spr.type}}, + xsize = 1, + ysize = 1, + type = spr.type, + xorigin = 0, + yorigin = 0, + width = 2, + height = spr.height} + else + -- {sprites={...}, height=y} case, compute sizes, and width + local xsize = 1 + local ysize = 1 + local spr_type = nil + for _, sp in ipairs(spr.sprites) do + if sp.xpos > xsize then xsize = sp.xpos end + if sp.ypos > ysize then ysize = sp.ypos end + + assert(not spr_type or spr_type == sp.type) -- Ensure all sprites have the same type. + spr_type = sp.type + end + -- Position to draw (1,1) sprite, by default (0,0) + -- Since sprites are drawn top to bottom, yorigin never changes. + local xorigin = (ysize - 1) * 32 + local yorigin = 0 + + local width = ysize - 1 + xsize - 1 + 2 + if width < ysize then width = ysize end + + return {sprites = spr.sprites, + xsize = xsize, + ysize = ysize, + type = spr_type, + xorigin = xorigin, + yorigin = yorigin, + width = width, + height = spr.height, + objects = spr.objects} + end +end + +--!Decide the highest possible placement for 'width' columns. +--!param cols (list int) First available position in each column, higher number is lower. +--!param width (int) Required width as number of columns. +--!return (int, int) Starting column and placement height. +local function getHighestRowcol(cols, width) + local best = cols[1] + 100000 + local best_col = 0 + + for left = 1, #cols - width + 1 do -- Try starting in each column. + if cols[left] < best then -- First column is potentially better. + local top = cols[left] + for i = 1, width - 1 do + if top < cols[left + i] then + top = cols[left + i] + if top >= best then break end -- i-th column breaks improvement. + end + end + if top < best then + best = top + best_col = left + end + end + end + return best_col, best +end + +--! Layout buttons from a tab of editor sprites. +--!param esprs (list) Editor sprite tab to layout. +--!param num_cols (int) Number of columns available in the layout. +--!return (list) Sprites with button positions in ('column', 'row'). +local function layoutButtons(esprs, num_cols) + local buttons = {} + + local cols = {} + for i = 1, num_cols do + cols[i] = 1 + end + + for hgt = MAX_HEIGHT, 1, -1 do -- Fit highest sprites first. + for _, espr in ipairs(esprs) do + espr = normalizeEditSprite(espr) + if espr.height == hgt then + local spr_col, spr_height = getHighestRowcol(cols, espr.width) + buttons[#buttons + 1] = espr + buttons[#buttons].column = spr_col + buttons[#buttons].row = spr_height + + for i = spr_col, spr_col + espr.width - 1 do -- Update height in the affected columns + assert(cols[i] <= spr_height) + cols[i] = spr_height + hgt + end + + end + end + end + return buttons +end +-- }}} +-- }}} + +local EDITOR_WINDOW_XSIZE = 368 +local EDITOR_WINDOW_YSIZE = 586 +local EDITOR_COLUMNS = 10 -- Number of columns for the sprite buttons +local EDITOR_COLUMN_SIZE = 32 + 3 -- Width of a sprite button in pixels +local EDITOR_ROW_SIZE = 32 + 4 -- Height of a sprite button in pixels + +function UIMapEditor:UIMapEditor(ui) + self:UIResizable(ui, EDITOR_WINDOW_XSIZE, EDITOR_WINDOW_YSIZE, col_bg) + self.resizable = false + + self.ui = ui + self.panel_sprites = self.ui.app.map.blocks + + -- For when there are multiple things which could be sampled from a tile, + -- keep track of the index of which one was most recently sampled, so that + -- next time a different one is sampled. + self.sample_i = 1 + + -- Cursor data in the main world view. + -- States: + -- - disabled: Just show the cursor. + -- - grid: Show an area with red rectangles (requires 'sprite' to exist). + -- - left: Dragging with left mouse button is down, (leftx, lefty) defines the tile. + -- - right: Dragging with right mouse button down, (rightx, righty) defines the tile. + -- - both: Dragging with both left and right mouse buttons down (initiated with left + -- button), (rightx, righty) defines the tile where right button got pressed. + -- - delete: Like grid, with a 1x1 cursor for selecting tiles to remove walls from. + -- - delete-left: Left mouse button drag of 'delete' mode. + -- - parcel: Like grid, with a 1x1 cursor for selecting tiles to set the parcel. + -- - parcel-left: Left mouse button drag of 'parcel' mode. + -- - paste: Like grid, with a copy_xsize, copy_ysize cursor to show where to paste. + -- - paste-left: Left mouse button drag of 'paste' mode. Pasting is limited to dragged + -- area (which can be smaller than (copy_xsize, copy_ysize) area). + -- - camera: Like grid, with a 1x1 cursor for selecting tile to set the camera + -- - heliport: Like grid, with a 1x1 cursor for selecting tile to set the heliport + -- + -- Notes: + -- - The code switches back to 'grid' or 'disabled' without waiting for all + -- buttons getting released. + -- - Nothing gets added in the world until you let go of a mouse button. + -- - Drag detection ('is_drag') is used to allow cancel if user moves back + -- to the (leftx, lefty) position. + -- - The sprite decides how you can drag (none, north-south, east-west, area) + -- + self.cursor = { + state = "disabled", -- State of the cursor. + sprite = nil, -- Selected sprite from the menu. + is_drag = false, -- Whether a true drag (at least 2 cells covered) has been detected. + parcel = nil, -- Parcel number to set in 'parcel' / 'parcel-left' mode. + camera = nil, -- Camera player to set in 'camera' mode. + heliport = nil, -- Heliport player to set in 'heliport' mode. + + xpos = 0, -- Horizontal tile position of the mouse cursor. + ypos = 0, -- Vertical tile position of the mouse cursor. + + leftx = 0, -- Horizontal tile position where the left-click was first detected. + lefty = 0, -- Vertical tile position where the left-click was first detected. + rightx = 0, -- Horizontal tile position where the right-click was first detected. + righty = 0, -- Vertical tile position where the right-click was first detected. + + copy_data = nil, -- Data of the copied area, 'nil' if no data available. + copy_xsize = 0, -- Horizontal size of the copy area. + copy_ysize = 0, -- Vertical size of the copy area. + } + + -- {{{ Creation of buttons. + -- A sprite table containing a "cell outline" sprite + self.cell_outline = TheApp.gfx:loadSpriteTable("Bitmap", "aux_ui", true) + + self:addBevelPanel(0, 0, EDITOR_WINDOW_XSIZE, EDITOR_WINDOW_YSIZE, col_bg) -- Background of the window. + + self.block_buttons = {} -- List of table {button = .., panel = ..} + self.selected_block = nil -- Page of of block buttons currently displayed/selected. + + -- Make the page selection buttons + local XSTART = 10 + local XSIZE = 109 + local YSIZE = 20 + + local ypos = 10 + local xpos = XSTART + self.page_selectbuttons = {} + for _, page in ipairs(PAGES) do + local name = page.name + if xpos + XSIZE >= EDITOR_WINDOW_XSIZE then -- Update ypos (and xpos) if necessary. + xpos = XSTART + ypos = ypos + YSIZE + 2 + end + + local p = self:addBevelPanel(xpos, ypos, XSIZE, YSIZE, col_bg) + :setLabel(name):makeToggleButton(0, 0, XSIZE, YSIZE, nil, + --[[persistable:map_editor_spritepage_clicked]] function() self:pageClicked(name) end) + local spr_buttons = layoutButtons(page.spr_data, EDITOR_COLUMNS) + local page_data = {button = p, name = name, sprite_buttons = spr_buttons} + + self.page_selectbuttons[#self.page_selectbuttons + 1] = page_data + xpos = xpos + XSIZE + 10 + end + -- Make the bottom text buttons + xpos = XSTART + ypos = 420 + + local text_pages = { + {name = "paste", text = _S.map_editor_window.pages.paste}, + {name = "delete_wall", text = _S.map_editor_window.pages.delete_wall}, + {name = "parcel_0", text = _S.map_editor_window.pages.parcel_0, parcel = 0}, + {name = "parcel_1", text = _S.map_editor_window.pages.parcel_1, parcel = 1}, + {name = "parcel_2", text = _S.map_editor_window.pages.parcel_2, parcel = 2}, + {name = "parcel_3", text = _S.map_editor_window.pages.parcel_3, parcel = 3}, + {name = "parcel_4", text = _S.map_editor_window.pages.parcel_4, parcel = 4}, + {name = "parcel_5", text = _S.map_editor_window.pages.parcel_5, parcel = 5}, + {name = "parcel_6", text = _S.map_editor_window.pages.parcel_6, parcel = 6}, + {name = "parcel_7", text = _S.map_editor_window.pages.parcel_7, parcel = 7}, + {name = "parcel_8", text = _S.map_editor_window.pages.parcel_8, parcel = 8}, + {name = "parcel_9", text = _S.map_editor_window.pages.parcel_9, parcel = 9}, + {name = "camera_1", text = _S.map_editor_window.pages.camera_1, camera = 1}, + {name = "camera_2", text = _S.map_editor_window.pages.camera_2, camera = 2}, + {name = "camera_3", text = _S.map_editor_window.pages.camera_3, camera = 3}, + {name = "camera_4", text = _S.map_editor_window.pages.camera_4, camera = 4}, + {name = "heliport_1", text = _S.map_editor_window.pages.heliport_1, heliport = 1}, + {name = "heliport_2", text = _S.map_editor_window.pages.heliport_2, heliport = 2}, + {name = "heliport_3", text = _S.map_editor_window.pages.heliport_3, heliport = 3}, + {name = "heliport_4", text = _S.map_editor_window.pages.heliport_4, heliport = 4}} + + for _, page in ipairs(text_pages) do + if xpos + XSIZE >= EDITOR_WINDOW_XSIZE then -- Update ypos (and xpos) if necessary. + xpos = XSTART + ypos = ypos + YSIZE + 2 + end + + local name = page.name + local p = self:addBevelPanel(xpos, ypos, XSIZE, YSIZE, col_bg) + :setLabel(page.text):makeToggleButton(0, 0, XSIZE, YSIZE, nil, + --[[persistable:map_editor_textpage_clicked]] function() self:pageClicked(name) end) + local page_data = {button = p, name = name, data = page} + self.page_selectbuttons[#self.page_selectbuttons + 1] = page_data + xpos = xpos + XSIZE + 10 + end + self:pageClicked("") -- Initialize all above 'page_selectbuttons'. + + -- }}} + + self:setPosition(0.1, 0.1) +end + +function UIMapEditor:setPlayerCount(count) + local map = self.ui.app.map + map:setPlayerCount(count) + if self.cursor.state == "camera" or self.cursor.state == "heliport" then + map:updateDebugOverlay() + end +end + +-- {{{ function UIMapEditor:pageClicked(name) + +--! Update how the button is displayed based on the provided new state. +--!param button (Panel) to update. +--!param action (str) New state of the button. +local function updateToggleButton(button, action) + if action == "raised" then + button:enable(true) + button:setVisible(true) + button:setToggleState(false) + + elseif action == "lowered" then + button:enable(true) + button:setVisible(true) + button:setToggleState(true) + + elseif action == "invisible" then + button:enable(false) + button:setVisible(false) + + elseif action == "disabled" then + button:enable(false) + button:setVisible(true) + button:setToggleState(false) + + else + assert(false) -- Should never arrive here + end +end + +--! Callback function of the page select buttons. +--!param name (string) Name of the clicked page. +function UIMapEditor:pageClicked(name) + local map = self.ui.app.map + if name == "paste" then + -- Make 'paste' button non-selectable if there is no data to paste. + name = self.cursor.copy_data and name or "" + else + self.cursor.copy_data = nil -- Delete copied area when selecting another item. + end + + for _, pb in ipairs(self.page_selectbuttons) do + if pb.name == name then + map:clearDebugText() + self.cursor.state = name == "paste" and "paste" or "disabled" + updateToggleButton(pb.button, "lowered") + if pb.sprite_buttons then + -- 'sprite' button, display sprites to select from, by the user. + self:buildSpriteButtons(pb.sprite_buttons) + else + -- 'text' button, switch cursor to the right mode directly. + self:buildSpriteButtons({}) + if pb.name == "delete_wall" then + self.cursor.state = "delete" + self.cursor.sprite = nil + self.cursor.is_drag = false + + elseif pb.name == "paste" then + self.cursor.state = "paste" + self.cursor.sprite = nil + self.cursor.is_drag = false + + elseif pb.data.camera then + self.cursor.state = "camera" + self.cursor.spirte = nil + self.cursor.is_drag = false + self.cursor.camera = pb.data.camera + map:loadDebugText("camera") + + elseif pb.data.heliport then + self.cursor.state = "heliport" + self.cursor.spirte = nil + self.cursor.is_drag = false + self.cursor.heliport = pb.data.heliport + map:loadDebugText("heliport") + + else -- Should be a parcel button. + assert(pb.data.parcel) + + self.cursor.state = "parcel" + self.cursor.sprite = nil + self.cursor.is_drag = false + self.cursor.parcel = pb.data.parcel + map:loadDebugText("parcel") + end + end + + elseif pb.name == "paste" and not self.cursor.copy_data then + updateToggleButton(pb.button, "disabled") + else + updateToggleButton(pb.button, "raised") + end + end +end + +--! Do layout of the sprite buttons of the page. +function UIMapEditor:buildSpriteButtons(buttons) + self.selected_block = buttons + + local XBASE = 10 + local YBASE = 83 + local number = 1 + for _, button in ipairs(buttons) do + local xpos = XBASE + (button.column - 1) * EDITOR_COLUMN_SIZE + local ypos = YBASE + (button.row - 1) * EDITOR_ROW_SIZE + local width = EDITOR_COLUMN_SIZE * button.width - 2 + local height = EDITOR_ROW_SIZE * button.height - 2 + + local pb = self.block_buttons[number] + if pb == nil then -- New sprite button needed + local bbutton_number = number + local bbutton = self:addBevelPanel(xpos, ypos, width, height, col_bg) + bbutton = bbutton:makeToggleButton(0, 0, width, height, nil, + --[[persistable:map_editor_block_clicked]] function() self:blockClicked(bbutton_number) end) + updateToggleButton(bbutton, "raised") + + local bpanel = self:addPanel(number, xpos+1, ypos+1, width-2, height-2) + bpanel.visible = true + bpanel.editor_button = button + + bpanel.custom_draw = --[[persistable:map_editor_draw_block_sprite]] function(panel, canvas, x, y) + x = x + panel.x + panel.editor_button.xorigin + y = y + panel.y + panel.editor_button.yorigin + for _, spr in ipairs(panel.editor_button.sprites) do + local xspr = x + (spr.xpos - spr.ypos) * 32 + local yspr = y + (spr.xpos + spr.ypos) * 16 - 32 + panel.window.panel_sprites:draw(canvas, spr.sprite % 256, xspr, yspr, math.floor(spr.sprite / 256)) + end + end + + self.block_buttons[#self.block_buttons + 1] = {button=bbutton, panel=bpanel} + + else -- Reposition & resize existing sprite button + local bbutton = pb.button + bbutton:setPosition(xpos, ypos) + bbutton:setSize(width, height) + updateToggleButton(bbutton, "raised") + + local bpanel = pb.panel + bpanel.editor_button = button + bpanel:setPosition(xpos+1, ypos+1) + bpanel:setSize(width-2, height-2) + bpanel:setVisible(true) + end + + number = number + 1 + end + + -- Make remaining buttons and panels invisible. + while true do + local pb = self.block_buttons[number] + if pb == nil then break end + + updateToggleButton(pb.button, "invisible") + pb.panel.visible = false + number = number + 1 + end +end +-- }}} + +--! Should the given type of sprite be considered a floor sprite? +--!param sprite_type (string) Type of sprite. +--!return The (boolean) type is a floor sprite type. +local function isFloorSpriteType(sprite_type) + return sprite_type == "floor" or sprite_type == "hospital" or sprite_type == "road" +end + +--! Construct cell flags for a given kind of floor sprite. +--!param sprite_type (string) Type of sprite. +local function makeCellFlags(sprite_type) + if sprite_type == "floor" then + return {buildable=false, passable=false, hospital=false} + + elseif sprite_type == "road" then + return {buildable=false, passable=true, hospital=false} + + elseif sprite_type == "hospital" then + return {buildable=true, passable=true, hospital=true} + end + assert(false) -- Should never get here +end + +--! Get the tile area covered by two points. +--!param x1 (jnt) Horizontal coordinate of the first point. +--!param y1 (int) Vertical coordinate of the first point. +--!param x2 (jnt) Horizontal coordinate of the second point. +--!param y2 (int) Vertical coordinate of the second point. +--!return (4 int) Smallest horizontal, smallest vertical, largest horizontal, +-- and largest vertical coordinate. +local function getCoveredArea(x1, y1, x2, y2) + local minx, maxx, miny, maxy + if x1 < x2 then minx, maxx = x1, x2 else minx, maxx = x2, x1 end + if y1 < y2 then miny, maxy = y1, y2 else miny, maxy = y2, y1 end + return minx, miny, maxx, maxy +end + +--! Get the size of an area covered by two points. +--!param x1 (jnt) Horizontal coordinate of the first point. +--!param y1 (int) Vertical coordinate of the first point. +--!param x2 (jnt) Horizontal coordinate of the second point. +--!param y2 (int) Vertical coordinate of the second point. +--!return (2 int) Horizontal and vertical size of the area. +local function getAreaSize(x1, y1, x2, y2) + local minx, miny, maxx, maxy = getCoveredArea(x1, y1, x2, y2) + return maxx - minx + 1, maxy - miny + 1 +end + +--! Test whether (px, py) is inside the given area. +--!param px (int) Horizontal coordinate of the point to test. +--!param py (int) Vertical coordinate of the point to test. +--!param minx (jnt) Smallest horizontal coordinate of the area. +--!param miny (int) Smallest vertical coordinate of the area. +--!param maxx (jnt) Largest horizontal coordinate of the area. +--!param maxy (int) Largest vertical coordinate of the area. +--!return (bool) Whether the point is inside the given area. +local function isPointInside(px, py, minx, miny, maxx, maxy) + return px >= minx and px <= maxx and py >= miny and py <= maxy +end + + +--! Compute x/y pairs to draw the cursor sprite over the area. +--!param minx (int) First horizontal position to draw the sprite. +--!param miny (int) First vertical position to draw the sprite. +--!param maxx (int) Last horizontal position to draw the sprite. +--!param maxy (int) Last vertical position to draw the sprite. +--!param dx (nil or int) Horizontal step size of drawing, usually same size as +-- the width of the sprite being drawn, default is 1. +--!param dy (nil or int) Vertical step size of drawing, usually same size as +-- the height of the sprite being drawn, default is 1. +--!return (array of (xpos, ypos) pairs) Points to draw the sprite cursor. +local function computeCursorSpriteAtArea(minx, miny, maxx, maxy, dx, dy) + local coords = {} + + if not dx or not dy then dx, dy = 1, 1 end + + assert(dx > 0 and dy > 0) + local xbase, ybase + xbase = minx + while xbase <= maxx do + ybase = miny + while ybase <= maxy do + coords[#coords + 1] = {xpos = xbase, ypos = ybase} + + ybase = ybase + dy + end + xbase = xbase + dx + end + + return coords +end + +--! Compute the positions to draw the selected sprite in the world. +--!return (array of {xpos, ypos} tables) Coordinates to draw the selected sprite. +function UIMapEditor:getDrawPoints() + if self.cursor.state == "disabled" then + -- Nothing to compute, drop to bottom {} return. + + elseif self.cursor.state == "grid" then + local bx, by = self:areaOnWorld(self.cursor.xpos, self.cursor.ypos, + self.cursor.sprite.xsize, self.cursor.sprite.ysize) + return {{xpos = bx, ypos = by}} + + elseif self.cursor.state == "delete" or self.cursor.state == "parcel" or + self.cursor.state == "camera" or self.cursor.state == "heliport" or + self.cursor.state == "paste" then + return {{xpos = self.cursor.xpos, ypos = self.cursor.ypos}} + + elseif self.cursor.state == "left" then + -- Simple drag (left button only). + local minx, miny, maxx, maxy = getCoveredArea(self.cursor.leftx, self.cursor.lefty, + self.cursor.xpos, self.cursor.ypos) + if minx ~= maxx or miny ~= maxy or not self.cursor.is_drag then + -- Just 1 tile without starting a drag, or an area of at least two tiles. + return computeCursorSpriteAtArea(minx, miny, maxx, maxy, + self.cursor.sprite.xsize, self.cursor.sprite.ysize) + end + + elseif self.cursor.state == "delete-left" or self.cursor.state == "parcel-left" or + self.cursor.state == "paste-left" then + local minx, miny, maxx, maxy = getCoveredArea(self.cursor.leftx, self.cursor.lefty, + self.cursor.xpos, self.cursor.ypos) + if minx ~= maxx or miny ~= maxy or not self.cursor.is_drag then + -- Just 1 tile without starting a drag, or an area of at least two tiles. + return computeCursorSpriteAtArea(minx, miny, maxx, maxy, 1, 1) + end + + elseif self.cursor.state == "right" then + local minx, miny, maxx, maxy = getCoveredArea(self.cursor.rightx, self.cursor.righty, + self.cursor.xpos, self.cursor.ypos) + if minx ~= maxx or miny ~= maxy or not self.cursor.is_drag then + -- Just 1 tile without starting a drag, or an area of at least two tiles. + return computeCursorSpriteAtArea(minx, miny, maxx, maxy, 1, 1) + end + + elseif self.cursor.state == "both" then + -- left+right drag (left initiated). + -- Area is defined from first to last point, 'right' point must be inside the area. + local minx, miny, maxx, maxy = getCoveredArea(self.cursor.leftx, self.cursor.lefty, + self.cursor.xpos, self.cursor.ypos) + if minx ~= maxx or miny ~= maxy then -- Otherwise area is 1x1, either due to 'cancel', or never enlarged. + if isPointInside(self.cursor.rightx, self.cursor.righty, minx, miny, maxx, maxy) then + -- Get block size between left and right click. + local dx, dy = getAreaSize(self.cursor.leftx, self.cursor.lefty, + self.cursor.rightx, self.cursor.righty) + if dx > 1 or dy > 1 then -- Otherwise, left and right click is in the same tile. + return computeCursorSpriteAtArea(minx, miny, maxx, maxy, dx, dy) + end + end + end + end + + return {} +end + +--! Fill an area of tiles with red cursor rectangles. Caller must make sure that +-- the area is completely inside the world boundaries. +--!param canvas Canvas to draw at. +--!param xpos (int) Horizontal base tile position (of the top corner). +--!param ypos (int) Vertical base tile position (of the top corner). +--!param xsize (int) Horizontal size in tiles. +--!param ysize (int) Vertical size in tiles. +function UIMapEditor:fillCursorArea(canvas, xpos, ypos, xsize, ysize) + local ui = self.ui + local zoom = ui.zoom_factor + + for x = 0, xsize - 1 do + for y = 0, ysize - 1 do + local xcoord, ycoord = ui:WorldToScreen(xpos + x, ypos + y) + self.cell_outline:draw(canvas, 2, math.floor(xcoord / zoom) - 32, math.floor(ycoord / zoom)) + end + end +end + +--! Draw the display (map editor window, and main world display) +--!param canvas (draw object) Canvas to draw on. +function UIMapEditor:draw(canvas, ...) + local ui = self.ui + + -- Draw the red grid for the selected tile. + local coords = self:getDrawPoints() + if #coords ~= 0 then + -- Get size of the cursor. + local xsize, ysize + if self.cursor.state == "delete" or self.cursor.state == "delete-left" or + self.cursor.state == "parcel" or self.cursor.state == "parcel-left" or + self.cursor.state == "heliport" or self.cursor.state == "camera" or + self.cursor.state == "paste-left" or self.cursor.state == "right" then + xsize, ysize = 1, 1 + elseif self.cursor.state == "paste" then + xsize, ysize = self.cursor.copy_xsize, self.cursor.copy_ysize + else + xsize, ysize = self.cursor.sprite.xsize, self.cursor.sprite.ysize + end + -- Draw cursors. + local scaled = canvas:scale(ui.zoom_factor) + for _, coord in ipairs(coords) do + local xpos, ypos = coord.xpos, coord.ypos + self:fillCursorArea(canvas, xpos, ypos, xsize, ysize) + end + if scaled then + canvas:scale(1) + end + end + + UIResizable.draw(self, canvas, ...) +end + +-- {{{ several useful functions +--! User clicked at a block (a button with a sprite). +--!param num Index block number. +function UIMapEditor:blockClicked(num) + -- Reset toggle of other block buttons. + for bnum = 1, #self.block_buttons do + if bnum ~= num then self.block_buttons[bnum].button:setToggleState(false) end + end + + if self.block_buttons[num].button.toggled then + local sprite = self.selected_block[num] + self.cursor.state = "grid" + self.cursor.sprite = {xsize = sprite.xsize, + ysize = sprite.ysize, + sprites = sprite.sprites, + objects = sprite.objects, + type = sprite.type} + else + self.cursor.state = "disabled" + self.cursor.sprite = nil + end +end + +--! Convert mouse coordinates to tile coordinates in the world. +--!param mx (int) Mouse X screen coordinate. +--!param my (int) Mouse y screen coordinate. +--!return (int, int) Tile x,y coordinates, limited to the map. +function UIMapEditor:mouseToWorld(mx, my) + local ui = self.ui + + local wxr, wyr = ui:ScreenToWorld(self.x + mx, self.y + my) + local wx = math.floor(wxr) + local wy = math.floor(wyr) + return self:areaOnWorld(wx, wy, 1, 1) +end + +--! Stay on world with the entire area, by moving the base position (if needed). +--!param xpos (int) Horizontal base position. +--!param ypos (int) Vertical base position. +--!param xsize (int) Horizontal size. +--!param ysize (int) Vertical size. +--!return (int, int) Allowed base position +function UIMapEditor:areaOnWorld(xpos, ypos, xsize, ysize) + local map = self.ui.app.map + + xpos = math.min(math.max(xpos, 1), map.width - xsize + 1) + ypos = math.min(math.max(ypos, 1), map.height - ysize + 1) + return xpos, ypos +end +-- }}} + +--! Retrieve what drag capabilities are allowed by the currently selected world cursor sprite. +--!return (string) "none"=not draggable, "east-west"=dragging only in east-west direction, +-- "north-south"=dragging only in north-south direction, "area"=dragging in both directions. +function UIMapEditor:getCursorDragCapabilities() + -- Parcel and delete modes have unrestricted movement. + if self.cursor.state == "delete" or self.cursor.state == "delete-left" or + self.cursor.state == "parcel" or self.cursor.state == "parcel-left" or + self.cursor.state == "paste" or self.cursor.state == "paste-left" or + self.cursor.state == "right" then + return "area" + end + + -- No sprite, or not a 1x1 size -> not draggable. + if not self.cursor.sprite then return "none" end + if self.cursor.sprite.xsize ~= 1 or self.cursor.sprite.ysize ~= 1 then + return "none" + end + + if isFloorSpriteType(self.cursor.sprite.type) then return "area" end + if self.cursor.sprite.type == "north" then return "east-west" end + if self.cursor.sprite.type == "west" then return "north-south" end + assert(false) -- Should never get here +end + +--! The user moved the mouse! +--!param x (int) New horizontal position of the mouse at the screen. +--!param y (int) New vertical position of the mouse at the screen. +--!param dx (int) Horizontal shift in position of the mouse at the screen. +--!param dy (int) Vertical shift in position of the mouse at the screen. +function UIMapEditor:onMouseMove(x, y, dx, dy) + local repaint = UIResizable.onMouseMove(self, x, y, dx, dy) + + -- Update the stored state of cursor position, and trigger a repaint as the + -- cell outline sprite should track the cursor position. + local wx, wy = self:mouseToWorld(x, y) + if wx ~= self.cursor.xpos or wy ~= self.cursor.ypos then + + if self.cursor.state == "disabled" then + self.cursor.xpos = wx -- Nothing is displayed, just keep track of the position. + self.cursor.ypos = wy + return repaint + + elseif self.cursor.state == "grid" or self.cursor.state == "delete" or + self.cursor.state == "parcel" or self.cursor.state == "paste" or + self.cursor.state == "heliport" or self.cursor.state == "camera" or + self.cursor.state == "right" then + self.cursor.xpos = wx -- Allow arbitrary movement. + self.cursor.ypos = wy + return true + + else -- Dragging in some mode. + self.cursor.is_drag = true -- Crossing a tile boundary implies 'real' dragging. + + -- Update wx and wy according to drag capabilities. + local cap = self:getCursorDragCapabilities() + if cap == "north-south" then wx = self.cursor.leftx + elseif cap == "east-west" then wy = self.cursor.lefty + elseif cap == "none" then wx, wy = self.cursor.leftx, self.cursor.lefty -- Block all movement. + end + + repaint = repaint or self.cursor.xpos ~= wx or self.cursor.ypos ~= wy + self.cursor.xpos = wx + self.cursor.ypos = wy + return repaint + end + end +end + +--! Mouse button got pressed. +--!param button (string) Mouse button being pressed. +--!param xpos (int) Horizontal position of the mouse at the time of the mouse button press. +--!param ypos (int) Vertical position of the mouse at the time of the mouse button press. +--!return (bool) Whether to repaint the display. +function UIMapEditor:onMouseDown(button, xpos, ypos) + if UIResizable.onMouseDown(self, button, xpos, ypos) then -- Button in this window. + return true + end + + if self:hitTest(xpos, ypos) then -- Clicked elsewhere in the window. + return true + end + + local repaint = false + if self.cursor.state == "disabled" then + if button == "right" then + self.cursor.state = "right" + self.cursor.rightx = self.cursor.xpos + self.cursor.righty = self.cursor.ypos + end + + elseif self.cursor.state == "grid" then + -- LMB down switches to 'left' + if button == "left" then + self.cursor.state = "left" + self.cursor.leftx = self.cursor.xpos + self.cursor.lefty = self.cursor.ypos + -- RMB down switches to 'right' + elseif button == "right" then + self.cursor.state = "right" + self.cursor.rightx = self.cursor.xpos + self.cursor.righty = self.cursor.ypos + end + -- Since 'grid' already shows the red rectangles, nothing changes visually. + + elseif self.cursor.state == "delete" then + if button == "left" then + self.cursor.state = "delete-left" + self.cursor.leftx = self.cursor.xpos + self.cursor.lefty = self.cursor.ypos + elseif button == "right" then + self.cursor.state = "right" + self.cursor.rightx = self.cursor.xpos + self.cursor.righty = self.cursor.ypos + end + + elseif self.cursor.state == "parcel" then + if button == "left" then + self.cursor.state = "parcel-left" + self.cursor.leftx = self.cursor.xpos + self.cursor.lefty = self.cursor.ypos + elseif button == "right" then + self.cursor.state = "right" + self.cursor.rightx = self.cursor.xpos + self.cursor.righty = self.cursor.ypos + end + + elseif self.cursor.state == "left" then + -- If RMB is down, switch to 'both'. + if button == "right" then + self.cursor.state = "both" + self.cursor.rightx = self.cursor.xpos + self.cursor.righty = self.cursor.ypos + repaint = true + end + + elseif self.cursor.state == "right" then + -- Ignore all down buttons, until RMB is released. + + elseif self.cursor.state == "paste" then + if button == "left" then + self.cursor.state = "paste-left" + self.cursor.leftx = self.cursor.xpos + self.cursor.lefty = self.cursor.ypos + elseif button == "right" then + self.cursor.state = "right" + self.cursor.rightx = self.cursor.xpos + self.cursor.righty = self.cursor.ypos + end + + -- "both", "delete-left", "parcel-left", "paste-left" do not handle buttons. + + end + + return repaint +end + +--! Add an object to the map. Currently, only "entrance_door" is supported. +--!param obj_type (str) Type of object ("entrance_door") +--!param xpos (int) Desired x position of the new object. +--!param ypos (int) Desired y position of the new object. +--!param direction (str) Direction of the new object ("north" or "west"). +function UIMapEditor:drawObject(obj_type, xpos, ypos, direction) + local world = self.ui.app.world + + -- TheApp.objects[name].thob + -- name = world.object_id_by_thob[thob] + -- generic object = world.object_types[object_id] + -- instance: world:getObject(x, y, name) + if obj_type == "entrance_door" then + world:newObject("entrance_right_door", xpos, ypos, direction) + if direction == "north" then + world:newObject("entrance_left_door", xpos - 1, ypos, direction) + else + world:newObject("entrance_left_door", xpos, ypos - 1, direction) + end + end +end + +--! Remove an entrance door from the world. +--!param door Entrance door to remove. +function UIMapEditor:removeDoor(door) + local world = self.ui.app.world + + world:destroyEntity(door) + if door.slave then + world:destroyEntity(door.slave) + end +end + +--! Collect other objects that use the space needed for the specified new object. +-- If they exist, return them or delete them. +--!param obj_type (str) Type of object ("entrance_door") +--!param xpos (int) Desired x position of the new object. +--!param ypos (int) Desired y position of the new object. +--!param direction (str) Direction of the new object ("north" or "west"). +--!param remove (bool) If set, remove the found objects. +--!return (list) The objects that use the space, if they are not removed. +function UIMapEditor:checkObjectSpace(obj_type, xpos, ypos, direction, remove) + local world = self.ui.app.world + local right_door = world.object_types["entrance_right_door"] + local left_door = world.object_types["entrance_left_door"] + local th = self.ui.app.map.th + + --! Check single tile for conflicts with other doors. + --!param x X position of the tile to check. + --!param y Y position of the tile to check. + --!return (int, int) position of the conflicting door, or (nil, nil) if no conflict. + local function checkTile(x, y) + local all_flags = th:getCellFlags(x, y) + if not all_flags.thob then + return nil, nil + elseif all_flags.thob == right_door.thob then + return x, y + elseif all_flags.thob == left_door.thob then + if all_flags.tallWest then + return x, y + 1 + else + return x + 1, y + end + end + return nil, nil + end + + -- While the general intention is 'objects', the only object that can exist + -- and is handled here is the entrance door. + assert(obj_type == "entrance_door") + local doors = {} + + local x, y = checkTile(xpos, ypos) + if x then + doors[#doors + 1] = world:getObject(x, y, "entrance_right_door") + end + + local x2, y2 + if direction == "north" then + x2, y2 = checkTile(xpos - 1, ypos) + else + x2, y2 = checkTile(xpos, ypos - 1) + end + + if x2 and (x2 ~= x or y2 ~= y) then + doors[#doors + 1] = world:getObject(x2, y2, "entrance_right_door") + end + + if remove then + for _, door in ipairs(doors) do self:removeDoor(door) end + return + end + return doors +end + +--! Recognize objects in the collection of thob+tallWest entries +--!param minx (int) Base horizontal position (objects should be put relative to it). +--!param miny (int) Base vertical position (objects should be put relative to it). +--!param thobdir_positions (table xy to {thob, tallWest}) Found thobs. +--!return (array of {type, xpos, ypos, direction}) Found objects. +function UIMapEditor:findObjects(minx, miny, thobdir_positions) + local world = self.ui.app.world + local right_door = world.object_types["entrance_right_door"] + local left_door = world.object_types["entrance_left_door"] + + local objects = {} -- Found objects ordered by position. + + -- Look for right entrance door. + for xy_right, thobdir_right in pairs(thobdir_positions) do + if right_door.thob == thobdir_right.thob then + -- Found right door, is there a matching left door? + local xy_left = thobdir_right.tallWest and xy_right - 256 or xy_right - 1 + local thobdir_left = thobdir_positions[xy_left] + if thobdir_left and thobdir_left.thob == left_door.thob and + thobdir_left.tallWest == thobdir_right.tallWest then + local obj = {type="entrance_door", + xpos = xy_right % 256 - minx + 1, + ypos = math.floor(xy_right / 256) - miny + 1, + direction=thobdir_right.tallWest and "west" or "north"} + objects[#objects + 1] = obj + end + end + end + + return objects +end + +--! Draw the selected sprite at the given coordinates. +--!param coords (array or {xpos, ypos} tables) Coordinates to draw the selected sprite. +function UIMapEditor:drawCursorSpriteAtArea(coords) + local th = self.ui.app.map.th + + if self.cursor.sprite then + for _, coord in ipairs(coords) do + local xbase, ybase = coord.xpos, coord.ypos + + -- Draw the selected sprite. + xbase, ybase = self:areaOnWorld(xbase, ybase, self.cursor.sprite.xsize, self.cursor.sprite.ysize) + for _, spr in ipairs(self.cursor.sprite.sprites) do + local tx, ty = xbase + spr.xpos - 1, ybase + spr.ypos - 1 + local f, nw, ww = th:getCell(tx, ty) -- floor, north-wall, west-wall (, ui) + if isFloorSpriteType(spr.type) then + f = spr.sprite + -- Floor sprite gets changed, also modify the cell flags. + th:setCellFlags(tx, ty, makeCellFlags(spr.type)) + + elseif spr.type == "north" then + nw = spr.sprite + + elseif spr.type == "west" then + ww = spr.sprite + end + + th:setCell(tx, ty, f, nw, ww, 0) + end + + -- Draw the objects + if self.cursor.sprite.objects then + for _, obj in ipairs(self.cursor.sprite.objects) do + local tx, ty = xbase + obj.xpos - 1, ybase + obj.ypos - 1 + self:drawObject(obj.type, tx, ty, obj.direction) + end + end + end + end +end + +--! Copy area from the game. +--!return (bool) Whether copying succeeded. +function UIMapEditor:copyArea() + local th = self.ui.app.map.th + + local minx, miny, maxx, maxy = getCoveredArea(self.cursor.rightx, self.cursor.righty, + self.cursor.xpos, self.cursor.ypos) + if minx == maxx and miny == maxy and self.is_drag then + return false -- Canceled drag + end + + local thobdir_positions = {} + + -- Copy data. + self.cursor.copy_data = {} + self.cursor.copy_xsize = maxx - minx + 1 + self.cursor.copy_ysize = maxy - miny + 1 + + local tx, ty + tx = minx + while tx <= maxx do + ty = miny + while ty <= maxy do + local f, nw, ww = th:getCell(tx, ty) + local all_flags = th:getCellFlags(tx, ty) + self.cursor.copy_data[#self.cursor.copy_data + 1] = { + xpos = tx - minx, + ypos = ty - miny, + floor = f, + north_wall = nw, + west_wall = ww, + flags = {buildable = all_flags.buildable, + passable = all_flags.passable, + hospital = all_flags.hospital}, + } + if all_flags.thob and all_flags.thob ~= 0 then + thobdir_positions[tx + 256 * ty] = {thob = all_flags.thob, + tallWest = all_flags.tallWest} + end + + ty = ty + 1 + end + tx = tx + 1 + end + self.cursor.copy_objects = self:findObjects(minx, miny, thobdir_positions) + + return true +end + +--! Paste copied area into the destination area (one or more times). +function UIMapEditor:pasteArea() + local th = self.ui.app.map.th + + local minx, miny, maxx, maxy + -- Fill 'minx', 'miny' with the non-cursor corner. + if self.cursor.leftx == self.cursor.xpos and self.cursor.lefty == self.cursor.ypos then + if self.is_drag then + return -- Canceled paste area. + end + + minx = self.cursor.xpos + self.cursor.copy_xsize - 1 + miny = self.cursor.ypos + self.cursor.copy_ysize - 1 + minx, miny = self:areaOnWorld(minx, miny, 1, 1) + else + minx = self.cursor.leftx + miny = self.cursor.lefty + end + + minx, miny, maxx, maxy = getCoveredArea(minx, miny, self.cursor.xpos, self.cursor.ypos) + -- Copy area in 'sub-areas' of (self.cursor.copy_xsize, self.cursor.copy_ysize). + local tx, ty + tx = minx + while tx <= maxx do + ty = miny + while ty <= maxy do + -- Copy floor and wall sprites, and set the passable/buildable/hospital flag. + for _, elm in ipairs(self.cursor.copy_data) do + local x, y = tx + elm.xpos, ty + elm.ypos + if x <= maxx and y <= maxy then + th:setCell(x, y, elm.floor, elm.north_wall, elm.west_wall, 0) + th:setCellFlags(x, y, elm.flags) + end + end + -- Make room for the new objects. + for _, obj in ipairs(self.cursor.copy_objects) do + local x, y = tx + obj.xpos - 1, ty + obj.ypos - 1 + if x <= maxx and y <= maxy then + self:checkObjectSpace(obj.type, x, y, obj.direction, true) + end + end + -- Paste the objects of the copied area. + for _, obj in ipairs(self.cursor.copy_objects) do + local x, y = tx + obj.xpos - 1, ty + obj.ypos - 1 + if x <= maxx and y <= maxy then + self:drawObject(obj.type, x, y, obj.direction) + end + end + + ty = ty + self.cursor.copy_ysize + end + tx = tx + self.cursor.copy_xsize + end +end + +--! Delete the walls at the given coordinates. +--!param coords (array or {xpos, ypos} tables) Coordinates to remove the walls. +function UIMapEditor:deleteWallsAtArea(coords) + local th = self.ui.app.map.th + + local thobdir_positions = {} -- Storage for found objects. + + for _, coord in ipairs(coords) do + local tx, ty = coord.xpos, coord.ypos + -- Remove west and north wall. + local f = th:getCell(tx, ty) -- floor (, north-wall, west-wall , ui) + th:setCell(tx, ty, f, 0, 0, 0) + -- No need for map:setCellFlags, as 'passable', 'buildable', and 'hospital' are floor properties. + + -- Collect thobs, to remove next. + local all_flags = th:getCellFlags(tx, ty) + if all_flags.thob ~= 0 then + thobdir_positions[tx + ty * 256] = {thob=all_flags.thob, + tallWest=all_flags.tallWest} + end + end + + -- Remove objects from the area. + local objects = self:findObjects(1, 1, thobdir_positions) -- Uses absolute position for the objects + for _, obj in ipairs(objects) do + self:checkObjectSpace(obj.type, obj.xpos, obj.ypos, obj.direction, true) + end +end + +--! Set parcel number at the given coordinates. +--!param coords (array or {xpos, ypos} tables) Coordinates to set parcel. +--!param parcel_num (int) Parcel number to set. +function UIMapEditor:setParcelAtArea(coords, parcel_num) + local th = self.ui.app.map.th + + for _, coord in ipairs(coords) do + local tx, ty = coord.xpos, coord.ypos + th:setCellFlags(tx, ty, {parcelId = parcel_num}) + end +end + +--! Mouse button was released. +--!param button (string) Mouse button being released. +--!param x (int) Horizontal position of the mouse at the time of the mouse button release. +--!param y (int) Vertical position of the mouse at the time of the mouse button release. +--!return (bool) Whether to repaint the display. +function UIMapEditor:onMouseUp(button, x, y) + local map = self.ui.app.map + + if UIResizable.onMouseUp(self, button, x, y) then + return true + end + + if self:hitTest(x, y) then + return true + end + + --! Get the cursor mode to jump to after ending the drag mode. + --!return (string) New cursor mode. + local function newState() + if self.cursor.sprite then + return "grid" + else + return "disabled" + end + end + + + local repaint = false + if self.cursor.state == "disabled" then + -- Don't care about buttons. + + elseif self.cursor.state == "left" then + if button == "left" then + -- Simple drag (left button only). + self:drawCursorSpriteAtArea(self:getDrawPoints()) + + self.cursor.state = newState() + self.cursor.is_drag = false + repaint = true + end + + elseif self.cursor.state == "delete-left" then + if button == "left" then + self:deleteWallsAtArea(self:getDrawPoints()) + + self.cursor.state = "delete" + self.cursor.is_drag = false + repaint = true + end + + elseif self.cursor.state == "parcel-left" then + if button == "left" then + self:setParcelAtArea(self:getDrawPoints(), self.cursor.parcel) + map:updateDebugOverlay() + + self.cursor.state = "parcel" + self.cursor.is_drag = false + repaint = true + end + + elseif self.cursor.state == "camera" then + if button == "left" then + local dp = self:getDrawPoints() + map:setCameraTile(dp[1].xpos, dp[1].ypos, self.cursor.camera) + map:updateDebugOverlay() + repaint = true + end + + elseif self.cursor.state == "heliport" then + if button == "left" then + local dp = self:getDrawPoints() + map:setHeliportTile(dp[1].xpos, dp[1].ypos, self.cursor.heliport) + map:updateDebugOverlay() + repaint = true + end + + elseif self.cursor.state == "right" then + if button == "right" then + if self:copyArea() then + self.cursor.state = "paste" + self:pageClicked("paste") + self.cursor.is_drag = false + repaint = true + else + self.cursor.state = "disabled" -- Copy area was canceled. + self.cursor.is_drag = false + repaint = true + end + end + + elseif self.cursor.state == "paste-left" then + if button == "left" then + self.cursor.state = "paste" + self.cursor.is_drag = false + repaint = true + self:pasteArea() + end + + elseif self.cursor.state == "both" then + if button == "left" then -- Only care about left button. + -- left+right drag ends. + self:drawCursorSpriteAtArea(self:getDrawPoints()) + + self.cursor.state = newState() + self.cursor.is_drag = false + repaint = true + end + -- "grid", "delete", "parcel", and "paste" already assumed no buttons pushed, + -- ignore event. + + end + + return repaint +end + diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/menu_list_dialog.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/menu_list_dialog.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/menu_list_dialog.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/menu_list_dialog.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! A menu list with a scrollbar. Used by load_game, save_game and custom_game. class "UIMenuList" (UIResizable) +---@type UIMenuList +local UIMenuList = _G["UIMenuList"] + local col_caption = { red = 174, green = 166, @@ -40,22 +43,21 @@ !param items (table) A list of items to include in the list. Each listing should be a table with keys "name" and "tooltip" with the corresponding values. !param num_rows (integer) The number of rows displayed at a given time. Default is 10. -!param extra_above_list (integer) How much space, if any, the dialog will need above the list. +!param extra_beside_list (integer) How much space, if any, the dialog will need to the right of the list, e.g. information space. ]] -function UIMenuList:UIMenuList(ui, mode, title, items, num_rows, extra_above_list) +function UIMenuList:UIMenuList(ui, mode, title, items, num_rows, extra_beside_list) self.col_bg = { red = 154, green = 146, blue = 198, } - extra_above_list = extra_above_list or 0 - self:UIResizable(ui, 280, 270 + extra_above_list, self.col_bg) + extra_beside_list = extra_beside_list or 0 + self:UIResizable(ui, 280 + extra_beside_list, 270, self.col_bg) self.default_button_sound = "selectx.wav" self.items = items self.num_rows = num_rows and num_rows or 10 - local app = ui.app self.mode = mode self.modal_class = mode == "menu" and "main menu" or "saveload" self.on_top = mode == "menu" @@ -63,18 +65,17 @@ self.resizable = false self:setDefaultPosition(0.5, 0.25) - self:addBevelPanel(20, 10, 240, 20, col_caption):setLabel(title) - .lowered = true + self:addBevelPanel(20, 10, 240, 20, col_caption):setLabel(title).lowered = true - local scrollbar_base = self:addBevelPanel(240, 40 + extra_above_list, 20, self.num_rows*17, self.col_bg) + local scrollbar_base = self:addBevelPanel(240, 40, 20, self.num_rows * 17, self.col_bg) scrollbar_base.lowered = true - self.scrollbar = scrollbar_base:makeScrollbar(col_scrollbar, --[[persistable:menu_list_scrollbar_callback]] function() - self:updateButtons() - end, 1, math.max(#items, 1), self.num_rows) + self.scrollbar = scrollbar_base:makeScrollbar(col_scrollbar, + --[[persistable:menu_list_scrollbar_callback]] function() self:updateButtons() end, + 1, math.max(#items, 1), self.num_rows) local function button_clicked(num) - return --[[persistable:menu_list_button]] function(self) - self:buttonClicked(num) + return --[[persistable:menu_list_button]] function(window) + window:buttonClicked(num) end end @@ -82,11 +83,11 @@ self.item_buttons = {} for num = 1, self.num_rows do - self.item_panels[num] = self:addBevelPanel(20, 40 + extra_above_list + (num - 1) * 17, 210, 17, self.col_bg):setLabel(nil, nil, "centre") + self.item_panels[num] = self:addBevelPanel(20, 40 + (num - 1) * 17, 210, 17, self.col_bg):setLabel(nil, nil, "center") self.item_buttons[num] = self.item_panels[num]:makeButton(0, 0, 220, 17, nil, button_clicked(num)) end - self:addBevelPanel(20, 220 + extra_above_list, 240, 40, self.col_bg):setLabel(_S.menu_list_window.back) + self:addBevelPanel(20, 220, 240, 40, self.col_bg):setLabel(_S.menu_list_window.back) :makeButton(0, 0, 240, 40, nil, self.buttonBack):setTooltip(_S.tooltip.menu_list_window.back) self:updateButtons() diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/custom_campaign.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/custom_campaign.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/custom_campaign.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/custom_campaign.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,128 @@ +--[[ Copyright (c) 2014 Edvin "Lego3" Linge + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +local pathsep = package.config:sub(1, 1) + +--! Custom Campaign Window +class "UICustomCampaign" (UIMenuList) + +---@type UICustomCampaign +local UICustomCampaign = _G["UICustomCampaign"] + +local col_scrollbar = { + red = 164, + green = 156, + blue = 208, +} + +local details_width = 280 + +--! Collect the campaign levels at the provided path +--!param path (str) File system path to search. +--!return (array) The found levels, with some basic information about each level. +local function createCampaignList(path) + local campaigns = {} + + for file in lfs.dir(path) do + if file:match"%.campaign$" then + local campaign_info, err = TheApp:readCampaignFile(file) + if not campaign_info then + print(err) + else + if campaign_info.levels and #campaign_info.levels > 0 then + campaigns[#campaigns + 1] = { + name = campaign_info.name, + tooltip = _S.tooltip.custom_campaign_window.choose_campaign, + no_levels = #campaign_info.levels, + path = file, + description = campaign_info.description, + } + else + print("Warning: Loaded campaign that had no levels specified") + end + end + end + end + return campaigns +end + +function UICustomCampaign:UICustomCampaign(ui) + self.label_font = TheApp.gfx:loadFont("QData", "Font01V") + + local local_path = debug.getinfo(1, "S").source:sub(2, -61) + local dir = "Campaigns" .. pathsep + local path = local_path .. dir + + local campaigns = createCampaignList(path) + + self:UIMenuList(ui, "menu", _S.custom_campaign_window.caption, campaigns, 10, details_width + 40) + + -- Create a toolbar ready to be used if the description for a level is + -- too long to fit + local scrollbar_base = self:addBevelPanel(560, 40, 20, self.num_rows*17, self.col_bg) + scrollbar_base.lowered = true + self.details_scrollbar = scrollbar_base:makeScrollbar(col_scrollbar, --[[persistable:campaign_details_scrollbar_callback]] function() + self:updateDescriptionOffset() + end, 1, 1, self.num_rows) + + self.description_offset = 0 + + -- Finally the load button + self:addBevelPanel(420, 220, 160, 40, self.col_bg) + :setLabel(_S.custom_campaign_window.start_selected_campaign) + :makeButton(0, 0, 160, 40, 11, self.buttonStartCampaign) + :setTooltip(_S.tooltip.custom_campaign_window.start_selected_campaign) +end + +-- Overrides the function in the UIMenuList, choosing what should happen when the player +-- clicks a choice in the list. +function UICustomCampaign:buttonClicked(num) + local item = self.items[num + self.scrollbar.value - 1] + self.chosen_item = item + if item.description then + local _, _, rows = self.label_font:sizeOf(item.description, details_width) + self.details_scrollbar:setRange(1, rows, 13, 1) + else + self.details_scrollbar:setRange(1, 13, 13, 1) + end + self.description_offset = 0 +end + +function UICustomCampaign:buttonStartCampaign() + if self.chosen_item then + TheApp:loadCampaign(self.chosen_item.path) + end +end + +function UICustomCampaign:draw(canvas, x, y) + UIMenuList.draw(self, canvas, x, y) + x, y = self.x + x, self.y + y + + if self.chosen_item and self.chosen_item.name then + self.label_font:drawWrapped(canvas, self.chosen_item.name, + x + 270, y + 10, details_width) + self.label_font:drawWrapped(canvas, "(levels: " .. + self.chosen_item.no_levels .. ")", x+ 270, y + 22, details_width) + end + if self.chosen_item and self.chosen_item.description then + self.label_font:drawWrapped(canvas, self.chosen_item.description, + x + 270, y + 40, details_width, nil, 13, self.description_offset) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/custom_game.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/custom_game.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/custom_game.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/custom_game.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010 Edvin "Lego3" Linge +--[[ Copyright (c) 2010-2014 Edvin "Lego3" Linge Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -18,51 +18,62 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local pathsep = package.config:sub(1, 1) - --! Custom Game Window class "UICustomGame" (UIMenuList) -function UICustomGame:UICustomGame(ui) - - -- Supply the required list of items to UIMenuList - local path = debug.getinfo(1, "S").source:sub(2, -57) - - path = path .. "Levels" .. pathsep +---@type UICustomGame +local UICustomGame = _G["UICustomGame"] - -- Create the actual list - local items = {} +local col_scrollbar = { + red = 164, + green = 156, + blue = 208, +} + +local details_width = 280 + +--! Compile metainfo for all of the levels in the given path. +--!param path (string) The path that should contain level files. +--!param items (table) Table to insert the level metadata into. +local findLevelsInDir = function(path, items) for file in lfs.dir(path) do if file:match"%.level$" then - local level_name, level_file, level_intro - for line in io.lines(path .. pathsep .. file) do - -- Get level name and name of the level file to load - if line:sub(1, 1) == "%" then - for text in line:gmatch("\".+\"") do - if line:find("Name") then - level_name = text - elseif line:find("LevelFile") then - level_file = text - elseif line:find("LevelBriefing") then - level_intro = text - end - end - end - end - if level_name and level_file then + local level_info = TheApp:readLevelFile(file) + if level_info.name and level_info.map_file then items[#items + 1] = { - name = level_name, - tooltip = _S.tooltip.custom_game_window.start_game_with_name:format(level_file, level_intro), - level_file = level_file, - path = path .. file, - intro = level_intro, + name = level_info.name, + tooltip = _S.tooltip.custom_game_window.choose_game, + map_file = level_info.map_file, + level_file = file, + intro = level_info.briefing, + deprecated_variable_used = level_info.deprecated_variable_used, } end end end - self:UIMenuList(ui, "menu", _S.custom_game_window.caption, items, 10, 30) +end + +function UICustomGame:UICustomGame(ui) + self.label_font = TheApp.gfx:loadFont("QData", "Font01V") + + -- Supply the required list of items to UIMenuList + -- Create the actual list + local items = {} + findLevelsInDir(TheApp.level_dir, items) + findLevelsInDir(TheApp.user_level_dir, items) + self:UIMenuList(ui, "menu", _S.custom_game_window.caption, items, 10, details_width + 40) + + -- Create a toolbar ready to be used if the description for a level is + -- too long to fit + local scrollbar_base = self:addBevelPanel(560, 40, 20, self.num_rows*17, self.col_bg) + scrollbar_base.lowered = true + self.details_scrollbar = scrollbar_base:makeScrollbar(col_scrollbar, --[[persistable:menu_list_details_scrollbar_callback]] function() + self:updateDescriptionOffset() + end, 1, 1, self.num_rows) - -- Now add the free build button above the list. + self.description_offset = 0 + + -- Now add the free build button beside the list. if not pcall(function() local palette = ui.app.gfx:loadPalette("QData", "DrugN01V.pal") self.panel_sprites = ui.app.gfx:loadSpriteTable("QData", "DrugN02V", true, palette) @@ -72,34 +83,74 @@ return end - self:addBevelPanel(20, 40, 200, 20, self.col_bg):setLabel(_S.custom_game_window.free_build).lowered = true - local button = self:addPanel(12, 230, 36):makeToggleButton(0, 0, 29, 29, 11, self.buttonFreebuild) + self:addBevelPanel(280, 230, 140, 20, self.col_bg):setLabel(_S.custom_game_window.free_build).lowered = true + local button = self:addPanel(12, 430, 225):makeToggleButton(0, 0, 29, 29, 11, self.buttonFreebuild) :setTooltip(_S.tooltip.custom_game_window.free_build) if self.ui.app.config.free_build_mode then button:toggle() end + + -- Finally the load button + self:addBevelPanel(480, 220, 100, 40, self.col_bg) + :setLabel(_S.custom_game_window.load_selected_level) + :makeButton(0, 0, 100, 40, 11, self.buttonLoadLevel) + :setTooltip(_S.tooltip.custom_game_window.load_selected_level) +end + +function UICustomGame:updateDescriptionOffset() + self.description_offset = self.details_scrollbar.value - 1 end -- Overrides the function in the UIMenuList, choosing what should happen when the player -- clicks a choice in the list. function UICustomGame:buttonClicked(num) - local app = self.ui.app local item = self.items[num + self.scrollbar.value - 1] - local level_name = item.name:sub(2, -2) - local level_file = item.level_file:sub(2, -2) - local level_intro = item.intro and item.intro:sub(2, -2) - local filename = item.path - -- First make sure the map file exists. - local _, errors = app:readLevelDataFile(level_file) - if errors then - self.ui:addWindow(UIInformation(self.ui, {errors})) - return + self.chosen_index = num + self.chosen_level_name = item.name + self.chosen_level_description = item.intro + if self.chosen_level_description then + local _, y, rows = self.label_font:sizeOf(self.chosen_level_description, details_width) + local row_height = y / rows + self.max_rows_shown = math.floor(self.num_rows*17 / row_height) + self.details_scrollbar:setRange(1, rows, math.min(rows, self.max_rows_shown), 1) + else + self.details_scrollbar:setRange(1, 1, 1, 1) + end + self.description_offset = 0 + + if item.deprecated_variable_used then + self.ui:addWindow(UIInformation(self.ui, {_S.warnings.levelfile_variable_is_deprecated:format(item.name)})) + end +end + +function UICustomGame:buttonLoadLevel() + if self.chosen_index then + -- First make sure the map file exists. + local item = self.items[self.chosen_index + self.scrollbar.value - 1] + local app = self.ui.app + local _, errors = app:readMapDataFile(item.map_file) + if errors then + self.ui:addWindow(UIInformation(self.ui, {errors})) + return + end + app:loadLevel(item.level_file, nil, self.chosen_level_name, item.map_file, self.chosen_level_description) end - app:loadLevel(filename, nil, level_name, level_file, level_intro) end function UICustomGame:buttonFreebuild(checked) self.ui.app.config.free_build_mode = checked end - +function UICustomGame:draw(canvas, x, y) + UIMenuList.draw(self, canvas, x, y) + x, y = self.x + x, self.y + y + + if self.chosen_level_name then + self.label_font:drawWrapped(canvas, self.chosen_level_name, + x + 270, y + 10, details_width) + end + if self.chosen_level_description then + self.label_font:drawWrapped(canvas, self.chosen_level_description, + x + 270, y + 40, details_width, nil, self.max_rows_shown, self.description_offset) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/make_debug_patient.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/make_debug_patient.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/make_debug_patient.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/menu_list_dialogs/make_debug_patient.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,6 +20,9 @@ class "UIMakeDebugPatient" (UIMenuList) +---@type UIMakeDebugPatient +local UIMakeDebugPatient = _G["UIMakeDebugPatient"] + function UIMakeDebugPatient:UIMakeDebugPatient(ui) local items = {} for _, disease in ipairs(ui.app.diseases) do diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/new_game.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/new_game.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/new_game.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/new_game.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,18 +21,15 @@ --! Class for the difficulty choice window. class "UINewGame" (UIResizable) +---@type UINewGame +local UINewGame = _G["UINewGame"] + local col_bg = { red = 154, green = 146, blue = 198, } -local col_button = { - red = 84, - green = 180, - blue = 84, -} - local col_caption = { red = 174, green = 166, @@ -162,11 +159,10 @@ if (0 <= x and x < self.width) or (0 <= y and y < self.height) then return true end - local test = sprites.hitTest - return test(sprites, 10, x + 9, y + 9) - or test(sprites, 12, x - 160, y + 9) - or test(sprites, 15, x + 9, y - 240) - or test(sprites, 17, x - 160, y - 240) + return sprites.hitTest(sprites, 10, x + 9, y + 9) or + sprites.hitTest(sprites, 12, x - 160, y + 9) or + sprites.hitTest(sprites, 15, x + 9, y - 240) or + sprites.hitTest(sprites, 17, x - 160, y - 240) end function UINewGame:buttonTutorial(checked, button) @@ -198,6 +194,10 @@ function UINewGame:startGame(difficulty) self.ui.app:loadLevel(1, difficulty) + -- Initiate campaign progression. The UI above may now have changed. + if not TheApp.using_demo_files then + TheApp.world.campaign_info = "TH.campaign" + end if self.start_tutorial then TheApp.ui.start_tutorial = true TheApp.ui:startTutorial() diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/options.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/options.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/options.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/options.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,18 +21,15 @@ --! Options window used in the main menu and ingame. class "UIOptions" (UIResizable) +---@type UIOptions +local UIOptions = _G["UIOptions"] + local col_bg = { red = 154, green = 146, blue = 198, } -local col_button = { - red = 84, - green = 200, - blue = 84, -} - local col_textbox = { red = 0, green = 0, @@ -57,8 +54,27 @@ blue = 218, } +-- Private functions + +--- Calculates the Y position for the dialog box in the option menu +-- and increments along the current position for the next element +-- @return The Y position to place the element at + +function UIOptions:_getOptionYPos() + -- Offset from top of options box + local STARTING_Y_POS = 15 + -- Y Height is 20 for panel size + 10 for spacing + local Y_HEIGHT = 30 + + -- Multiply by the index so that index=1 is at STARTING_Y_POS + local calculated_pos = STARTING_Y_POS + Y_HEIGHT * (self._current_option_index - 1) + self._current_option_index = self._current_option_index + 1 + return calculated_pos +end + + function UIOptions:UIOptions(ui, mode) - self:UIResizable(ui, 320, 240, col_bg) + self:UIResizable(ui, 320, 300, col_bg) local app = ui.app self.mode = mode @@ -70,6 +86,13 @@ self.default_button_sound = "selectx.wav" self.app = app + -- Tracks the current position of the object + self._current_option_index = 1 + + -- Constants for most button's width and height + local BTN_WIDTH = 135 + local BTN_HEIGHT = 20 + self:checkForAvailableLanguages() -- Set up list of resolutions @@ -85,6 +108,7 @@ {text = "1600x900 (16:9)", width = 1600, height = 900}, {text = "1920x1080 (16:9)", width = 1920, height = 1080}, {text = "1280x800 (16:10)", width = 1280, height = 800}, + {text = "1440x900 (16:10)", width = 1440, height = 900}, {text = "1680x1050 (16:10)", width = 1680, height = 1050}, {text = "1920x1200 (16:10)", width = 1920, height = 1200}, {text = _S.options_window.custom_resolution, custom = true}, @@ -92,50 +116,78 @@ -- Window parts definition -- Title - self:addBevelPanel(80, 10, 165, 20, col_caption):setLabel(_S.options_window.caption) + local title_y_pos = self:_getOptionYPos() + self:addBevelPanel(80, title_y_pos, 165, 20, col_caption):setLabel(_S.options_window.caption) .lowered = true -- Fullscreen - self:addBevelPanel(20, 45, 135, 20, col_shadow, col_bg, col_bg) + local fullscreen_y_pos = self:_getOptionYPos() + self:addBevelPanel(20, fullscreen_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg) :setLabel(_S.options_window.fullscreen):setTooltip(_S.tooltip.options_window.fullscreen).lowered = true self.fullscreen_panel = - self:addBevelPanel(165, 45, 135, 20, col_bg):setLabel(app.fullscreen and _S.options_window.option_on or _S.options_window.option_off) - self.fullscreen_button = self.fullscreen_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonFullscreen) + self:addBevelPanel(165, fullscreen_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.fullscreen and _S.options_window.option_on or _S.options_window.option_off) + self.fullscreen_button = self.fullscreen_panel:makeToggleButton(0, 0, 140, BTN_HEIGHT, nil, self.buttonFullscreen) :setToggleState(app.fullscreen):setTooltip(_S.tooltip.options_window.fullscreen_button) -- Screen resolution - self:addBevelPanel(20, 70, 135, 20, col_shadow, col_bg, col_bg) + local screen_res_y_pos = self:_getOptionYPos() + self:addBevelPanel(20, screen_res_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg) :setLabel(_S.options_window.resolution):setTooltip(_S.tooltip.options_window.resolution).lowered = true + self.resolution_panel = self:addBevelPanel(165, screen_res_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.config.width .. "x" .. app.config.height) + + self.resolution_button = self.resolution_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.dropdownResolution):setTooltip(_S.tooltip.options_window.select_resolution) + + -- Mouse capture + local capture_mouse_y_pos = self:_getOptionYPos() + self:addBevelPanel(20, capture_mouse_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg) + :setLabel(_S.options_window.capture_mouse):setTooltip(_S.tooltip.options_window.capture_mouse).lowered = true + + self.mouse_capture_panel = + self:addBevelPanel(165, capture_mouse_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.config.capture_mouse and _S.options_window.option_on or _S.options_window.option_off) + + self.mouse_capture_button = self.mouse_capture_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.buttonMouseCapture) + :setToggleState(app.config.capture_mouse):setTooltip(_S.tooltip.options_window.capture_mouse) - self.resolution_panel = self:addBevelPanel(165, 70, 135, 20, col_bg):setLabel(app.config.width .. "x" .. app.config.height) - self.resolution_button = self.resolution_panel:makeToggleButton(0, 0, 135, 20, nil, self.dropdownResolution):setTooltip(_S.tooltip.options_window.select_resolution) -- Language - local lang = string.upper(app.config.language) - self:addBevelPanel(20, 95, 135, 20, col_shadow, col_bg, col_bg) + -- Get language name in the language to normalize display. + -- If it doesn't exist, display the current config option. + local lang = self.app.strings:getLanguageNames(app.config.language) + if lang then + lang = lang[1] + else + lang = app.config.language + end + + local lang_y_pos = self:_getOptionYPos() + self:addBevelPanel(20, lang_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg) :setLabel(_S.options_window.language):setTooltip(_S.tooltip.options_window.language).lowered = true - self.language_panel = self:addBevelPanel(165, 95, 135, 20, col_bg):setLabel(lang) - self.language_button = self.language_panel:makeToggleButton(0, 0, 135, 20, nil, self.dropdownLanguage):setTooltip(_S.tooltip.options_window.select_language) + self.language_panel = self:addBevelPanel(165, lang_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(lang) + self.language_button = self.language_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.dropdownLanguage):setTooltip(_S.tooltip.options_window.select_language) -- add the Audio global switch. - self:addBevelPanel(20, 120, 135, 20, col_shadow, col_bg, col_bg) + local audio_y_pos = self:_getOptionYPos() + self:addBevelPanel(20, audio_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg) :setLabel(_S.options_window.audio):setTooltip(_S.tooltip.options_window.audio_button).lowered = true self.volume_panel = - self:addBevelPanel(165, 120, 135, 20, col_bg):setLabel(app.config.audio and _S.customise_window.option_on or _S.customise_window.option_off) - self.volume_button = self.volume_panel:makeToggleButton(0, 0, 135, 20, nil, self.buttonAudioGlobal) + self:addBevelPanel(165, audio_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.config.audio and _S.customise_window.option_on or _S.customise_window.option_off) + self.volume_button = self.volume_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.buttonAudioGlobal) :setToggleState(app.config.audio):setTooltip(_S.tooltip.options_window.audio_toggle) -- "Customise" button - self:addBevelPanel(20, 150, 135, 30, col_bg):setLabel(_S.options_window.customise) - :makeButton(0, 0, 135, 30, nil, self.buttonCustomise):setTooltip(_S.tooltip.options_window.customise_button) + local customise_y_pos = self:_getOptionYPos() + self:addBevelPanel(20, customise_y_pos, BTN_WIDTH, 30, col_bg):setLabel(_S.options_window.customise) + :makeButton(0, 0, BTN_WIDTH, 30, nil, self.buttonCustomise):setTooltip(_S.tooltip.options_window.customise_button) -- "Folders" button - self:addBevelPanel(165, 150, 135, 30, col_bg):setLabel(_S.options_window.folder) - :makeButton(0, 0, 135, 30, nil, self.buttonFolder):setTooltip(_S.tooltip.options_window.folder_button) + self:addBevelPanel(165, customise_y_pos, BTN_WIDTH, 30, col_bg):setLabel(_S.options_window.folder) + :makeButton(0, 0, BTN_WIDTH, 30, nil, self.buttonFolder):setTooltip(_S.tooltip.options_window.folder_button) -- "Back" button - self:addBevelPanel(20, 190, 280, 40, col_bg):setLabel(_S.options_window.back) + -- Give some extra space to back button. This is fine as long as it is the last button in the options menu + local back_button_y_pos = self:_getOptionYPos() + 15 + self:addBevelPanel(20, back_button_y_pos, 280, 40, col_bg):setLabel(_S.options_window.back) :makeButton(0, 0, 280, 40, nil, self.buttonBack):setTooltip(_S.tooltip.options_window.back) end @@ -221,6 +273,13 @@ self.fullscreen_panel:setLabel(self.ui.app.fullscreen and _S.options_window.option_on or _S.options_window.option_off) end +function UIOptions:buttonMouseCapture(checked) + local app = self.ui.app + app.config.capture_mouse = not app.config.capture_mouse + app:saveConfig() + app:setCaptureMouse() + self.mouse_capture_button:setLabel(app.config.capture_mouse and _S.options_window.option_on or _S.options_window.option_off) +end function UIOptions:buttonCustomise() local window = UICustomise(self.ui, "menu") @@ -272,6 +331,9 @@ --! A custom resolution selection window class "UIResolution" (UIResizable) +---@type UIResolution +local UIResolution = _G["UIResolution"] + function UIResolution:UIResolution(ui, callback) self:UIResizable(ui, 200, 140, col_bg) @@ -338,3 +400,4 @@ self.callback(tonumber(self.width_textbox.text) or 0, tonumber(self.height_textbox.text) or 0) end end + diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/tip_of_the_day.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/tip_of_the_day.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/tip_of_the_day.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/tip_of_the_day.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Tip of the Day Window class "UITipOfTheDay" (UIResizable) +---@type UITipOfTheDay +local UITipOfTheDay = _G["UITipOfTheDay"] + local col_bg = { red = math.random(20, 200), green = math.random(20, 200), diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/update.lua corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/update.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/resizables/update.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/resizables/update.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,19 +21,15 @@ --! Options window used in the main menu and ingame. class "UIUpdate" (UIResizable) +---@type UIUpdate +local UIUpdate = _G["UIUpdate"] + local col_bg = { red = 154, green = 146, blue = 198, } -local col_button = { - red = 84, - green = 200, - blue = 84, -} - - local col_old_version = { red = 255, green = 0, diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/staff_dialog.lua corsix-th-0.62/CorsixTH/Lua/dialogs/staff_dialog.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/staff_dialog.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/staff_dialog.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,10 +18,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" -local math_floor - = math.floor - -- Test for hit within the view circle local --[[persistable:staff_dialog_is_in_view_circle]] function is_in_view_circle(x, y, is_handyman) local circle_center_y = is_handyman and 276 or 248 @@ -31,6 +27,10 @@ --! Individual staff information dialog class "UIStaff" (Window) +---@type UIStaff +local UIStaff = _G["UIStaff"] + +--! Callback function for handyman to change his parcel. function UIStaff:changeParcel() local index = 0 for i, v in ipairs(self.staff.hospital.ownedPlots) do @@ -93,9 +93,9 @@ end self:addPanel(302, 5, 205) -- View circle top/Wage self:addPanel(313, 15, 189) -- Tasks bottom - self:addPanel(314, 37, 145):makeButton(0, 0, 49, 48, 315, self.doMoreCleaning):setTooltip(_S.tooltip.handyman_window.prio_litter) - self:addPanel(316, 92, 145):makeButton(0, 0, 49, 48, 317, self.doMoreWatering):setTooltip(_S.tooltip.handyman_window.prio_plants) - self:addPanel(318, 148, 145):makeButton(0, 0, 49, 48, 319, self.doMoreRepairing):setTooltip(_S.tooltip.handyman_window.prio_machines) + self:addPanel(314, 37, 145):makeRepeatButton(0, 0, 49, 48, 315, self.doMoreCleaning):setTooltip(_S.tooltip.handyman_window.prio_litter) + self:addPanel(316, 92, 145):makeRepeatButton(0, 0, 49, 48, 317, self.doMoreWatering):setTooltip(_S.tooltip.handyman_window.prio_plants) + self:addPanel(318, 148, 145):makeRepeatButton(0, 0, 49, 48, 319, self.doMoreRepairing):setTooltip(_S.tooltip.handyman_window.prio_machines) self:addPanel(240, 21, 210):makeButton(0, 0, 73, 30, 240, self.changeParcel):setTooltip(_S.tooltip.handyman_window.parcel_select) self:addPanel(303, 0, 253) -- View circle midpiece self:addPanel(304, 6, 302) -- View circle bottom @@ -176,11 +176,10 @@ font:draw(canvas, "$" .. profile.wage, x + 135, y + 226) -- Wage font:draw(canvas, self:getParcelText(), x + 35, y + 215, 50, 0) -- The concentration areas - local cleaning_width, watering_width, repairing_width = 0, 0, 0 if self.staff.attributes["cleaning"] then -- Backwards compatibility - cleaning_width = math_floor(self.staff.attributes["cleaning"] * 40 + 0.5) - watering_width = math_floor(self.staff.attributes["watering"] * 40 + 0.5) - repairing_width = math_floor(self.staff.attributes["repairing"] * 40 + 0.5) + local cleaning_width = math.floor(self.staff.attributes["cleaning"] * 40 + 0.5) + local watering_width = math.floor(self.staff.attributes["watering"] * 40 + 0.5) + local repairing_width = math.floor(self.staff.attributes["repairing"] * 40 + 0.5) if cleaning_width ~= 0 then for dx = 0, cleaning_width - 1 do self.panel_sprites:draw(canvas, 351, x + 43 + dx, y + 200) @@ -202,7 +201,7 @@ end if self.staff.attributes["happiness"] then - local happiness_bar_width = math_floor(self.staff.attributes["happiness"] * 40 + 0.5) + local happiness_bar_width = math.floor(self.staff.attributes["happiness"] * 40 + 0.5) if happiness_bar_width ~= 0 then for dx = 0, happiness_bar_width - 1 do self.panel_sprites:draw(canvas, 348, x + 139 + dx, y + 56) @@ -212,7 +211,7 @@ local fatigue_bar_width = 40.5 if self.staff.attributes["fatigue"] then - fatigue_bar_width = math_floor((1 - self.staff.attributes["fatigue"]) * 40 + 0.5) + fatigue_bar_width = math.floor((1 - self.staff.attributes["fatigue"]) * 40 + 0.5) end if fatigue_bar_width ~= 0 then for dx = 0, fatigue_bar_width - 1 do @@ -220,7 +219,7 @@ end end - local skill_bar_width = math_floor(profile.skill * 40 + 0.5) + local skill_bar_width = math.floor(profile.skill * 40 + 0.5) if skill_bar_width ~= 0 then for dx = 0, skill_bar_width - 1 do self.panel_sprites:draw(canvas, 350, x + 139 + dx, y + 120) @@ -256,7 +255,7 @@ return Window.onMouseDown(self, button, x, y) end --- Helper function to faciliate humanoid_class comparison wrt. Surgeons +-- Helper function to facilitate humanoid_class comparison wrt. Surgeons local function surg_compat(class) return class == "Surgeon" and "Doctor" or class end @@ -310,12 +309,7 @@ function UIStaff:placeStaff() self.staff.pickup = true - self.staff:setNextAction({ - name = "pickup", - ui = self.ui, - todo_close = self, - must_happen = true, - }, true) + self.staff:setNextAction(PickupAction(self.ui):setTodoClose(self), true) end function UIStaff:fireStaff() @@ -324,62 +318,57 @@ end)) end -local attributes = {"cleaning", "watering", "repairing"} +--! Function to balance 'cleaning','watering', and 'repairing', where +--! one of them is increased, and the other two are decreased. +--!param increased Attribute to increase. function UIStaff:changeHandymanAttributes(increased) - self.staff:changeAttribute(increased, 0.1) - local extra_decrease = 0 - for no, attr in ipairs(attributes) do - if attr ~= increased then - if self.staff.attributes[attr] < 0.05 then - extra_decrease = 0.05 - self.staff.attributes[attr] - end - self.staff:changeAttribute(attr, -0.05) - end + if not self.staff.attributes[increased] then + return end - if extra_decrease ~= 0 then - for no, attr in ipairs(attributes) do - if attr ~= increased then - self.staff:changeAttribute(attr, -extra_decrease) + + local incr_value = 0.1 -- Increase of 'increased' + local smallest_decr = 0.05 -- Smallest decrement that can be performed. + local decr_attrs = {} + + local attributes = {"cleaning", "watering", "repairing"} + for _, attr in ipairs(attributes) do + if attr == increased then + -- Adding too much is not a problem, it gets clipped to 1. + self.staff:changeAttribute(attr, incr_value) + if self.staff.attributes[attr] == 1 then + incr_value = 2.0 -- Doing 'increased' 100%, set other attributes to 0. + end + else + decr_attrs[#decr_attrs + 1] = attr + smallest_decr = math.min(smallest_decr, self.staff.attributes[attr]) end end + assert(#decr_attrs == 2) + + -- The decreasing attributes should together decrease '-incr_value', but one + -- or both may be smaller than '-incr_value / 2'. + -- Compensate by subtracting the biggest value from both. + local decr_value = incr_value - smallest_decr + for _, attr in ipairs(decr_attrs) do + -- Subtracting too much is not a problem, it gets clipped to 0. + self.staff:changeAttribute(attr, -decr_value) end end +--! UI callback function to increase 'cleaning' (wiping litter). function UIStaff:doMoreCleaning() - if self.staff.attributes["cleaning"] then - if self.staff.attributes["cleaning"] < 0.9 then - self:changeHandymanAttributes("cleaning") - else - self.staff.attributes["cleaning"] = 1.0 - self.staff.attributes["watering"] = 0.0 - self.staff.attributes["repairing"] = 0.0 - end - end + self:changeHandymanAttributes("cleaning") end +--! UI callback function to increase 'watering' (plants). function UIStaff:doMoreWatering() - if self.staff.attributes["watering"] then - if self.staff.attributes["watering"] < 0.9 then - self:changeHandymanAttributes("watering") - else - self.staff.attributes["cleaning"] = 0.0 - self.staff.attributes["watering"] = 1.0 - self.staff.attributes["repairing"] = 0.0 - end - end + self:changeHandymanAttributes("watering") end +--! UI callback function to increase 'repairing' (machines). function UIStaff:doMoreRepairing() - if self.staff.attributes["repairing"] then - if self.staff.attributes["repairing"] < 0.9 then - self:changeHandymanAttributes("repairing") - else - self.staff.attributes["cleaning"] = 0.0 - self.staff.attributes["watering"] = 0.0 - self.staff.attributes["repairing"] = 1.0 - end - end + self:changeHandymanAttributes("repairing") end function UIStaff:openStaffManagement() diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/staff_rise.lua corsix-th-0.62/CorsixTH/Lua/dialogs/staff_rise.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/staff_rise.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/staff_rise.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,12 +18,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local math_floor - = math.floor --! Dialog for staff member requesting a salaray raise. class "UIStaffRise" (Window) +---@type UIStaffRise +local UIStaffRise = _G["UIStaffRise"] + function UIStaffRise:UIStaffRise(ui, staff, rise_amount) self:Window() local app = ui.app @@ -46,6 +47,7 @@ self.panel_sprites = app.gfx:loadSpriteTable("QData", "Req12V", true) self.white_font = app.gfx:loadFont("QData", "Font01V") + self.black_font = app.gfx:loadFont("QData", "Font00V") self.face_parts = app.gfx:loadRaw("Face01V", 65, 1350, nil, "Data", "MPalette.dat") -- Left hand side @@ -136,7 +138,7 @@ end -- Complaint text - font:drawWrapped(canvas, self.text, x + 200, y + 20, 140) + self.black_font:drawWrapped(canvas, self.text, x + 200, y + 20, 140) end function UIStaffRise:drawDoctorAttributes(canvas) @@ -186,3 +188,9 @@ world:setSpeed(world.prev_speed) end end + +function UIStaffRise:afterLoad(old, new) + if not self.black_font then + self.black_font = self.ui.app.gfx:loadFont("QData", "Font00V") + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/tree_ctrl.lua corsix-th-0.62/CorsixTH/Lua/dialogs/tree_ctrl.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/tree_ctrl.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/tree_ctrl.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! Iterface for items within a UI tree control class "TreeNode" +---@type TreeNode +local TreeNode = _G["TreeNode"] + function TreeNode:TreeNode() self.is_expanded = false self.num_visible_descendants = 0 @@ -28,7 +31,7 @@ --! Get the number of childrem which the item has function TreeNode:getChildCount() - error "To be implemented in subclasses" + error("To be implemented in subclasses") end --! Query if the item has any children at all. @@ -41,18 +44,18 @@ --! Get a child of the item. --!param idx (integer) An integer between 1 and getChildCount() (inclusive). function TreeNode:getChildByIndex(idx) - error "To be implemented in subclasses" + error("To be implemented in subclasses") end --! Given a child of the item, determine which index it is --!param child (TreeNode) A value returned from getChildByIndex() function TreeNode:getIndexOfChild(child) - error "To be implemented in subclasses" + error("To be implemented in subclasses") end --! Get the text to be displayed for the item function TreeNode:getLabel() - error "To be implemented in subclasses" + error("To be implemented in subclasses") end --! Get the item's parent, if it has one @@ -181,6 +184,9 @@ --! A tree node representing a file (or directory) in the physical file-system. class "FileTreeNode" (TreeNode) +---@type FileTreeNode +local FileTreeNode = _G["FileTreeNode"] + local pathsep = package.config:sub(1, 1) function FileTreeNode:FileTreeNode(path) @@ -196,6 +202,62 @@ self.order = "ascending" end +function FileTreeNode:isDirectory() + return lfs.attributes(self.path, "mode") == "directory" +end + +--- +--@param (optional) return the most recently modified child file which has this string in its name. +--@return nil if no child file is found otherwise return the FileTreedNode for mostly recently modified child file. +function FileTreeNode:getMostRecentlyModifiedChildFile(file_name_filter) + self:checkForChildren() + self:reSortChildren("date", "descending") + local most_recently_mod_child_dir_file = nil + local root_child = nil + --A. Search for files matching the file name filter in the root directory and its child directories: + for i = 1, self:getChildCount(), 1 do + root_child = self:getChildByIndex(i) + -- 1. Get the most recently modified child directory file which matches the name filter: + if root_child:isDirectory() then + local current_child_dir_file = root_child:getMostRecentlyModifiedChildFile(file_name_filter) + if current_child_dir_file ~= nil then + if most_recently_mod_child_dir_file == nil then + most_recently_mod_child_dir_file = current_child_dir_file + elseif current_child_dir_file:getLastModification() > most_recently_mod_child_dir_file:getLastModification() then + most_recently_mod_child_dir_file = current_child_dir_file + end + end + + -- Sort always puts directories first so when this else closure is reached in this iterative for loop + -- all the sub directories will have been checked: + else + -- 2. Get the most recently modified root directory file which matches the name filter: + local matches_filter = true + if(file_name_filter) then + matches_filter = string.find(root_child:getLabel(), file_name_filter) + end + -- End this for loop to begin step B: + if matches_filter then + break + end + end + root_child = nil + end + --B. Return the most recently modified file or nil if no file matching the name filter was found: + if most_recently_mod_child_dir_file then + if root_child then + if root_child:getLastModification() > most_recently_mod_child_dir_file:getLastModification() then + return root_child + end + end + return most_recently_mod_child_dir_file + elseif root_child then + return root_child + else + return nil + end +end + function FileTreeNode:childPath(item) if self.path:sub(-1, -1) == pathsep then return self.path .. item @@ -276,7 +338,7 @@ --!param sort_by What to sort by. Either "name" or "date". --!param order If the ordering should be "ascending" or "descending". function FileTreeNode:reSortChildren(sort_by, order) - for i, child in ipairs(self.children) do + for _, child in ipairs(self.children) do if sort_by == "date" then child.sort_key = lfs.attributes(child.path, "modification") child.sort_by = sort_by @@ -387,6 +449,9 @@ -- multiple root nodes. class "DummyRootNode" (TreeNode) +---@type DummyRootNode +local DummyRootNode = _G["DummyRootNode"] + --!param roots (array) An array of `TreeNode`s which should be displayed as -- root nodes. function DummyRootNode:DummyRootNode(roots) @@ -417,6 +482,9 @@ -- tree of items and select one item from it. class "TreeControl" (Window) +---@type TreeControl +local TreeControl = _G["TreeControl"] + --!param root (TreeNode) The single root node of the tree (use a `DummyRootNode` -- here if multiple root nodes are desired). --!param x (integer) The X-position, in pixels, where the control should start @@ -537,34 +605,33 @@ function TreeControl:onMouseUp(button, x, y) local redraw = Window.onMouseUp(self, button, x, y) - if button == 4 or button == 5 then - -- Scrollwheel - self.scrollbar:setXorY(self.scrollbar:getXorY() + (button - 4.5) * 8) - else - local node, expand = self:hitTestTree(x, y) - if self.mouse_down_in_self and node then - if expand then - if node:hasChildren() then - if node:isExpanded() then - node:contract() - else - node:expand() - end - redraw = true + local node, expand = self:hitTestTree(x, y) + if self.mouse_down_in_self and node then + if expand then + if node:hasChildren() then + if node:isExpanded() then + node:contract() + else + node:expand() end - elseif self.selected_node == node and self.select_callback then - self.select_callback(node) - else - self.selected_node = node - node:select() redraw = true end + elseif self.selected_node == node and self.select_callback then + self.select_callback(node) + else + self.selected_node = node + node:select() + redraw = true end - self.mouse_down_in_self = false end + self.mouse_down_in_self = false return redraw end +function TreeControl:onMouseWheel(x, y) + self.scrollbar:setXorY(self.scrollbar:getXorY() - y * 8) +end + function TreeControl:onNumVisibleNodesChange() self.scrollbar:setRange(1, self.tree_root:numVisibleDescendants(), self.num_rows, self.first_visible_ordinal) @@ -572,11 +639,11 @@ function TreeControl:onScroll() if self.scrollbar.value > self.first_visible_ordinal then - for i = 1, self.scrollbar.value - self.first_visible_ordinal do + for _ = 1, self.scrollbar.value - self.first_visible_ordinal do self.first_visible_node = self.first_visible_node:getNextVisible() end elseif self.scrollbar.value < self.first_visible_ordinal then - for i = 1, self.first_visible_ordinal - self.scrollbar.value do + for _ = 1, self.first_visible_ordinal - self.scrollbar.value do self.first_visible_node = self.first_visible_node:getPrevVisible() end end @@ -590,12 +657,11 @@ function TreeControl:draw(canvas, x, y) Window.draw(self, canvas, x, y) - x, y = self.x + x, self.y + y + self.y_offset + x = x + self.x + self.tree_rect.x + y = y + self.y + self.tree_rect.y + self.y_offset local node = self.first_visible_node local num_nodes_drawn = 0 - local y = y + self.tree_rect.y - local x = x + self.tree_rect.x while node and num_nodes_drawn < self.num_rows do local level = node:getLevel() for i = 0, level - 1 do diff -Nru corsix-th-0.30/CorsixTH/Lua/dialogs/watch.lua corsix-th-0.62/CorsixTH/Lua/dialogs/watch.lua --- corsix-th-0.30/CorsixTH/Lua/dialogs/watch.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/dialogs/watch.lua 2018-07-21 11:13:17.000000000 +0000 @@ -22,6 +22,9 @@ --! The timer lasts approximately 100 days, split into 13 segments class "UIWatch" (Window) +---@type UIWatch +local UIWatch = _G["UIWatch"] + --!param count_type (string) One of: "open_countdown" or "emergency" or "epidemic" function UIWatch:UIWatch(ui, count_type) self:Window() @@ -30,7 +33,7 @@ self.esc_closes = false self.modal_class = "open_countdown" - self.tick_rate = math.floor((100 * app.world.hours_per_day) / 13) + self.tick_rate = math.floor((100 * Date.hoursPerDay()) / 13) self.tick_timer = self.tick_rate -- Initialize tick timer self.open_timer = 12 self.ui = ui @@ -41,6 +44,10 @@ self.panel_sprites = app.gfx:loadSpriteTable("Data", "Watch01V", true) self.epidemic = false self.count_type = count_type + -- For cycling the list of epidemic/emergency patients which index to use + self.current_index = nil + -- The last patient whose dialog was opened by clicking the timer + self.lastCycledPatient = nil local end_sprite = (count_type == "epidemic") and 14 or 16 @@ -50,12 +57,25 @@ ["epidemic"] = _S.tooltip.watch.epidemic, } - if count_type ~= "emergency" then + if count_type == "epidemic" then + self.end_button = self:addPanel(end_sprite, 4, 0) + :makeButton(4, 0, 27, 28, end_sprite + 1, self.toggleVaccinationMode) + :setTooltip(tooltips[count_type]) + elseif count_type ~= "emergency" then self.end_button = self:addPanel(end_sprite, 4, 0) :makeButton(4, 0, 27, 28, end_sprite + 1, self.onCountdownEnd) :setTooltip(tooltips[count_type]) end - self:addPanel(13, 0, 28):setTooltip(tooltips[count_type]) + + local timer_sprite = 13 + if count_type == "epidemic" or count_type == "emergency" then + self:addPanel(timer_sprite, 0, 28) + :setTooltip(tooltips[count_type]) + :makeButton(timer_sprite, 0, 25, 50, timer_sprite, + self.scrollToTimerEventPatient, nil, self.cycleTimerEventPatient) + else + self:addPanel(timer_sprite, 0, 28):setTooltip(tooltips[count_type]) + end self:addPanel(1, 2, 47) end @@ -63,6 +83,14 @@ self:close() if self.count_type == "emergency" then self.ui.hospital:resolveEmergency() + elseif self.count_type == "epidemic" then + local epidemic = self.hospital.epidemic + if epidemic and not epidemic.inspector then + epidemic:spawnInspector() + if epidemic.vaccination_mode_active then + epidemic:toggleVaccinationMode() + end + end elseif self.count_type == "initial_opening" then self.ui.hospital.opened = true self.ui.hospital.boiler_can_break = true -- boiler can't break whilst build timer is open @@ -90,3 +118,59 @@ self.tick_timer = self.tick_timer - 1 end end + +--[[! Toggles vaccination mode by toggling the button then +toggling the mode in the current epidemic.]] +function UIWatch:toggleVaccinationMode() + local epidemic = self.hospital.epidemic + self.end_button:toggle() + epidemic:toggleVaccinationMode() +end + +--[[! During an emergency - Cycles through the patient dialogs of all the emergency patients + ! During an epidemic - Cycles to the first patient who is infected but not vaccinated]] +function UIWatch:cycleTimerEventPatient() + self.ui:playSound("camclick.wav") + local hospital = self.ui.hospital + + if self.count_type == "emergency" then + local patients = hospital.emergency_patients + + if #patients > 0 then + if not self.current_index or self.current_index == #patients then + self.current_index = 1 + else + self.current_index = self.current_index + 1 + end + self.lastCycledPatient = patients[self.current_index] + self.ui:addWindow(UIPatient(self.ui, self.lastCycledPatient)) + end + else + for _, infected_patient in ipairs(hospital.epidemic.infected_patients) do + if not infected_patient.vaccinated and not infected_patient.cured then + self.lastCycledPatient = infected_patient + self.ui:addWindow(UIPatient(self.ui, self.lastCycledPatient)) + break + end + end + end +end + +--[[! While cycling through timer event patients (@see + UIWatch:cycleTimerEventPatient) scrolls the screen to centre on the selected patient + If a patient dialog is open that does not belong to the timer event, does nothing]] +function UIWatch:scrollToTimerEventPatient() + self.ui:playSound("camclick.wav") + local patient = self.lastCycledPatient + if patient then + -- Current open dialog + local current_patient_dialog = self.ui:getWindow(UIPatient) + if not current_patient_dialog then + -- Create the dialog but don't add it to the window + local patient_dialog = UIPatient(self.ui, patient) + patient_dialog:scrollToPatient() + elseif patient == current_patient_dialog.patient then + current_patient_dialog:scrollToPatient() + end + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/alien_dna.lua corsix-th-0.62/CorsixTH/Lua/diseases/alien_dna.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/alien_dna.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/alien_dna.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 2000 disease.emergency_sound = "emerg020.wav" disease.emergency_number = 16 +disease.contagious = false disease.must_stand = TheApp.config.alien_dna_must_stand -- Alien Patients are forced to stand while queueing because of missing animation disease.only_emergency = TheApp.config.alien_dna_only_by_emergency -- TODO implement (there are no normal door animations, so they cannot go to GP) disease.initPatient = function(patient) diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/baldness.lua corsix-th-0.62/CorsixTH/Lua/diseases/baldness.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/baldness.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/baldness.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 950 disease.emergency_sound = "emerg012.wav" disease.emergency_number = 18 +disease.contagious = false disease.initPatient = function(patient) patient:setType("Slack Male Patient") patient:setLayer(0, 12) diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/bloaty_head.lua corsix-th-0.62/CorsixTH/Lua/diseases/bloaty_head.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/bloaty_head.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/bloaty_head.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 850 disease.emergency_sound = "emerg007.wav" disease.emergency_number = 18 +disease.contagious = false disease.initPatient = function(patient) patient:setType("Standard Male Patient") patient:setLayer(0, math.random(6, 8) * 2) diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/broken_heart.lua corsix-th-0.62/CorsixTH/Lua/diseases/broken_heart.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/broken_heart.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/broken_heart.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1900 disease.emergency_sound = "emerg025.wav" disease.emergency_number = 6 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/broken_wind.lua corsix-th-0.62/CorsixTH/Lua/diseases/broken_wind.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/broken_wind.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/broken_wind.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,6 +30,7 @@ disease.cure_price = 1300 disease.emergency_sound = "emerg016.wav" disease.emergency_number = 14 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/chronic_nosehair.lua corsix-th-0.62/CorsixTH/Lua/diseases/chronic_nosehair.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/chronic_nosehair.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/chronic_nosehair.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,6 +30,7 @@ disease.cure_price = 800 disease.emergency_sound = "emerg029.wav" disease.emergency_number = 18 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/corrugated_ankles.lua corsix-th-0.62/CorsixTH/Lua/diseases/corrugated_ankles.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/corrugated_ankles.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/corrugated_ankles.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,6 +30,7 @@ disease.cure_price = 800 disease.emergency_sound = "emerg028.wav" disease.emergency_number = 18 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/discrete_itching.lua corsix-th-0.62/CorsixTH/Lua/diseases/discrete_itching.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/discrete_itching.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/discrete_itching.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,6 +30,7 @@ disease.cure_price = 700 disease.emergency_sound = "emerg013.wav" disease.emergency_number = 15 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/fake_blood.lua corsix-th-0.62/CorsixTH/Lua/diseases/fake_blood.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/fake_blood.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/fake_blood.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 800 disease.emergency_sound = "emerg031.wav" disease.emergency_number = 18 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/fractured_bones.lua corsix-th-0.62/CorsixTH/Lua/diseases/fractured_bones.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/fractured_bones.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/fractured_bones.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 450 disease.emergency_sound = "emerg005.wav" disease.emergency_number = 16 +disease.contagious = false disease.initPatient = function(patient) if not TheApp.config.disable_fractured_bones_females and math.random(1, 2) == 2 then -- The female animation in the cast remover is bad -- so by default it is disabled. They can though be allowed by turning them on in config diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/gastric_ejections.lua corsix-th-0.62/CorsixTH/Lua/diseases/gastric_ejections.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/gastric_ejections.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/gastric_ejections.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,6 +30,7 @@ disease.cure_price = 650 disease.emergency_sound = "emerg032.wav" disease.emergency_number = 15 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/golf_stones.lua corsix-th-0.62/CorsixTH/Lua/diseases/golf_stones.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/golf_stones.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/golf_stones.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1600 disease.emergency_sound = "emerg034.wav" disease.emergency_number = 6 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/gut_rot.lua corsix-th-0.62/CorsixTH/Lua/diseases/gut_rot.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/gut_rot.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/gut_rot.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,6 +30,7 @@ disease.emergency_sound = "emerg019.wav" disease.emergency_number = 14 disease.more_loo_use = true +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/hairyitis.lua corsix-th-0.62/CorsixTH/Lua/diseases/hairyitis.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/hairyitis.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/hairyitis.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1150 disease.emergency_sound = "emerg008.wav" disease.emergency_number = 12 +disease.contagious = false disease.initPatient = function(patient) patient:setType("Chewbacca Patient") -- NB: Layers have no effect on the appearance until cured, at which point diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/heaped_piles.lua corsix-th-0.62/CorsixTH/Lua/diseases/heaped_piles.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/heaped_piles.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/heaped_piles.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,6 +30,7 @@ disease.cure_price = 400 disease.emergency_sound = "emerg001.wav" disease.emergency_number = 14 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/infectious_laughter.lua corsix-th-0.62/CorsixTH/Lua/diseases/infectious_laughter.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/infectious_laughter.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/infectious_laughter.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1500 disease.emergency_sound = "emerg027.wav" disease.emergency_number = 18 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/invisibility.lua corsix-th-0.62/CorsixTH/Lua/diseases/invisibility.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/invisibility.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/invisibility.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1400 disease.emergency_sound = "emerg006.wav" disease.emergency_number = 18 +disease.contagious = false disease.initPatient = function(patient) patient:setType("Invisible Patient") patient:setLayer(0, 2) diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/iron_lungs.lua corsix-th-0.62/CorsixTH/Lua/diseases/iron_lungs.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/iron_lungs.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/iron_lungs.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1700 disease.emergency_sound = "emerg033.wav" disease.emergency_number = 5 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/jellyitis.lua corsix-th-0.62/CorsixTH/Lua/diseases/jellyitis.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/jellyitis.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/jellyitis.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1000 disease.emergency_sound = "emerg014.wav" disease.emergency_number = 12 +disease.contagious = false disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/kidney_beans.lua corsix-th-0.62/CorsixTH/Lua/diseases/kidney_beans.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/kidney_beans.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/kidney_beans.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1050 disease.emergency_sound = "emerg024.wav" disease.emergency_number = 5 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/king_complex.lua corsix-th-0.62/CorsixTH/Lua/diseases/king_complex.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/king_complex.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/king_complex.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1600 disease.emergency_sound = "emerg009.wav" disease.emergency_number = 18 +disease.contagious = false disease.initPatient = function(patient) patient:setType("Elvis Patient") patient:setLayer(0, math.random(1, 3)*2) diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/pregnant.lua corsix-th-0.62/CorsixTH/Lua/diseases/pregnant.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/pregnant.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/pregnant.lua 2018-07-21 11:13:17.000000000 +0000 @@ -27,6 +27,7 @@ disease.cure_price = 200 disease.emergency_sound = "emerg021.wav" disease.emergency_number = 8 +disease.contagious = false disease.initPatient = function(patient) patient:setType("Standard Female Patient") patient:setLayer(0, math.random(1, 4) * 2) diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/ruptured_nodules.lua corsix-th-0.62/CorsixTH/Lua/diseases/ruptured_nodules.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/ruptured_nodules.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/ruptured_nodules.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1600 disease.emergency_sound = "emerg026.wav" disease.emergency_number = 6 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/serious_radiation.lua corsix-th-0.62/CorsixTH/Lua/diseases/serious_radiation.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/serious_radiation.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/serious_radiation.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1800 disease.emergency_sound = "emerg010.wav" disease.emergency_number = 18 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/slack_tongue.lua corsix-th-0.62/CorsixTH/Lua/diseases/slack_tongue.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/slack_tongue.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/slack_tongue.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 900 disease.emergency_sound = "emerg011.wav" disease.emergency_number = 18 +disease.contagious = false disease.initPatient = function(patient) if math.random(0, 1) == 1 then patient:setType("Slack Female Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/sleeping_illness.lua corsix-th-0.62/CorsixTH/Lua/diseases/sleeping_illness.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/sleeping_illness.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/sleeping_illness.lua 2018-07-21 11:13:17.000000000 +0000 @@ -31,6 +31,7 @@ disease.cure_price = 750 disease.emergency_sound = "emerg015.wav" disease.emergency_number = 18 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/spare_ribs.lua corsix-th-0.62/CorsixTH/Lua/diseases/spare_ribs.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/spare_ribs.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/spare_ribs.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 1100 disease.emergency_sound = "emerg023.wav" disease.emergency_number = 4 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/sweaty_palms.lua corsix-th-0.62/CorsixTH/Lua/diseases/sweaty_palms.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/sweaty_palms.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/sweaty_palms.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 600 disease.emergency_sound = "emerg017.wav" disease.emergency_number = 14 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/the_squits.lua corsix-th-0.62/CorsixTH/Lua/diseases/the_squits.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/the_squits.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/the_squits.lua 2018-07-21 11:13:17.000000000 +0000 @@ -31,6 +31,7 @@ disease.emergency_sound = "emerg002.wav" disease.emergency_number = 18 disease.more_loo_use = true +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/third_degree_sideburns.lua corsix-th-0.62/CorsixTH/Lua/diseases/third_degree_sideburns.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/third_degree_sideburns.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/third_degree_sideburns.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 550 disease.emergency_sound = "emerg030.wav" disease.emergency_number = 13 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/transparency.lua corsix-th-0.62/CorsixTH/Lua/diseases/transparency.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/transparency.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/transparency.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 800 disease.emergency_sound = "emerg022.wav" disease.emergency_number = 12 +disease.contagious = false disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Transparent Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/tv_personalities.lua corsix-th-0.62/CorsixTH/Lua/diseases/tv_personalities.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/tv_personalities.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/tv_personalities.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 800 disease.emergency_sound = "emerg003.wav" disease.emergency_number = 14 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/uncommon_cold.lua corsix-th-0.62/CorsixTH/Lua/diseases/uncommon_cold.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/uncommon_cold.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/uncommon_cold.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,6 +30,7 @@ disease.cure_price = 300 disease.emergency_sound = "emerg004.wav" disease.emergency_number = 18 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/diseases/unexpected_swelling.lua corsix-th-0.62/CorsixTH/Lua/diseases/unexpected_swelling.lua --- corsix-th-0.30/CorsixTH/Lua/diseases/unexpected_swelling.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/diseases/unexpected_swelling.lua 2018-07-21 11:13:17.000000000 +0000 @@ -29,6 +29,7 @@ disease.cure_price = 500 disease.emergency_sound = "emerg018.wav" disease.emergency_number = 5 +disease.contagious = true disease.initPatient = function(patient) if math.random(0, 1) == 0 then patient:setType("Standard Male Patient") diff -Nru corsix-th-0.30/CorsixTH/Lua/entities/grim_reaper.lua corsix-th-0.62/CorsixTH/Lua/entities/grim_reaper.lua --- corsix-th-0.30/CorsixTH/Lua/entities/grim_reaper.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entities/grim_reaper.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,40 @@ +--[[ Copyright (c) 2012 Luís "Driver" Duarte + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +class "GrimReaper" (Humanoid) + +---@type GrimReaper +local GrimReaper = _G["GrimReaper"] + +function GrimReaper:GrimReaper(...) + self:Humanoid(...) + self.attributes = {} + self.hover_cursor = TheApp.gfx:loadMainCursor("default") + self.walk_anims = { + walk_east = 996, + walk_north = 994, + idle_east = 1004, + idle_north = 1002, + } +end + +function GrimReaper:tickDay() + return false +end diff -Nru corsix-th-0.30/CorsixTH/Lua/entities/humanoid.lua corsix-th-0.62/CorsixTH/Lua/entities/humanoid.lua --- corsix-th-0.30/CorsixTH/Lua/entities/humanoid.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entities/humanoid.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,7 +21,8 @@ --! An `Entity` which occupies a single tile and is capable of moving around the map. class "Humanoid" (Entity) -local TH = require "TH" +---@type Humanoid +local Humanoid = _G["Humanoid"] local walk_animations = permanent"humanoid_walk_animations"({}) local door_animations = permanent"humanoid_door_animations"({}) @@ -55,10 +56,21 @@ } end -local function die_anims(name, fall, rise, wings, hands, fly, extra) +--- +-- @param name The name of the patient class these death animations are for. +-- @param fall The patient's fall animation. +-- @param rise The transparent getting up animation for heaven death patients who have been lying dead on the ground. +-- @param rise_hell The opaque getting up animation for hell death patients who have been lying dead on the ground. +-- @param wings The heaven death animation in which the patient's wings appear. +-- @param hands The heaven death animation which occurs after the wings animation when the patient puts their hands together. +-- @param fly The heaven death animation which makes patients fly upwards to heaven. +-- @param extra Dead untreated patients who don't transform before falling over use this animation afterwards to transform into a standard male/female. +--- +local function die_anims(name, fall, rise, rise_hell, wings, hands, fly, extra) die_animations[name] = { fall_east = fall, rise_east = rise, + rise_hell_east = rise_hell, wings_east = wings, hands_east = hands, fly_east = fly, @@ -125,24 +137,25 @@ anims("Handyman", 1858, 1860, 1866, 1868, 3286, 3288, nil, nil, 3518, 3520) anims("Receptionist", 3668, 3670, 3676, 3678) -- Could do with door animations anims("VIP", 266, 268, 274, 276) +anims("Inspector", 266, 268, 274, 276) anims("Grim Reaper", 994, 996, 1002, 1004) -- | Die Animations | --- | Name |FallE|RiseE|WingsE|HandsE|FlyE|ExtraE| Notes -----+--------------------------------+-----+-----+-----+-----+------+------+ -die_anims("Standard Male Patient", 1682, 2434, 2438, 2446, 2450) -- Always facing east or south -die_anims("Alternate Male Patient", 1682, 2434, 2438, 2446, 2450) -die_anims("Slack Male Patient", 1682, 2434, 2438, 2446, 2450) +-- | Name |FallE|RiseE|RiseE Hell|WingsE|HandsE|FlyE|ExtraE| Notes 2248 +----+--------------------------------+-----+-----+----------+-----+------+-----+------ +die_anims("Standard Male Patient", 1682, 2434, 384, 2438, 2446, 2450) -- Always facing east or south +die_anims("Alternate Male Patient", 1682, 2434, 3404, 2438, 2446, 2450) +die_anims("Slack Male Patient", 1682, 2434, 384, 2438, 2446, 2450) -- TODO: Where is slack male transformation? Uses alternate male for now. -die_anims("Transparent Male Patient", 4412, 2434, 2438, 2446, 2450, 4416) -- Extra = Transformation -die_anims("Standard Female Patient", 3116, 3208, 3212, 3216, 3220) -die_anims("Slack Female Patient", 4288, 3208, 3212, 3216, 3220) -die_anims("Transparent Female Patient",4420, 3208, 3212, 3216, 3220, 4428) -- Extra = Transformation -die_anims("Chewbacca Patient", 4182, 2434, 2438, 2446, 2450) -- Only males die... (1222 is the Female) -die_anims("Elvis Patient", 974, 2434, 2438, 2446, 2450, 4186) -- Extra = Transformation -die_anims("Invisible Patient", 4200, 2434, 2438, 2446, 2450) -die_anims("Alien Male Patient", 4882, 2434, 2438, 2446, 2450) -die_anims("Alien Female Patient", 4886, 3208, 3212, 3216, 3220) +die_anims("Transparent Male Patient", 4412, 2434, 384, 2438, 2446, 2450, 4416) -- Extra = Transformation +die_anims("Standard Female Patient", 3116, 3208, 580, 3212, 3216, 3220) +die_anims("Slack Female Patient", 4288, 3208, 580, 3212, 3216, 3220) +die_anims("Transparent Female Patient",4420, 3208, 580, 3212, 3216, 3220, 4428) -- Extra = Transformation +die_anims("Chewbacca Patient", 4182, 2434, 384, 2438, 2446, 2450, 1682) -- Only males die... (1222 is the Female) +die_anims("Elvis Patient", 974, 2434, 384, 2438, 2446, 2450, 4186) -- Extra = Transformation +die_anims("Invisible Patient", 4200, 2434, 384, 2438, 2446, 2450) +die_anims("Alien Male Patient", 4882, 2434, 384, 2438, 2446, 2450) +die_anims("Alien Female Patient", 4886, 3208, 580, 3212, 3216, 3220) -- The next fours sets belong together, but are done like this so we can use them on there own -- I also had difficulty in keeping them together, as the patient needs to on the floor @@ -238,12 +251,12 @@ moods("hot", 3988, 0, true) -- they will be shown when hovering moods("queue", 4568, 70) -- no matter what other priorities. moods("poo", 3996, 5) -moods("money", 4018, 30) +moods("sad_money", 4018, 50) moods("patient_wait", 5006, 40) -moods("epidemy1", 4566, 38) -moods("epidemy2", 4570, 40) -moods("epidemy3", 4572, 40) -moods("epidemy4", 4574, 40) +moods("epidemy1", 4566, 55) +moods("epidemy2", 4570, 55) +moods("epidemy3", 4572, 55) +moods("epidemy4", 4574, 55) moods("sad1", 3992, 40) moods("sad2", 4000, 41) moods("sad3", 4002, 42) @@ -321,6 +334,14 @@ self.toilet_callback = nil end end + if old < 83 and self.humanoid_class == "Chewbacca Patient" then + self.die_anims.extra_east = 1682 + end + + for _, action in pairs(self.action_queue) do + -- Sometimes actions not actual instances of HumanoidAction + HumanoidAction.afterLoad(action, old, new) + end Entity.afterLoad(self, old, new) end @@ -338,56 +359,9 @@ end function Humanoid:dump() - local name = "humanoid" - if self.profile then - name = self.profile.name - end - print("-----------------------------------") - print("Clicked on ".. name, self) - print("Class: ", self.humanoid_class) - if self.humanoid_class == "Doctor" then - print(string.format("Skills: (%.3f) Surgeon (%.3f) Psych (%.3f) Researcher (%.3f)", - self.profile.skill or 0, - self.profile.is_surgeon or 0, - self.profile.is_psychiatrist or 0, - self.profile.is_researcher or 0)) - end - print(string.format("Warmth: %.3f Happiness: %.3f Fatigue: %.3f Thirst: %.3f Toilet_Need: %.3f Health: %.3f", - self.attributes["warmth"] or 0, - self.attributes["happiness"] or 0, - self.attributes["fatigue"] or 0, - self.attributes["thirst"] or 0, - self.attributes["toilet_need"] or 0, - self.attributes["health"] or 0)) - - print("") - print("Actions:") - for i = 1, #self.action_queue do - local action = self.action_queue[i] - local flag = - (action.must_happen and " must_happen" or " ") .. - (action.todo_interrupt and " " or " ") - if action.room_type then - print(action.name .. " - " .. action.room_type .. flag) - elseif action.object then - print(action.name .. " - " .. action.object.object_type.id .. flag) - elseif action.name == "walk" then - print(action.name .. " - going to " .. action.x .. ":" .. action.y .. flag) - elseif action.name == "queue" then - local distance = action.current_bench_distance - if distance == nil then - distance = "nil" - end - local standing = "false" - if action:isStanding() then - standing = "true" - end - print(action.name .. " - Bench distance: " .. distance .. " Standing: " .. standing) - else - print(action.name .. flag) - end - end + print("Clicked on: ") + print(self:tostring()) print("-----------------------------------") end @@ -408,21 +382,21 @@ -- Set the `Hospital` which is responsible for treating or employing the -- `Humanoid`. In single player games, this has little effect, but it is very -- important in multiplayer games. ---!param hospital (Hospital, nil) The `Hospital` which should be responsible --- for the `Humanoid`. If nil, then the `Humanoid` is despawned. +--!param hospital (Hospital) The `Hospital` which should be responsible +-- for the `Humanoid`. function Humanoid:setHospital(hospital) self.hospital = hospital - if not hospital or not hospital.is_in_world then - local spawn_points = self.world.spawn_points - self:setNextAction{ - name = "spawn", - mode = "despawn", - point = spawn_points[math.random(1, #spawn_points)], - must_happen = true, - } + if not hospital.is_in_world then + self:despawn() end end +--! Despawn the humanoid. +function Humanoid:despawn() + local spawn_point = self.world.spawn_points[math.random(1, #self.world.spawn_points)] + self:setNextAction(SpawnAction("despawn", spawn_point):setMustHappen(true)) +end + -- Function to activate/deactivate moods of a humanoid. -- If mood_name is nil it is considered a refresh only. function Humanoid:setMood(mood_name, activate) @@ -441,7 +415,7 @@ end local new_mood = nil -- TODO: Make equal priorities cycle, or make all moods unique - for key, value in pairs(self.active_moods) do + for _, value in pairs(self.active_moods) do if new_mood then -- There is a mood, check priorities. if new_mood.priority < value.priority then new_mood = value @@ -486,17 +460,25 @@ -- Handle an empty action queue in some way instead of crashing. if not action then + -- if this is a patient that is going home, an empty + -- action queue is not a problem + if class.is(self, Patient) and self.going_home then + return + end + ---- Empty action queue! ---- -- First find out if this humanoid is in a room. local room = self:getRoom() if room then room:makeHumanoidLeave(self) end - -- Is it a member of staff or a patient? + -- Is it a member of staff, grim or a patient? if class.is(self, Staff) then - self:queueAction({name = "meander"}) + self:queueAction(MeanderAction()) + elseif class.is(self,GrimReaper) then + self:queueAction(IdleAction()) else - self:queueAction({name = "seek_reception"}) + self:queueAction(SeekReceptionAction()) end -- Open the dialog of the humanoid. local ui = self.world.ui @@ -529,11 +511,11 @@ -- Set these variables to increase the likelihood of the humanoid managing to get out of the hospital. self.going_home = false self.hospital = self.world:getLocalPlayerHospital() - self:goHome() + self:goHome("kicked") end if TheApp.world:isCurrentSpeed("Pause") then - TheApp.world:setSpeed(TheApp.world.prev_speed) - end + TheApp.world:setSpeed(TheApp.world.prev_speed) + end end, --[[persistable:humanoid_stay_in_hospital]] function() if TheApp.world:isCurrentSpeed("Pause") then @@ -643,7 +625,7 @@ -- Check if the humanoid is running actions intended to leave the room, as indicated by the flag function Humanoid:isLeaving() - return self.action_queue[1].is_leaving + return self.action_queue[1].is_leaving and true or false end -- Check if there is "is_leaving" action in the action queue @@ -672,7 +654,7 @@ self.pee_anim = pee_animations[humanoid_class] self.humanoid_class = humanoid_class if #self.action_queue == 0 then - self:setNextAction {name = "idle"} + self:setNextAction(IdleAction()) end self.th:setPartialFlag(self.permanent_flags or 0, false) @@ -695,12 +677,8 @@ --!param must_happen (boolean, nil) If true, then the walk action will not be -- interrupted. function Humanoid:walkTo(tile_x, tile_y, must_happen) - self:setNextAction { - name = "walk", - x = tile_x, - y = tile_y, - must_happen = must_happen, - } + self:setNextAction(WalkAction(tile_x, tile_y) + :setMustHappen(not not must_happen)) end -- Stub functions for handling fatigue. These are overridden by the staff subclass, @@ -718,9 +696,9 @@ function Humanoid:handleRemovedObject(object) local replacement_action if self.humanoid_class and self.humanoid_class == "Receptionist" then - replacement_action = {name = "meander"} + replacement_action = MeanderAction() elseif object.object_type.id == "bench" or object.object_type.id == "drinks_machine" then - replacement_action = {name = "idle", must_happen = true} + replacement_action = IdleAction():setMustHappen(true) end for i, action in ipairs(self.action_queue) do @@ -754,7 +732,7 @@ function Humanoid:changeAttribute(attribute, amount) -- Receptionist is always 100% happy if self.humanoid_class and self.humanoid_class == "Receptionist" and attribute == "happiness" then - self.attributes[attribute] = 1; + self.attributes[attribute] = 1 return true end @@ -781,19 +759,23 @@ -- If it is too hot or too cold, start to decrease happiness and -- show the corresponding icon. Otherwise we could get happier instead. - -- Let the player get into the level first though, don't decrease happiness the first year. - if self.attributes["warmth"] and self.hospital and not self.hospital.initial_grace then - -- Cold: less than 11 degrees C - if self.attributes["warmth"] < 0.22 then - self:changeAttribute("happiness", -0.02 * (0.22 - self.attributes["warmth"]) / 0.14) + local min_comfort_temp = 0.22 -- 11 degrees Celcius. + local max_comfort_temp = 0.36 -- 18 degrees Celcius. + local decrease_factor = 0.10 + local increase_happiness = 0.005 + + if self.attributes["warmth"] and self.hospital then + -- Cold: less than comfortable. + if self.attributes["warmth"] < min_comfort_temp then + self:changeAttribute("happiness", -decrease_factor * (min_comfort_temp - self.attributes["warmth"])) self:setMood("cold", "activate") - -- Hot: More than 18 degrees C - elseif self.attributes["warmth"] > 0.36 then - self:changeAttribute("happiness", -0.02 * (self.attributes["warmth"] - 0.36) / 0.14) + -- Hot: More than comfortable. + elseif self.attributes["warmth"] > max_comfort_temp then + self:changeAttribute("happiness", -decrease_factor * (self.attributes["warmth"] - max_comfort_temp)) self:setMood("hot", "activate") - -- Ideal: Between 11 and 18 + -- Ideal: Not too cold or too warm. else - self:changeAttribute("happiness", 0.005) + self:changeAttribute("happiness", increase_happiness) self:setMood("cold", "deactivate") self:setMood("hot", "deactivate") end @@ -803,7 +785,7 @@ -- Helper function that finds out if there is an action queued to use the specified object function Humanoid:goingToUseObject(object_type) - for i, action in ipairs(self.action_queue) do + for _, action in ipairs(self.action_queue) do if action.object and action.object.object_type.id == object_type then return true end @@ -815,7 +797,6 @@ --!param callback (function) The callback to call when a room has been built. function Humanoid:registerRoomBuildCallback(callback) if not self.build_callbacks[callback] then - self.world:registerRoomBuildCallback(callback) self.build_callbacks[callback] = true else self.world:gameLog("Warning: Trying to re-add room build callback (" .. tostring(callback) .. ") for humanoid (" .. tostring(self) .. ").") @@ -826,13 +807,18 @@ --!param callback (function) The callback to remove. function Humanoid:unregisterRoomBuildCallback(callback) if self.build_callbacks[callback] then - self.world:unregisterRoomBuildCallback(callback) self.build_callbacks[callback] = nil else self.world:gameLog("Warning: Trying to remove nonexistant room build callback (" .. tostring(callback) .. ") from humanoid (" .. tostring(self) .. ").") end end +function Humanoid:notifyNewRoom(room) + for callback, _ in pairs(self.build_callbacks) do + callback(room) + end +end + -- Registers a new remove callback for this humanoid. --!param callback (function) The callback to call when a room has been removed. function Humanoid:registerRoomRemoveCallback(callback) @@ -876,3 +862,68 @@ function Humanoid:getDrawingLayer() return 4 end + +function Humanoid:getCurrentAction() + if next(self.action_queue) == nil then + error("Action queue was empty. This should never happen.\n" .. self:tostring()) + end + + return self.action_queue[1] +end + +--[[ Return string representation +! Returns string representation of the humanoid like status and action queue +!return (string) +]] +function Humanoid:tostring() + local name = self.profile and self.profile.name or nil + local class = self.humanoid_class and self.humanoid_class or "N/A" + local full_name = "humanoid" + if (name) then + full_name = full_name .. " (" .. name .. ")" + end + + local result = string.format("%s - class: %s", full_name, class) + + result = result .. string.format("\nWarmth: %.3f Happiness: %.3f Fatigue: %.3f Thirst: %.3f Toilet_Need: %.3f Health: %.3f", + self.attributes["warmth"] or 0, + self.attributes["happiness"] or 0, + self.attributes["fatigue"] or 0, + self.attributes["thirst"] or 0, + self.attributes["toilet_need"] or 0, + self.attributes["health"] or 0) + + result = result .. "\nActions: [" + for i = 1, #self.action_queue do + local action = self.action_queue[i] + local action_string = action.name + if action.room_type then + action_string = action_string .. " - " .. action.room_type + elseif action.object then + action_string = action_string .. " - " .. action.object.object_type.id + elseif action.name == "walk" then + action_string = action_string .. " - going to " .. action.x .. ":" .. action.y + elseif action.name == "queue" then + local distance = action.current_bench_distance + if distance == nil then + distance = "nil" + end + local standing = "false" + if action:isStanding() then + standing = "true" + end + action_string = action_string .. " - Bench distance: " .. distance .. " Standing: " .. standing + end + local flag = action.must_happen and " must_happen" or "" + if flag ~= "" then + action_string = action_string .. " " .. flag + end + + if i ~= 1 then + result = result .. ", " + end + result = result .. action_string + end + result = result .. "]" + return result +end diff -Nru corsix-th-0.30/CorsixTH/Lua/entities/inspector.lua corsix-th-0.62/CorsixTH/Lua/entities/inspector.lua --- corsix-th-0.30/CorsixTH/Lua/entities/inspector.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entities/inspector.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,58 @@ +--[[ Copyright (c) 2011 William "sadger" Gatens + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +--[[ An `Inspector` is called to the hospital after an epidemic to issue a report]] +class "Inspector" (Humanoid) + +---@type Inspector +local Inspector = _G["Inspector"] + +function Inspector:Inspector(...) + self:Humanoid(...) + self.hover_cursor = TheApp.gfx:loadMainCursor("default") + self.has_been_announced = false +end + +--[[ Labels the inspector as the "Health Inspector" ]] +function Inspector:updateDynamicInfo(action_string) + self:setDynamicInfo('text', {_S.dynamic_info.health_inspector}) +end + +--[[ Sends the inspector home ]] +function Inspector:goHome() + if self.going_home then + return + end + --Store a reference to the hospital last visited to send fax to + self.last_hospital = self.hospital + + self:unregisterCallbacks() + self.going_home = true + self:despawn() +end + +--[[ Called when the inspector has left the map ]] +function Inspector:onDestroy() + return Humanoid.onDestroy(self) +end + +function Inspector:announce() + self.world.ui:playAnnouncement("vip008.wav") +end diff -Nru corsix-th-0.30/CorsixTH/Lua/entities/machine.lua corsix-th-0.62/CorsixTH/Lua/entities/machine.lua --- corsix-th-0.30/CorsixTH/Lua/entities/machine.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entities/machine.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,11 +18,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") --! An `Object` which needs occasional repair (to prevent explosion). class "Machine" (Object) +---@type Machine +local Machine = _G["Machine"] + function Machine:Machine(world, object_type, x, y, direction, etc) self.total_usage = -1 -- Incremented in the constructor of Object. @@ -36,15 +39,9 @@ -- We actually don't want any dynamic info just yet self:clearDynamicInfo() - -- TODO: Smoke, 3424 -- Change hover cursor once the room has been finished. - local callback - callback = --[[persistable:machine_build_callback]] function(room) - if room.objects[self] then - self:finalize(room) - self.world:unregisterRoomBuildCallback(callback) - end - end + self.waiting_for_finalize = true -- Waiting until the room is completed (reset by new-room callback). + local orientation = object_type.orientations[direction] local handyman_position = orientation.handyman_position if handyman_position then @@ -68,50 +65,133 @@ else self.handyman_position = {orientation.use_position[1], orientation.use_position[2]} end - self.world:registerRoomBuildCallback(callback) +end + +function Machine:notifyNewRoom(room) + if self.waiting_for_finalize and room.objects[self] then + self:finalize(room) + self.waiting_for_finalize = false + end end function Machine:setCrashedAnimation() self:setAnimation(self.object_type.crashed_animation) end +--! Calculates the number of times the machine can be used before crashing (unless repaired first) +function Machine:getRemainingUses() + return self.strength - self.times_used +end + +--! Set whether the smoke animation should be showing +local function setSmoke(self, isSmoking) + -- If turning smoke on for this machine + if isSmoking then + -- If there is no smoke animation for this machine, make one + if not self.smokeInfo then + self.smokeInfo = TH.animation() + -- Note: Set the location of the smoke to that of the machine + -- rather than setting the machine to the parent so that the smoke + -- doesn't get hidden with the machine during use + self.smokeInfo:setTile(self.th:getTile()) + -- Always show the first smoke layer + self.smokeInfo:setLayer(10, 2) + -- tick to animate over all frames + self.ticks = true + end + -- TODO: select the smoke icon based on the type of machine + self.smokeInfo:setAnimation(self.world.anims, 3424) + else -- Otherwise, turning smoke off + -- If there is currently a smoke animation, remove it + if self.smokeInfo then + self.smokeInfo:setTile(nil) + end + self.smokeInfo = nil + end +end + +--! Call on machine use. Handles crashing the machine & queueing repairs function Machine:machineUsed(room) + -- Do nothing if the room has already crashed if room.crashed then - -- Do nothing if the room has already crashed. return end + -- Update dynamic info (strength & times used) self:updateDynamicInfo() - local threshold = self.times_used/self.strength - + -- How many uses this machine has left until it explodes + local threshold = self:getRemainingUses() + -- Find a queued task for a handyman coming to repair this machine local taskIndex = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "repairing") - if threshold >= 0.9 then + + -- Too late it is about to explode + if threshold < 1 then + -- Clean up any task of handyman coming to repair the machine self.hospital:removeHandymanTask(taskIndex, "repairing") + -- Blow up the room room:crashRoom() self:setCrashedAnimation() + -- No special cursor required when hovering over the crashed room self.hover_cursor = nil + -- Clear dynamic info (tracks machine usage which is no longer required) self:clearDynamicInfo() + -- Prevent the machine from smoking, it's now just a pile of rubble + setSmoke(self, false) + -- If we have the window for this machine open, close it local window = self.world.ui:getWindow(UIMachine) if window and window.machine == self then window:close() end + -- Clear the icon showing a handyman is coming to repair the machine self:setRepairing(nil) return true - elseif threshold >= 0.70 then - -- TODO: 3428 is smoke, add it when additional objects can be made - -- Urgent + -- Else if urgent repair needed + elseif threshold < 4 then + -- If the job of repairing the machine isn't queued, queue it now (higher priority) if taskIndex == -1 then local call = self.world.dispatcher:callForRepair(self, true, false, true) self.hospital:addHandymanTask(self, "repairing", 2, self.tile_x, self.tile_y, call) - else + else -- Otherwise the task is already queued. Increase the priority to above that of machines with at least 4 uses left self.hospital:modifyHandymanTaskPriority(taskIndex, 2, "repairing") end - elseif threshold >= 0.4 then - -- Not urgent + -- Else if repair is needed, but not urgently + elseif threshold < 6 then + -- If the job of repairing the machine isn't queued, queue it now (low priority) if taskIndex == -1 then local call = self.world.dispatcher:callForRepair(self) self.hospital:addHandymanTask(self, "repairing", 1, self.tile_x, self.tile_y, call) end end + + -- Update whether smoke gets displayed for this machine (and if so, how much) + self:calculateSmoke(room) +end + +--! Calculates whether smoke gets displayed for this machine (and if so, how much) +function Machine:calculateSmoke(room) + -- Do nothing if the room has already crashed + if room.crashed then + return + end + + -- How many uses this machine has left until it explodes + local threshold = self:getRemainingUses() + + -- If now exploding, clear any smoke + if threshold < 1 then + setSmoke(self, false) + -- Else if urgent repair needed + elseif threshold < 4 then + -- Display smoke, up to three animations per machine + -- i.e. < 4 one plume, < 3 two plumes or < 2 three plumes of smoke + setSmoke(self, true) + -- turn on additional layers of the animation for extra smoke plumes, depending on how damaged the machine is + if threshold < 3 then + self.smokeInfo:setLayer(11, 2) + end + if threshold < 2 then + self.smokeInfo:setLayer(12, 2) + end + end end function Machine:getRepairTile() @@ -129,52 +209,70 @@ self.repairing = handyman self:setRepairingMode() - local --[[persistable:handyman_repair_after_use]] function after_use() + local --[[persistable:handyman_repair_after_use]] function repair_after_use() handyman:setCallCompleted() handyman:setDynamicInfoText("") self:machineRepaired(self:getRoom()) end - local action = {name = "walk", x = ux, y = uy, is_entering = this_room and true or false} - local repair_action = { - name = "use_object", - object = self, - prolonged_usage = false, - loop_callback = --[[persistable:handyman_repair_loop_callback]] function() - action_use.prolonged_usage = false - end, - after_use = after_use, - min_length = 20, - } + + local action = WalkAction(ux, uy):setIsEntering(this_room and true or false) + + local repair_action = UseObjectAction(self):setProlongedUsage(false) + :setAfterUse(repair_after_use) + repair_action.min_length = 20 + if handyman_room and handyman_room ~= this_room then handyman:setNextAction(handyman_room:createLeaveAction()) handyman:queueAction(action) else handyman:setNextAction(action) end + + local meander_loop_callback = --[[persistable:handyman_meander_repair_loop_callback]] function() + if not self.user then + -- The machine is ready to be repaired. + -- The following statement will finish the meander action in the handyman's + -- action queue. + handyman:finishAction() + end + -- Otherwise do nothing and let the meandering continue. + end + -- Before the actual repair action, insert a meander action to wait for the machine -- to become free for use. - handyman:queueAction({ - name = "meander", - loop_callback = --[[persistable:handyman_meander_repair_loop_callback]] function() - if not self.user then - -- The machine is ready to be repaired. - -- The following statement will finish the meander action in the handyman's - -- action queue. - handyman:finishAction() - end - -- Otherwise do nothing and let the meandering continue. - end, - }) - -- The last one is another walk action to the repair tile. If the handymand goes directly + handyman:queueAction(MeanderAction():setLoopCallback(meander_loop_callback)) + + -- The last one is another walk action to the repair tile. If the handyman goes directly -- to repair it will simply complete in an instant. handyman:queueAction(action) handyman:queueAction(repair_action) CallsDispatcher.queueCallCheckpointAction(handyman) - handyman:queueAction{name = "answer_call"} + handyman:queueAction(AnswerCallAction()) handyman:setDynamicInfoText(_S.dynamic_info.staff.actions.going_to_repair :format(self.object_type.name)) end +--! Replace this machine (make it pretend it's brand new) +function Machine:machineReplaced() + -- Reset usage stats + self.total_usage = 0 + self.times_used = 0 + + -- Update strength to match the current level of research for it + self.strength = self.hospital.research.research_progress[self.object_type].start_strength + + -- Remove any queued repair jobs + local index = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "repairing") + if index ~= -1 then + self.hospital:removeHandymanTask(index, "repairing") + end + + -- Clear icon showing handyman is coming to repair the machine + self:setRepairing(nil) + -- Clear smoke + setSmoke(self, false) +end + function Machine:machineRepaired(room) room.needs_repair = nil local str = self.strength @@ -183,6 +281,7 @@ end self.times_used = 0 self:setRepairing(nil) + setSmoke(self, false) local taskIndex = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "repairing") self.hospital:removeHandymanTask(taskIndex, "repairing") @@ -272,6 +371,10 @@ if index ~= -1 then self.hospital:removeHandymanTask(index, "repairing") end + + -- Stop this machine from smoking + setSmoke(self, false) + Object.onDestroy(self) end @@ -293,3 +396,41 @@ end return Object.afterLoad(self, old, new) end + +function Machine:tick() + -- Tick any smoke animation + if self.smokeInfo then + self.smokeInfo:tick() + end + + return Object.tick(self) +end + +--[[ Gets the state of a machine + +! In addition to the object implementation this includes total_usage +!return (table) state +]] +function Machine:getState() + local state = Object.getState(self) + state.total_usage = self.total_usage + + return state +end + +--[[ Sets the state of a machine + +! Adds total_usage +!param state (table) table holding the state +!return (void) +]] +function Machine:setState(state) + Object.setState(self, state) + if state then + self.total_usage = state.total_usage + end +end + +-- Dummy callbacks for savegame compatibility +local callbackNewRoom = --[[persistable:machine_build_callback]] function(room) end +local repair_loop_callback = --[[persistable:handyman_repair_loop_callback]] function() end diff -Nru corsix-th-0.30/CorsixTH/Lua/entities/object.lua corsix-th-0.62/CorsixTH/Lua/entities/object.lua --- corsix-th-0.30/CorsixTH/Lua/entities/object.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entities/object.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,11 +18,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") --! An `Entity` which occupies at least a single map tile and does not move. class "Object" (Entity) +---@type Object +local Object = _G["Object"] + local orient_mirror = { north = "west", west = "north", @@ -190,7 +193,7 @@ if self.num_animation_ticks then for i = 2, #self.split_anims do local th = self.split_anims[i] - for i = 1, self.num_animation_ticks do + for _ = 1, self.num_animation_ticks do th:tick() end end @@ -291,9 +294,9 @@ end function Object:setTile(x, y) - local function coordinatesAreInFootprint(object_footprint, x, y) - for i, xy in ipairs(object_footprint) do - if(xy[1] == x and xy[2] == y) then + local function coordinatesAreInFootprint(object_footprint, xpos, ypos) + for _, xy in ipairs(object_footprint) do + if xy[1] == xpos and xy[2] == ypos then return true end end @@ -301,10 +304,7 @@ end local function isEmpty(table) - for _, _ in pairs(table) do - return false - end - return true + return next(table) == nil end local function getComplementaryPassableFlag(passable_flag) @@ -315,10 +315,10 @@ end end - local function setPassableFlags(passable_flag, x, y, next_x, next_y, value) + local function setPassableFlags(passable_flag, xpos, ypos, next_x, next_y, value) local flags1 = {} flags1[passable_flag] = value - self.world.map.th:setCellFlags(x, y, flags1) + self.world.map.th:setCellFlags(xpos, ypos, flags1) local flags2 = {} flags2[getComplementaryPassableFlag(passable_flag)] = value self.world.map.th:setCellFlags(next_x, next_y, flags2) @@ -341,40 +341,40 @@ if self.footprint then local map = self.world.map.th for _, xy in ipairs(self.footprint) do - local x, y = self.tile_x + xy[1], self.tile_y + xy[2] + local xpos, ypos = self.tile_x + xy[1], self.tile_y + xy[2] if xy.only_side then if self.set_passable_flags then self.set_passable_flags = nil local par = direction_parameters[direction] - local passableFlag, next_tile_x, next_tile_y = par["passable_flag"], x + par["x"], y + par["y"] - setPassableFlags(passableFlag, x, y, next_tile_x, next_tile_y, true) + local passableFlag, next_tile_x, next_tile_y = par.passable_flag, xpos + par.x, ypos + par.y + setPassableFlags(passableFlag, xpos, ypos, next_tile_x, next_tile_y, true) end local flags_to_set= {} - flags_to_set[direction_parameters[direction]["buildable_flag"]] = true - map:setCellFlags(x, y, flags_to_set) + flags_to_set[direction_parameters[direction].buildable_flag] = true + map:setCellFlags(xpos, ypos, flags_to_set) else local flags_to_set = {} for _, value in pairs(direction_parameters) do - if coordinatesAreInFootprint(self.footprint, xy[1] + value["x"], xy[2] + value["y"]) or - xy.complete_cell or xy[value["needed_side"]] then - flags_to_set[value["buildable_flag"]] = true + if coordinatesAreInFootprint(self.footprint, xy[1] + value.x, xy[2] + value.y) or + xy.complete_cell or xy[value.needed_side] then + flags_to_set[value.buildable_flag] = true end end if not isEmpty(flags_to_set) then - map:setCellFlags(x, y, flags_to_set) + map:setCellFlags(xpos, ypos, flags_to_set) end - if not map:getCellFlags(x, y).passable then - map:setCellFlags(x, y, { + if not map:getCellFlags(xpos, ypos).passable then + map:setCellFlags(xpos, ypos, { buildable = true, passable = true, }) else -- passable tiles can "belong" to multiple objects, so we have to check that - if not self.world:isTilePartOfNearbyObject(x, y, 10) then + if not self.world:isTilePartOfNearbyObject(xpos, ypos, 10) then -- assumption: no object defines a passable tile further than 10 tiles away from its origin - map:setCellFlags(x, y, { + map:setCellFlags(xpos, ypos, { buildable = true, }) end @@ -383,8 +383,22 @@ end end end + + local entity_map = self.world.entity_map + -- Remove the reference to the object at it's previous coordinates + if entity_map then + entity_map:removeEntity(self.tile_x,self.tile_y, self) + end + + -- Update the objects coordinates self.tile_x = x self.tile_y = y + + -- Update the entity map for the new position + if entity_map then + entity_map:addEntity(x,y,self) + end + if x then self.th:setDrawingLayer(self:getDrawingLayer()) self.th:setTile(self.world.map.th, self:getRenderAttachTile()) @@ -392,7 +406,6 @@ if self.footprint then local map = self.world.map.th local optional_found = false - local flags = {} local room = self.world:getRoom(x, y) local roomId = room and room.id local next_tile_x, next_tile_y = x,y @@ -403,20 +416,14 @@ local flags_to_set = {} local lx = x + xy[1] local ly = y + xy[2] - local flag + local flags if xy.optional then if optional_found then -- An optional tile has been accepted, we don't need anymore such tiles. change_flags = false else - -- Check if this optional tile is acceptable - flag = "buildable" - if xy.only_passable then - flag = "passable" - end - - local cell_flags = map:getCellFlags(lx, ly, flags)[flag] + flags = map:getCellFlags(lx, ly) local is_object_allowed = true if roomId and flags.roomId ~= roomId then is_object_allowed = false @@ -433,7 +440,7 @@ end end - map:getCellFlags(lx, ly, flags) + flags = map:getCellFlags(lx, ly) if xy.only_side then local par = direction_parameters[direction] flags_to_set[par["buildable_flag"]] = false @@ -599,7 +606,7 @@ if not self.reserved_for_list then self.reserved_for_list = {} end - for i, users in ipairs(self.reserved_for_list) do + for _, users in ipairs(self.reserved_for_list) do if users == user then return true end @@ -622,9 +629,9 @@ local room = self:getRoom() window = window and window.visible and window local direction = self.direction - if (not room and window) - or (room and not (window and window.room == room) and not self.object_type.corridor_object) - or (not room and not self.object_type.corridor_object) then + if (not room and window) or + (room and not (window and window.room == room) and not self.object_type.corridor_object) or + (not room and not self.object_type.corridor_object) then return end @@ -663,8 +670,11 @@ end end -function Object:resetAnimation() +function Object:eraseObject() self.world.map.th:eraseObjectTypes(self.tile_x, self.tile_y) +end + +function Object:resetAnimation() self.world.map.th:setCellFlags(self.tile_x, self.tile_y, {thob = self.object_type.thob}) self.th:setDrawingLayer(self:getDrawingLayer()) self.th:setTile(self.world.map.th, self:getRenderAttachTile()) @@ -676,7 +686,7 @@ room.objects[self] = nil end if self.user_list then - for i, user in ipairs(self.user_list) do + for _, user in ipairs(self.user_list) do user:handleRemovedObject(self) end self.user_list = {} @@ -685,7 +695,7 @@ end self.user = nil if self.reserved_for_list then - for i, reserver in ipairs(self.reserved_for_list) do + for _, reserver in ipairs(self.reserved_for_list) do reserver:handleRemovedObject(self) end self.reserved_for_list = {} @@ -696,6 +706,11 @@ Entity.onDestroy(self) + -- Issue 1105 - rebuild wall travel and pathfinding on side object removal + if self.object_type.class == "SideObject" then + self.world.map.th:updatePathfinding() + self.world:resetSideObjects() + end end function Object:afterLoad(old, new) @@ -725,19 +740,16 @@ local all_pathfind_dirs = {[0] = true, [1] = true, [2] = true, [3] = true} function Object.processTypeDefinition(object_type) - if object_type.id == "extinguisher" - or object_type.id == "radiator" - or object_type.id == "plant" - or object_type.id == "reception_desk" - or object_type.id == "bench" then + if object_type.id == "extinguisher" or object_type.id == "radiator" or + object_type.id == "plant" or object_type.id == "reception_desk" or + object_type.id == "bench" then object_type.count_category = object_type.id - elseif object_type.id ~= "bin" - and not object_type.corridor_object - and not object_type.id:find("door") then + elseif object_type.id ~= "bin" and not object_type.corridor_object and + not object_type.id:find("door") then object_type.count_category = "general" end if object_type.orientations then - for direction, details in pairs(object_type.orientations) do + for _, details in pairs(object_type.orientations) do -- Set default values if not details.animation_offset then details.animation_offset = {0, 0} @@ -800,7 +812,9 @@ solid_points[point[1] * 100 + point[2]] = point end end - for _, key in ipairs{"use_position_secondary", "finish_use_position", "finish_use_position_secondary"} do + for _, key in ipairs({"use_position_secondary", + "finish_use_position", + "finish_use_position_secondary"}) do if details[key] then details[key][1] = details[key][1] - x details[key][2] = details[key][2] - y @@ -832,17 +846,42 @@ local adjacent_set = {} local adjacent_list = {} details.adjacent_to_solid_footprint = adjacent_list - for k, point in pairs(solid_points) do - for _, delta in ipairs{{-1, 0}, {0, -1}, {0, 1}, {1, 0}} do + for _, point in pairs(solid_points) do + for _, delta in ipairs({{-1, 0}, {0, -1}, {0, 1}, {1, 0}}) do local x = point[1] + delta[1] local y = point[2] + delta[2] local k2 = x * 100 + y if not solid_points[k2] and not adjacent_set[k2] then adjacent_set[k2] = {x, y} - adjacent_list[#adjacent_list+1] = adjacent_set[k2] + adjacent_list[#adjacent_list + 1] = adjacent_set[k2] end end end end end end + +--[[ Gets the state of an object + +! The state can be later used to set the state of this object. This is +useful when we would destroy and create a new object that should represent +the same object. + +!return (table) state +]] +function Object:getState() + return {times_used = self.times_used} +end + +--[[ Sets the state of an object + +! This is a complement to a pair function. IT will use the generated state +table to update it's state. +!param state (table) table holding the state +!return (void) +]] +function Object:setState(state) + if state then + self.times_used = state.times_used + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/entities/patient.lua corsix-th-0.62/CorsixTH/Lua/entities/patient.lua --- corsix-th-0.30/CorsixTH/Lua/entities/patient.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entities/patient.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,14 +21,42 @@ --! A `Humanoid` who is in the hospital for diagnosis and/or treatment. class "Patient" (Humanoid) +---@type Patient +local Patient = _G["Patient"] + function Patient:Patient(...) self:Humanoid(...) self.hover_cursor = TheApp.gfx:loadMainCursor("patient") self.should_knock_on_doors = true self.treatment_history = {} + self.going_home = false -- If set, the patient is going home. + self.litter_countdown = nil -- If set, number of tiles to walk before attempting to drop litter. self.has_fallen = 1 self.has_vomitted = 0 self.action_string = "" + self.cured = false + self.infected = false + -- To distinguish between actually being dead and having a nil hospital + self.dead = false + -- Is the patient reserved for a particular nurse when being vaccinated + self.reserved_for = false + self.vaccinated = false + -- Has the patient been sent to the wrong room and needs redirecting + self.needs_redirecting = false + self.attempted_to_infect= false + -- Is the patient about to be vaccinated? + self.vaccination_candidate = false + -- Has the patient passed reception? + self.has_passed_reception = false + + -- Is the patient trying to get to the toilet? ("yes", "no", or "no-toilets") + self.going_to_toilet = "no" + + -- Health history in entries 1..SIZE (may not all exist at first). The "last" + -- entry indicates last written entry, "(last+1) % SIZE" is the oldest entry. + -- The "size" entry holds the length of the array (that is, SIZE). + -- Variable gets automatically initialized on first day. + self.health_history = nil end function Patient:onClick(ui, button) @@ -36,9 +64,21 @@ if self.message_callback then self:message_callback() else - ui:addWindow(UIPatient(ui, self)) + local hospital = self.hospital or self.world:getLocalPlayerHospital() + local epidemic = hospital and hospital.epidemic + if not epidemic or + (not epidemic.coverup_in_progress or + (not self.infected or self.marked_for_vaccination) and + not epidemic.vaccination_mode_active) then + ui:addWindow(UIPatient(ui, self)) + end + if epidemic and epidemic.coverup_in_progress and + self.infected and not self.marked_for_vaccination and + -- Prevent further vaccinations when the timer ends + not epidemic.timer.closed then + epidemic:markForVaccination(self) + end end - elseif self.user_of then -- The object we're using is made invisible, as the animation contains both -- the humanoid and the object. Hence send the click onto the object. @@ -53,7 +93,8 @@ self.diagnosed = false self.diagnosis_progress = 0 self.cure_rooms_visited = 0 - -- copy list of diagnosis rooms + -- Copy list of diagnosis rooms + -- (patient may visit these for diagnosis, if they exist in the hospital). self.available_diagnosis_rooms = {} for i, room in ipairs(self.disease.diagnosis_rooms) do self.available_diagnosis_rooms[i] = room @@ -73,30 +114,47 @@ self:updateDynamicInfo() end -function Patient:setdiagDiff() - local disease = self.disease - local difficulty = 0 - local expertise = self.world.map.level_config.expertise - if expertise then - difficulty = expertise[disease.expertise_id].MaxDiagDiff - self.diagnosis_difficulty = difficulty / 1000 +function Patient:changeDisease(new_disease) + assert(not self.diagnosed, "Cannot change the disease of a diagnosed patient") + -- These assertions should hold until handling of visual diseases is implemented. + assert(self.disease.contagious, "Cannot change the disease of a patient who has a non-contagious disease") + assert(new_disease.contagious, "Cannot change a disease to a non-contagious disease") + + local visited_rooms = {} + + -- Add all diagnosis room for the old disease. + for _, room in ipairs(self.disease.diagnosis_rooms) do + visited_rooms[room] = true + end + + -- Disable the rooms not yet visited by the patient. + for _, room in ipairs(self.available_diagnosis_rooms) do + visited_rooms[room] = false end - return self.diagnosis_difficulty + + -- 'visited_rooms' is now diagnosis rooms that the patient has visited for the old disease. + + -- Compute unvisited rooms for the new disease. + self.available_diagnosis_rooms = {} + for _, room in ipairs(new_disease.diagnosis_rooms) do + if not visited_rooms[room] then + self.available_diagnosis_rooms[#self.available_diagnosis_rooms + 1] = room + end + end + + self.disease = new_disease -- Finally, make the patient carry the new disease. end -function Patient:setDiagnosed(diagnosed) - self.diagnosed = diagnosed +--! Mark patient as being diagnosed. +function Patient:setDiagnosed() + self.diagnosed = true self.treatment_history[#self.treatment_history + 1] = self.disease.name + local window = self.world.ui:getWindow(UIPatient) if window and window.patient == self then window:updateInformation() end - self:updateDynamicInfo() -end --- Sets the value of the diagnosis progress. -function Patient:setDiagnosisProgress(progress) - self.diagnosis_progress = progress self:updateDynamicInfo() end @@ -119,14 +177,17 @@ -- Base: depending on difficulty of disease as set in sam file -- tiredness reduces the chance of diagnosis if staff member is above 50% tired local multiplier = 1 - local diagnosis_difficulty = self:setdiagDiff() - local diagnosis_base = (0.4 * (1 - diagnosis_difficulty)) + + local expertise = self.world.map.level_config.expertise + local diagnosis_difficulty = expertise[self.disease.expertise_id].MaxDiagDiff / 1000 + local diagnosis_base = 0.4 * (1 - diagnosis_difficulty) local diagnosis_bonus = 0.4 -- Did the staff member manage to leave the room before the patient had -- a chance to get diagnosed? Then use a default middle value. if room.staff_member then - local fatigue = room.staff_member.attributes["fatigue"] or 0 + local fatigue = room.staff_member.attributes["fatigue"] or 0 + -- Bonus: based on skill and attn to detail (with some randomness). -- additional bonus if the staff member is highly skilled / consultant -- tiredness reduces the chance of diagnosis if staff member is above 50% tired @@ -138,84 +199,129 @@ local divisor = math.random(1, 3) local attn_detail = room.staff_member.profile.attention_to_detail / divisor local skill = room.staff_member.profile.skill / divisor - local diagnosis_bonus = (attn_detail + 0.4) * skill + diagnosis_bonus = (attn_detail + 0.4) * skill end self:modifyDiagnosisProgress(diagnosis_base + (diagnosis_bonus * multiplier)) end +-- Sets the hospital for the patient - additionally removing them from a +-- hospital if they already belong to one. For player hospitals, patients who +-- are not debug or emergency patients are made to seek a reception desk. +--!param hospital (Hospital): hospital to assign to patient function Patient:setHospital(hospital) if self.hospital then self.hospital:removePatient(self) end Humanoid.setHospital(self, hospital) - if hospital then - if hospital.is_in_world and not self.is_debug and not self.is_emergency then - self:setNextAction{name = "seek_reception"} - end - hospital:addPatient(self) + if hospital.is_in_world and not self.is_debug and not self.is_emergency then + self:setNextAction(SeekReceptionAction()) + end + hospital:addPatient(self) +end + +--! Decide the ID of the disease or treatment that the patient is paying for. +--!return (string or nil) Id of the disease or treatment, or nil if the Id could +--! not be decided. +function Patient:getTreatmentDiseaseId() + if self.diagnosed then + return self.disease.id + else + local room_info = self:getRoom() + if not room_info then + print("Warning: Trying to receive money for treated patient who is ".. + "not in a room") + return nil + end + room_info = room_info.room_info + return "diag_" .. room_info.id end end -function Patient:treated() -- If a drug was used we also need to pay for this +--! Estimate the subjective perceived distortion between the price level the +--! patient might expect considering the reputation and the cure effectiveness +--! of a given treatment and the staff internal state. +--!param casebook (table): casebook entry for the treatment. +--!return (float) [-1, 1]. The smaller the value is, the more the patient +--! considers the bill to be under-priced. The bigger the value is, the more +--! the patient patient considers the bill to be over-priced. +function Patient:getPriceDistortion(casebook) + -- weights + local happiness_weight = 0.1 + local reputation_weight = 0.6 + local effectiveness_weight = 0.3 + + -- map the different variables to [0-1] and merge them + local reputation = casebook.reputation or self.hospital.reputation + local effectiveness = casebook.cure_effectiveness + + local weighted_happiness = happiness_weight * self.attributes.happiness + local weighted_reputation = reputation_weight * (reputation / 1000) + local weighted_effectiveness = effectiveness_weight * (effectiveness / 100) + + local expected_price_level = weighted_happiness + weighted_reputation + weighted_effectiveness + + -- map to [0-1] + local price_level = ((casebook.price - 0.5) / 3) * 2 + + return price_level - expected_price_level +end + +--! Handle attempting to treat this patient +--! +--! If the treatment is effective the patient will be sent home, otherwise they +--! will die. The patient may or may not agree to pay for the treatment +--! depending on whether they consider the price reasonable. +function Patient:treatDisease() local hospital = self.hospital - local amount = self.hospital.disease_casebook[self.disease.id].drug_cost or 0 + hospital:receiveMoneyForTreatment(self) - if amount ~= 0 then - local str = _S.drug_companies[math.random(1 , 5)] - hospital:spendMoney(amount, _S.transactions.drug_cost .. ": " .. str) - end -- Either the patient is no longer sick, or he/she dies. - - local cure_chance = hospital.disease_casebook[self.disease.id].cure_effectiveness - cure_chance = cure_chance * self.diagnosis_progress - if self.die_anims and math.random(1, 100) > cure_chance then - self:die() + if self:isTreatmentEffective() then + self:cure() + self.treatment_history[#self.treatment_history + 1] = _S.dynamic_info.patient.actions.cured + self:goHome("cured") else - -- to guess the cure is risky and the patient could die - if self.die_anims and math.random(1, 100) > (self.diagnosis_progress * 100) then - self:die() - else - if hospital.num_cured < 1 then - self.world.ui.adviser:say(_A.information.first_cure) - end - self.hospital.num_cured = hospital.num_cured + 1 - self.hospital.num_cured_ty = hospital.num_cured_ty + 1 - self.hospital:msgCured() - local casebook = hospital.disease_casebook[self.disease.id] - casebook.recoveries = casebook.recoveries + 1 - if self.is_emergency then - self.hospital.emergency.cured_emergency_patients = hospital.emergency.cured_emergency_patients + 1 - end - self:setMood("cured", "activate") - self.world.ui:playSound "cheer.wav" -- This sound is always heard - self.attributes["health"] = 1 - self:changeAttribute("happiness", 0.8) - hospital:changeReputation("cured", self.disease) - self.treatment_history[#self.treatment_history + 1] = _S.dynamic_info.patient.actions.cured - self:goHome(true) - self:updateDynamicInfo(_S.dynamic_info.patient.actions.cured) - end + self:die() end hospital:updatePercentages() - + hospital:paySupplierForDrug(self.disease.id) if self.is_emergency then - local killed = hospital.emergency.killed_emergency_patients - local cured = hospital.emergency.cured_emergency_patients - if killed + cured >= hospital.emergency.victims then - local window = hospital.world.ui:getWindow(UIWatch) - if window then - window:onCountdownEnd() - end - end + hospital:checkEmergencyOver() end end +--! Returns true if patient agrees to pay for the given treatment. +--!param disease_id (string): The id of the disease to test +function Patient:agreesToPay(disease_id) + local casebook = self.hospital.disease_casebook[disease_id] + local price_distortion = self:getPriceDistortion(casebook) + local is_over_priced = price_distortion > self.hospital.over_priced_threshold + + return not (is_over_priced and math.random(1, 5) == 1) +end + +--! Either the patient is cured, or he/she dies. +--!return (boolean) True if cured, false if died. +function Patient:isTreatmentEffective() + local cure_chance = self.hospital.disease_casebook[self.disease.id].cure_effectiveness + cure_chance = cure_chance * self.diagnosis_progress + + local die = self.die_anims and math.random(1, 100) > cure_chance + return not die +end + +--! Change patient internal state to "cured". +function Patient:cure() + self.cured = true + self.infected = false + self.attributes["health"] = 1 +end + function Patient:die() -- It may happen that this patient was just cured and then the room blew up. - -- (Hospital not set when going home) - local hospital = self.hospital or self.world:getLocalPlayerHospital() + local hospital = self.hospital if hospital.num_deaths < 1 then self.world.ui.adviser:say(_A.information.first_death) @@ -227,50 +333,49 @@ end hospital:msgKilled() self:setMood("dead", "activate") - self.world.ui:playSound "boo.wav" -- this sound is always heard + self.world.ui:playSound("boo.wav") -- this sound is always heard self.going_home = true if self:getRoom() then - self:queueAction{name = "meander", count = 1} + self:queueAction(MeanderAction():setCount(1)) else - self:setNextAction{name = "meander", count = 1} + self:setNextAction(MeanderAction():setCount(1)) end if self.is_emergency then hospital.emergency.killed_emergency_patients = hospital.emergency.killed_emergency_patients + 1 end - self:queueAction{name = "die"} + self:queueAction(DieAction()) self:updateDynamicInfo(_S.dynamic_info.patient.actions.dying) end function Patient:canPeeOrPuke(current) - return ((current.name == "walk" or current.name == "idle" or current.name == "seek_room" or current.name == "queue") - and not self.going_home and self.world.map.th:getCellFlags(self.tile_x, self.tile_y).buildable) + return ((current.name == "walk" or current.name == "idle" or + current.name == "seek_room" or current.name == "queue") and + not self.going_home and self.world.map.th:getCellFlags(self.tile_x, self.tile_y).buildable) end - -- animations for when there is an earth quake + +--! Animations for when there is an earth quake function Patient:falling() - local current = self.action_queue[1] + local current = self:getCurrentAction() current.keep_reserved = true if self.falling_anim and self:canPeeOrPuke(current) and self.has_fallen == 1 then - self:setNextAction({ - name = "falling", - must_happen = true - }, 0) + self:setNextAction(FallingAction(), 0) self.has_fallen = 2 if self.has_fallen == 2 then - self:setNextAction{name = "on_ground"} + self:setNextAction(OnGroundAction()) self.on_ground = true end - if self.on_ground then - self:setNextAction{name = "get_up"} - end - if current.name == "idle" or current.name == "walk" then - self:queueAction({ - name = current.name, - x = current.x, - y = current.y, - must_happen = current.must_happen, - is_entering = current.is_entering, - }, 2) - else + if self.on_ground then + self:setNextAction(GetUpAction()) + end + if current.name == "idle" or current.name == "walk" then + self:queueAction({ + name = current.name, + x = current.x, + y = current.y, + must_happen = current.must_happen, + is_entering = current.is_entering, + }, 2) + else self:queueAction({ name = current.name, room_type = current.room_type, @@ -278,18 +383,18 @@ diagnosis_room = current.diagnosis_room, treatment_room = current.treatment_room, }, 2) - end - if current.on_interrupt then - current.on_interrupt(current, self) - else + end + if current.on_interrupt then + current.on_interrupt(current, self) + else self:finishAction() - end - self.on_ground = false - if math.random(1, 5) == 3 then - self:shake_fist() - end - self:fallingAnnounce() - self:changeAttribute("happiness", -0.05) -- falling makes you very unhappy + end + self.on_ground = false + if math.random(1, 5) == 3 then + self:shakeFist() + end + self:fallingAnnounce() + self:changeAttribute("happiness", -0.05) -- falling makes you very unhappy else return end @@ -308,23 +413,19 @@ self.world.ui.adviser:say(msg[math.random(1, #msg)]) end end -function Patient:shake_fist() + +--! Perform 'shake fist' action. +function Patient:shakeFist() if self.shake_fist_anim then - self:queueAction({ - name = "shake_fist", - must_happen = true - }, 1) + self:queueAction(ShakeFistAction(), 1) end end function Patient:vomit() - local current = self.action_queue[1] + local current = self:getCurrentAction() --Only vomit under these conditions. Maybe I should add a vomit for patients in queues too? if self:canPeeOrPuke(current) and self.has_vomitted == 0 then - self:queueAction({ - name = "vomit", - must_happen = true - }, 1) + self:queueAction(VomitAction(), 1) if current.name == "idle" or current.name == "walk" then self:queueAction({ name = current.name, @@ -355,13 +456,10 @@ end function Patient:pee() - local current = self.action_queue[1] + local current = self:getCurrentAction() --Only pee under these conditions. As with vomit, should they also pee if in a queue? if self:canPeeOrPuke(current) then - self:queueAction({ - name = "pee", - must_happen = true - }, 1) + self:queueAction(PeeAction(), 1) if current.name == "idle" or current.name == "walk" then self:queueAction({ name = current.name, @@ -385,7 +483,7 @@ self:finishAction() end self:setMood("poo", "deactivate") - self:changeAttribute("happiness", -0.02) -- not being able to find a loo and doing it in the corridor will make you sad too + self:changeAttribute("happiness", -0.02) -- not being able to find a loo and doing it in the corridor will make you sad too if not self.hospital.did_it_on_floor then self.hospital.did_it_on_floor = true self.world.ui.adviser:say(_A.warnings.people_did_it_on_the_floor) @@ -396,51 +494,68 @@ end function Patient:checkWatch() - if self.check_watch_anim and not self.action_queue[1].is_leaving then - self:queueAction({ - name = "check_watch", - must_happen = true - }, 0) + if self.check_watch_anim and not self:getCurrentAction().is_leaving then + self:queueAction(CheckWatchAction(), 0) end end function Patient:yawn() - local action = self.action_queue[1] + local action = self:getCurrentAction() if self.yawn_anim and action.name == "idle" then - self:queueAction({ - name = "yawn", - must_happen = true - }, 0) + self:queueAction(YawnAction(), 0) end end function Patient:tapFoot() - if self.tap_foot_anim and not self.action_queue[1].is_leaving then - self:queueAction({ - name = "tap_foot", - must_happen = true - }, 0) + if self.tap_foot_anim and not self:getCurrentAction().is_leaving then + self:queueAction(TapFootAction(), 0) end end -function Patient:goHome(cured) +--! Make the patient leave the hospital. This function also handles some +--! statistics (number of cured/kicked out patients, etc.) +--! The mood icon is updated accordingly. Reputation is impacted accordingly. +--!param reason (string): the reason why the patient is sent home, which could be: +--! -"cured": When the patient is cured. +--! -"kicked": When the patient is kicked anyway, either manually, +--! either when no treatment can be found for her/him, etc. +--! -"over_priced": When the patient decided to leave because he/she believes +--! the last treatment is over-priced. +--param disease_id (string): When the reason is "over_priced" this is the +--! id of the disease/diagnosis that the patient considered over_priced +function Patient:goHome(reason, disease_id) local hosp = self.hospital - if not hosp and self.going_home then + if self.going_home then -- The patient should be going home already! Anything related to the hospital -- will not be updated correctly, but we still want to try to get the patient to go home. TheApp.world:gameLog("Warning: goHome called when the patient is already going home") - self:setHospital(nil) + self:despawn() return end - if not cured then + if reason == "cured" then + self:setMood("cured", "activate") + self:changeAttribute("happiness", 0.8) + self.world.ui:playSound("cheer.wav") -- This sound is always heard + self.hospital:updateCuredCounts(self) + self:updateDynamicInfo(_S.dynamic_info.patient.actions.cured) + self.hospital:msgCured() + + elseif reason == "kicked" then self:setMood("exit", "activate") - if not self.is_debug then - hosp:changeReputation("kicked", self.disease) - self.hospital.not_cured = hosp.not_cured + 1 - self.hospital.not_cured_ty = hosp.not_cured_ty + 1 - local casebook = self.hospital.disease_casebook[self.disease.id] - casebook.turned_away = casebook.turned_away + 1 - end + self.hospital:updateNotCuredCounts(self, reason) + + elseif reason == "over_priced" then + self:setMood("sad_money", "activate") + self:changeAttribute("happiness", -0.5) + + local treatment_name = self.hospital.disease_casebook[disease_id].disease.name + self.world.ui.adviser:say(_A.warnings.patient_not_paying:format(treatment_name)) + self.hospital:updateNotCuredCounts(self, reason) + self:clearDynamicInfo() + self:updateDynamicInfo(_S.dynamic_info.patient.actions.prices_too_high) + + else + TheApp.world:gameLog("Error: unknown reason " .. reason .. "!") end hosp:updatePercentages() @@ -454,11 +569,22 @@ self.going_home = true self.waiting = nil + -- Remove any vaccination calls from patient + if not self.vaccinated then + self.world.dispatcher:dropFromQueue(self) + end + local room = self:getRoom() if room then room:makeHumanoidLeave(self) end - self:setHospital(nil) + self:despawn() +end + +-- Despawns the patient and removes them from the hospital +function Patient:despawn() + self.hospital:removePatient(self) + Humanoid.despawn(self) end -- This function handles changing of the different attributes of the patient. @@ -469,7 +595,7 @@ if self.waiting then self.waiting = self.waiting - 1 if self.waiting == 0 then - self:goHome() + self:goHome("kicked") if self.diagnosed then -- No treatment rooms self:updateDynamicInfo(_S.dynamic_info.patient.actions.no_treatment_available) @@ -484,9 +610,10 @@ elseif self.waiting == 30 then self:checkWatch() end - if self.has_vomitted and self.has_vomitted > 0 then - self.has_vomitted = 0 - end + + if self.has_vomitted and self.has_vomitted > 0 then + self.has_vomitted = 0 + end end -- if patients are getting unhappy, then maybe we should see this! @@ -504,18 +631,18 @@ -- patient has been in the hospital for over 6 months and is still not well, so will become sad and will either get fed up and leave -- or stay in the hope that you will cure them before they die -- strange, but in TH happiness does not go down, even when close to death IMO that is wrong as you would be unhappy if you waited too long. - -- TODO death animation for slack female is missing its head. For now the only option is for her to get fed up and leave + -- TODO death animation for slack female is missing its head. For now the only option is for her to get fed up and leave -- this can be changed when the animation thing is resolved -- TODO clean up this block, nonmagical numbers if self.attributes["health"] >= 0.18 and self.attributes["health"] < 0.22 then self:setMood("sad2", "activate") - self:changeAttribute("happiness", -0.0002) -- waiting too long will make you sad + self:changeAttribute("happiness", -0.0002) -- waiting too long will make you sad -- There is a 1/3 chance that the patient will get fed up and leave -- note, this is potentially run 10 ((0.22-0.18)/0.004) times, hence the 1/30 chance. if math.random(1,30) == 1 then self:updateDynamicInfo(_S.dynamic_info.patient.actions.fed_up) self:setMood("sad2", "deactivate") - self:goHome() + self:goHome("kicked") end elseif self.attributes["health"] >= 0.14 and self.attributes["health"] < 0.18 then self:setMood("sad2", "deactivate") @@ -534,21 +661,21 @@ self:setMood("sad6", "activate") -- its not looking good elseif self.attributes["health"] > 0.00 and self.attributes["health"] < 0.01 then - self:setMood("sad6", "deactivate") - self:setMood("dead", "activate") self.attributes["health"] = 0.0 -- is there time to say a prayer elseif self.attributes["health"] == 0.0 then - local room = self:getRoom() - if not self:getRoom() and not self.action_queue[1].is_leaving then - self:die() - elseif self.in_room and self.attributes["health"] == 0.0 then - room:makeHumanoidLeave(self) + -- people who are in a room should not die: + -- 1. they are being cured in this moment. dying in the last few seconds + -- before the cure makes only a subtle difference for gameplay + -- 2. they will leave the room soon (toilets, diagnostics) and will die then + if not self:getRoom() and not self:getCurrentAction().is_leaving then + self:setMood("sad6", "deactivate") self:die() end --dead people aren't thirsty return end + -- Note: to avoid empty action queue error if the player spam clicks a patient at the same time as the day changes -- there is now an inbetween "neutal" stage. if self.has_fallen == 3 then @@ -556,12 +683,28 @@ elseif self.has_fallen == 2 then self.has_fallen = 3 end + + -- Update health history. + if not self.health_history then + -- First day, initialize health history. + self.health_history = {} + self.health_history[1] = self.attributes["health"] + self.health_history["last"] = 1 + self.health_history["size"] = 20 + else + -- Update the health history, wrapping around the array. + local last = self.health_history["last"] + 1 + if last > self.health_history["size"] then last = 1 end + self.health_history[last] = self.attributes["health"] + self.health_history["last"] = last + end + -- Vomitings. - if self.vomit_anim and not self:getRoom() and not self.action_queue[1].is_leaving and not self.action_queue[1].is_entering then + if self.vomit_anim and not self:getRoom() and not self:getCurrentAction().is_leaving and not self:getCurrentAction().is_entering then --Nausea level is based on health then proximity to vomit is used as a multiplier. - --Only a patient with a health value of less than 0.8 can be the inital vomiter, however :) - local initialVomitMult = 0.002 --The initial chance of vomiting. - local proximityVomitMult = 1.5 --The multiplier used when in proximity to vomit. + --Only a patient with a health value of less than 0.8 can be the initial vomiter, however :) + local initialVomitMult = 0.002 --The initial chance of vomiting. + local proximityVomitMult = 1.5 --The multiplier used when in proximity to vomit. local nausea = (1.0 - self.attributes["health"]) * initialVomitMult local foundVomit = {} local numVomit = 0 @@ -592,8 +735,8 @@ self:changeAttribute("happiness", -0.0004) end end) -- End of findObjectNear - -- As we don't yet have rats, rat holes and dead rats the chances of vomitting are slim - -- as a temp fix for this I have added 0.5 to the < nausea equation, + -- As we don't yet have rats, ratholes and dead rats the chances of vomitting are slim + -- as a temp fix for this I have added 0.5 to the < nausea equation, -- this may want adjusting or removing when the other factors are in the game MarkL if self.attributes["health"] <= 0.8 or numVomit > 0 or self.attributes["happiness"] < 0.6 then nausea = nausea * ((numVomit+1) * proximityVomitMult) @@ -620,7 +763,7 @@ self:changeAttribute("happiness", 0.0002) end) -- sitting makes you happy whilst standing and walking does not - if self:goingToUseObject("bench") then + if self:goingToUseObject("bench") then self:changeAttribute("happiness", 0.00002) else self:changeAttribute("happiness", -0.00002) @@ -636,35 +779,24 @@ end -- Maybe it's time to visit the loo? if self.attributes["toilet_need"] and self.attributes["toilet_need"] > 0.75 then - if self.pee_anim and not self.action_queue[1].is_leaving - and not self.action_queue[1].is_entering and not self.in_room then + if self.pee_anim and not self:getCurrentAction().is_leaving and + not self:getCurrentAction().is_entering and not self.in_room then if math.random(1, 10) < 5 then self:pee() self:changeAttribute("toilet_need", -(0.5 + math.random()*0.15)) - self.going_to_toilet = false + self.going_to_toilet = "no" else -- If waiting for user response, do not send to toilets, as this messes -- things up. - if not self.going_to_toilet and not self.waiting then + if self.going_to_toilet == "no" and not self.waiting then self:setMood("poo", "activate") -- Check if any room exists. if not self.world:findRoomNear(self, "toilets") then - self.going_to_toilet = true - local callback - callback = --[[persistable:patient_toilet_build_callback]] function(room) - if room.room_info.id == "toilets" then - self.going_to_toilet = false - self:unregisterRoomBuildCallback(callback) - end - end - self:registerRoomBuildCallback(callback) + self.going_to_toilet = "no-toilets" -- Gets reset when a new toilet is built (then, patient will try again). -- Otherwise we can queue the action, but only if not in any rooms right now. - elseif not self:getRoom() and not self.action_queue[1].is_leaving and not self.action_queue[1].pee then - self:setNextAction{ - name = "seek_toilets", - must_happen = true, - } - self.going_to_toilet = true + elseif not self:getRoom() and not self:getCurrentAction().is_leaving and not self:getCurrentAction().pee then + self:setNextAction(SeekToiletsAction():setMustHappen(true)) + self.going_to_toilet = "yes" end end end @@ -680,7 +812,7 @@ self:setMood("thirsty", "activate") -- If there's already an action to buy a drink in the action queue, or -- if we're going to the loo, do nothing - if self:goingToUseObject("drinks_machine") or self.going_to_toilet then + if self:goingToUseObject("drinks_machine") or self.going_to_toilet ~= "no" then return end -- Don't check for a drinks machine too often @@ -691,8 +823,7 @@ -- The only allowed situations to grab a soda is when queueing -- or idling/walking in the corridors -- Also make sure the walk action when leaving a room has a chance to finish. - if not self:getRoom() and not self.action_queue[1].is_leaving - and not self.going_home then + if not self:getRoom() and not self:getCurrentAction().is_leaving and not self.going_home then local machine, lx, ly = self.world: findObjectNear(self, "drinks_machine", 8) @@ -711,19 +842,17 @@ self:setMood("thirsty", "deactivate") -- The patient might be kicked while buying a drink if not self.going_home then - self.hospital:receiveMoneyForProduct(self, 20, _S.transactions.drinks) - -- Also increase the number of sodas sold this year. - self.hospital.sodas_sold = self.hospital.sodas_sold + 1 + self.hospital:sellSodaToPatient(self) end -- The patient might also throw the can on the floor, bad patient! if math.random() < 0.6 then - -- It will be dropped between 1 and 5 tiles away. - self.litter_countdown = math.random(1, 5) + -- It will be dropped between 1 and 12 tiles away (litter bin catches 8 radius). + self.litter_countdown = math.random(1, 12) end end -- If we are queueing, let the queue handle the situation. - for i, current_action in ipairs(self.action_queue) do + for _, current_action in ipairs(self.action_queue) do if current_action.name == "queue" then local callbacks = current_action.queue.callbacks[self] if callbacks then @@ -735,24 +864,13 @@ -- Or, if walking or idling insert the needed actions in -- the beginning of the queue - local current = self.action_queue[1] + local current = self:getCurrentAction() if current.name == "walk" or current.name == "idle" or current.name == "seek_room" then -- Go to the machine, use it, and then continue with -- whatever he/she was doing. current.keep_reserved = true - self:queueAction({ - name = "walk", - x = lx, - y = ly, - must_happen = true, - no_truncate = true, - }, 1) - self:queueAction({ - name = "use_object", - object = machine, - after_use = after_use, - must_happen = true, - }, 2) + self:queueAction(WalkAction(lx, ly):setMustHappen(true):disableTruncate(), 1) + self:queueAction(UseObjectAction(machine):setAfterUse(after_use):setMustHappen(true), 2) machine:addReservedUser(self) -- Insert the old action again, a little differently depending on -- what the previous action was. @@ -767,10 +885,7 @@ -- If we were idling, also go away a little before continuing with -- that important action. if current.name == "idle" then - self:queueAction({ - name = "meander", - count = 1, - }, 3) + self:queueAction(MeanderAction():setCount(1), 3) end else -- We were seeking a room, start that action from the beginning -- i.e. do not set the must_happen flag. @@ -790,31 +905,80 @@ end end end + + -- If the patient is sitting on a bench or standing and queued, + -- it may be a situation where he/she is not in the queue + -- anymore, but should be. If this is the case for more than + -- 2 ticks, go to reception + if #self.action_queue > 1 and (self:getCurrentAction().name == "use_object" or + self:getCurrentAction().name == "idle") and + self.action_queue[2].name == "queue" then + local found = false + for _, humanoid in ipairs(self.action_queue[2].queue) do + if humanoid == self then + found = true + break + end + end + + if not found then + if not self.noqueue_ticks then + self.noqueue_ticks = 1 + elseif self.noqueue_ticks > 2 then + self.world:gameLog("A patient has a queue action, but is not in the corresponding queue") + self:setNextAction(SeekReceptionAction()) + else + self.noqueue_ticks = self.noqueue_ticks + 1 + end + else + self.noqueue_ticks = 0 + end + end +end + +function Patient:notifyNewRoom(room) + Humanoid.notifyNewRoom(self, room) + if self.going_to_toilet == "no-toilets" and room.room_info.id == "toilets" then + self.going_to_toilet = "no" -- Patient can try again going to the loo. + end end -- Called each time the patient moves to a new tile. function Patient:setTile(x, y) - -- Is the patient about to drop some litter? - if self.litter_countdown then + if not self.litter_countdown then + -- If arrived at the first tile of the hospital, give patient some litter. + if x and self.world.map.th:getCellFlags(x, y).buildable then + -- Small hospitals are around 40-50 tiles. + self.litter_countdown = math.random(20, 100) + end + + elseif self.hospital and not self.going_home then self.litter_countdown = self.litter_countdown - 1 - if self.litter_countdown == 0 and self.hospital then - if x and not self:getRoom() and not self.world:getObjects(x, y) - and self.world.map.th:getCellFlags(x, y).buildable then + + -- Is the patient about to drop some litter? + if self.litter_countdown == 0 then + if x and not self:getRoom() and not self.world:getObjects(x, y) and + self.world.map.th:getCellFlags(x, y).buildable and + (not self.world:findObjectNear(self, "bin", 8) or math.random() < 0.05) then -- Drop some litter! local trash = math.random(1, 4) local litter = self.world:newObject("litter", x, y) litter:setLitterType(trash, math.random(0, 1)) if not self.hospital.hospital_littered then self.hospital.hospital_littered = true + -- A callout is only needed if there are no handymen employed if not self.hospital:hasStaffOfCategory("Handyman") then self.world.ui.adviser:say(_A.staff_advice.need_handyman_litter) end end end - self.litter_countdown = nil + + -- Always give new litter to drop. + self.litter_countdown = math.random(30, 150) end end + Humanoid.setTile(self, x, y) end @@ -825,7 +989,7 @@ assert(id == "bench", "Can only handle benches at the moment") -- Look for a queue action and tell this patient to look for a bench -- if currently standing up. - for i, action in ipairs(self.action_queue) do + for _, action in ipairs(self.action_queue) do if action.name == "queue" then local callbacks = action.queue.callbacks[self] if callbacks then @@ -884,10 +1048,22 @@ divider = self.hospital.policies["stop_procedure"] end if self.diagnosis_progress then - self:setDynamicInfo('progress', self.diagnosis_progress*(1/divider)) + self:setDynamicInfo('progress', math.min(1.0, self.diagnosis_progress / divider)) + end + end + -- Set the centre line of dynamic info based on contagiousness, if appropriate + local epidemic = self.hospital and self.hospital.epidemic + if epidemic and epidemic.coverup_in_progress then + if self.infected and not self.vaccinated then + self:setDynamicInfo('text', + {action_string, _S.dynamic_info.patient.actions.epidemic_contagious, info}) + elseif self.vaccinated then + self:setDynamicInfo('text', + {action_string, _S.dynamic_info.patient.actions.epidemic_vaccinated, info}) end + else + self:setDynamicInfo('text', {action_string, "", info}) end - self:setDynamicInfo('text', {action_string, "", info}) end --[[ Update availability of a choice in message owned by this patient, if any @@ -929,12 +1105,59 @@ end end +--[[ If the patient is not a vaccination candidate then + give them the arrow icon and candidate status ]] +function Patient:giveVaccinationCandidateStatus() + self:setMood("epidemy2","deactivate") + self:setMood("epidemy3","activate") + self.vaccination_candidate = true +end + +--[[Remove the vaccination candidate icon and status from the patient]] +function Patient:removeVaccinationCandidateStatus() + if not self.vaccinated then + self:setMood("epidemy3","deactivate") + self:setMood("epidemy2","activate") + self.vaccination_candidate = false + end +end + + function Patient:afterLoad(old, new) if old < 68 then if self.going_home then self.waiting = nil end end + if old < 87 then + if self.die_anims == nil then + self.die_anims = {} + end + + -- New humanoid animation: rise_hell_east: + if self:isMalePatient() then + if self.humanoid_class ~= "Alternate Male Patient" then + self.die_anims.rise_hell_east = 384 + else + self.die_anims.rise_hell_east = 3404 + end + else + self.die_anims.rise_hell_east = 580 + end + end + if old < 108 then + if self.going_to_toilet then + -- Not easily decidable what the patient is doing here, + -- removing a toilet while it's used is unlikely to happen. + if self.world:findRoomNear(self, "toilets") then + self.going_to_toilet = "yes" + else + self.going_to_toilet = "no-toilets" + end + else + self.going_to_toilet = "no" + end + end Humanoid.afterLoad(self, old, new) end @@ -946,3 +1169,6 @@ return male_patient_classes[self.humanoid_class] ~= nil end end + +-- Dummy callback for savegame compatibility +local callbackNewRoom = --[[persistable:patient_toilet_build_callback]] function(room) end diff -Nru corsix-th-0.30/CorsixTH/Lua/entities/staff.lua corsix-th-0.62/CorsixTH/Lua/entities/staff.lua --- corsix-th-0.30/CorsixTH/Lua/entities/staff.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entities/staff.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! A Doctor, Nurse, Receptionist, Handyman, or Surgeon class "Staff" (Humanoid) +---@type Staff +local Staff = _G["Staff"] + --!param ... Arguments to base class constructor. function Staff:Staff(...) self:Humanoid(...) @@ -90,13 +93,13 @@ self:changeAttribute("happiness", 0.0005) end) -- Being able to rest from work and play the video game or pool will make you happy - if (self.action_queue[1].name == "use_object" and self.action_queue[1].object.object_type.id == "video_game") then + if (self:getCurrentAction().name == "use_object" and self:getCurrentAction().object.object_type.id == "video_game") then self:changeAttribute("happiness", 0.08) end - if (self.action_queue[1].name == "use_object" and self.action_queue[1].object.object_type.id == "pool_table") then + if (self:getCurrentAction().name == "use_object" and self:getCurrentAction().object.object_type.id == "pool_table") then self:changeAttribute("happiness", 0.074) end - if (self.action_queue[1].name == "use_object" and self.action_queue[1].object.object_type.id == "sofa") then + if (self:getCurrentAction().name == "use_object" and self:getCurrentAction().object.object_type.id == "sofa") then self:changeAttribute("happiness", 0.05) end @@ -259,7 +262,7 @@ end -- Picking staff members up doesn't tire them, it just tires the player. - if self.action_queue[1].name == "pickup" then + if self:getCurrentAction().name == "pickup" then tiring = false end @@ -268,6 +271,7 @@ function Staff:isResting() local room = self:getRoom() + if room and room.room_info.id == "staff_room" and not self.on_call then return true else @@ -278,26 +282,29 @@ -- Determine if the staff member should contribute to research function Staff:isResearching() local room = self:getRoom() - return room and room.room_info.id == "research" -- in research lab - and self.humanoid_class == "Doctor" and self.profile.is_researcher >= 1.0 -- is qualified - and self.hospital -- is not leaving the hospital + + -- Staff is in research lab, is qualified, and is not leaving the hospital. + return room and room.room_info.id == "research" and + self.humanoid_class == "Doctor" and self.profile.is_researcher >= 1.0 and self.hospital end -- Determine if the staff member should increase their skills function Staff:isLearning() local room = self:getRoom() - return room and room.room_info.id == "training" -- in training room - and room.staff_member -- the training room has a consultant - and self.action_queue[1].name == "use_object" -- is using lecture chair - and self.action_queue[1].object.object_type.id == "lecture_chair" + + -- Staff is in training room, the training room has a consultant, and is using lecture chair. + return room and room.room_info.id == "training" and room.staff_member and + self:getCurrentAction().name == "use_object" and + self:getCurrentAction().object.object_type.id == "lecture_chair" end function Staff:isLearningOnTheJob() local room = self:getRoom() - return room and room.room_info.id ~= "training" and room.room_info.id ~= "staff_room" - and room.room_info.id ~= "toilets" -- is in room but not training room, staff room, or toilets - and self.humanoid_class == "Doctor" -- and is a doctor - and self.action_queue[1].name == "use_object" -- and is using something + + -- Staff is in room but not training room, staff room, or toilets; is a doctor; and is using something + return room and room.room_info.id ~= "training" and + room.room_info.id ~= "staff_room" and room.room_info.id ~= "toilets" and + self.humanoid_class == "Doctor" and self:getCurrentAction().name == "use_object" end @@ -332,7 +339,7 @@ self.world.ui.adviser:say(_A.information.promotion_to_consultant) if self:getRoom().room_info.id == "training" then self:setNextAction(self:getRoom():createLeaveAction()) - self:queueAction{name = "meander"} + self:queueAction(MeanderAction()) self.last_room = nil end self:updateStaffTitle() @@ -361,13 +368,13 @@ if staff_window and staff_window.staff == self then staff_window:close() end - self.hospital:spendMoney(self.profile.wage, _S.transactions.severance .. ": " .. self.profile.name) - self.world.ui:playSound "sack.wav" + self.hospital:spendMoney(self.profile.wage, _S.transactions.severance .. ": " .. self.profile.name) + self.world.ui:playSound("sack.wav") self:setMood("exit", "activate") self:setDynamicInfoText(_S.dynamic_info.staff.actions.fired) self.fired = true self.hospital:changeReputation("kicked") - self:setHospital(nil) + self:despawn() self.hover_cursor = nil self.attributes["fatigue"] = nil self:leaveAnnounce() @@ -381,7 +388,13 @@ end function Staff:die() - self:setHospital(nil) + self:despawn() + if self.task then + -- If the staff member had a task outstanding, unassigning them from that task. + -- Tasks with no handyman assigned will be eligible for reassignment by the hospital. + self.task.assignedHandyman = nil + self.task = nil + end -- Update the staff management screen (if present) accordingly local window = self.world.ui:getWindow(UIStaffManagement) if window then @@ -391,6 +404,12 @@ self.world.ui.hospital:humanoidDeath(self) end +-- Despawns the staff member and removes them from the hospital +function Staff:despawn() + self.hospital:removeStaff(self) + Humanoid.despawn(self) +end + -- Function which is called when the user clicks on the staff member. -- Responsible for opening a staff information dialog on left click and picking -- up the staff member on right click. @@ -409,7 +428,7 @@ end elseif button == "right" then self.pickup = true - self:setNextAction({name = "pickup", ui = ui, must_happen = true}, true) + self:setNextAction(PickupAction(ui), true) end Humanoid.onClick(self, ui, button) end @@ -451,6 +470,7 @@ end self:setLayer(5, profile.layer5) self:updateStaffTitle() + self.waiting_for_staffroom = false -- Staff member has detected there is no staff room to rest. end function Staff:needsWorkStation() @@ -551,41 +571,33 @@ self:changeAttribute("happiness", -0.0002) end -- If above the policy threshold, go to the staff room. - if self.attributes["fatigue"] >= self.hospital.policies["goto_staffroom"] - and not class.is(self:getRoom(), StaffRoom) then - local profile = self.profile - if self.waiting_for_staffroom then + if self.attributes["fatigue"] >= self.hospital.policies["goto_staffroom"] and + not class.is(self:getRoom(), StaffRoom) then -- The staff will get unhappy if there is no staffroom to rest in. + if self.waiting_for_staffroom then self:changeAttribute("happiness", -0.001) end local room = self:getRoom() - if self.staffroom_needed and ((room and not room:getPatient()) or not room) - or (room and self.going_to_staffroom) then - if self.action_queue[1].name ~= "walk" and self.action_queue[1].name ~= "queue" then + if (self.staffroom_needed and ((room and not room:getPatient()) or not room)) or + (room and self.going_to_staffroom) then + if self:getCurrentAction().name ~= "walk" and self:getCurrentAction().name ~= "queue" then self.staffroom_needed = nil self:goToStaffRoom() end end -- Abort if waiting for a staffroom to be built, waiting for the patient to leave, -- already going to staffroom or being picked up - if self.waiting_for_staffroom or self.staffroom_needed - or self.going_to_staffroom or self.pickup then + if self.waiting_for_staffroom or self.staffroom_needed or + self.going_to_staffroom or self.pickup then return end + -- If no staff room exists, prevent further checks until one is built if not self.world:findRoomNear(self, "staff_room") then - self.waiting_for_staffroom = true - local callback - callback = --[[persistable:staff_build_staff_room_callback]] function(room) - if room.room_info.id == "staff_room" then - self.waiting_for_staffroom = nil - self:unregisterRoomBuildCallback(callback) - end - end - self:registerRoomBuildCallback(callback) + self.waiting_for_staffroom = true -- notifyNewRoom resets it when a staff room gets built. return end - local room = self:getRoom() + if self.humanoid_class ~= "Handyman" and room and room:getPatient() then -- If occupied by patient, staff will go to the staffroom after the patient left. self.staffroom_needed = true @@ -599,6 +611,12 @@ end end +function Staff:notifyNewRoom(room) + if room.room_info.id == "staff_room" then + self.waiting_for_staffroom = false + end +end + function Staff:setCrazy(crazy) if crazy then -- make doctor crazy @@ -629,9 +647,9 @@ if room then room.staff_leaving = true self:setNextAction(room:createLeaveAction()) - self:queueAction{name = "seek_staffroom", must_happen = true} + self:queueAction(SeekStaffRoomAction()) else - self:setNextAction{name = "seek_staffroom", must_happen = true} + self:setNextAction(SeekStaffRoomAction()) end end @@ -649,7 +667,7 @@ self.task = nil end self:updateSpeed() - self:setNextAction{name = "meander"} + self:setNextAction(MeanderAction()) if self.humanoid_class == "Receptionist" then world:findObjectNear(self, "reception_desk", nil, function(x, y) local obj = world:getObject(x, y, "reception_desk") @@ -658,10 +676,9 @@ end end +-- Sets the Hospital for a member of staff +--!param hospital (Hospital) - hospital to assign to member of staff function Staff:setHospital(hospital) - if self.hospital then - self.hospital:removeStaff(self) - end Humanoid.setHospital(self, hospital) self:updateDynamicInfo() end @@ -746,8 +763,8 @@ local room = self:getRoom() if room then -- in special rooms, never - if room.room_info.id == "staff_room" or room.room_info.id == "research" - or room.room_info.id == "training" then + if room.room_info.id == "staff_room" or room.room_info.id == "research" or + room.room_info.id == "training" then return false end @@ -759,8 +776,9 @@ -- For other staff... -- in regular rooms (diagnosis / treatment), if no patient is in sight -- or if the only one in sight is actually leaving. - if self.humanoid_class ~= "Handyman" and room.door.queue:patientSize() == 0 and not self.action_queue[1].is_leaving - and not (room.door.reserved_for and class.is(room.door.reserved_for, Patient)) then + if self.humanoid_class ~= "Handyman" and room.door.queue:patientSize() == 0 and + not self:getCurrentAction().is_leaving and + not (room.door.reserved_for and class.is(room.door.reserved_for, Patient)) then if room:getPatientCount() == 0 then return true else @@ -775,11 +793,10 @@ else -- In the corridor and not on_call (watering or going to room), the staff is free -- unless going back to the training room or research department. - local x, y = self.action_queue[1].x, self.action_queue[1].y + local x, y = self:getCurrentAction().x, self:getCurrentAction().y if x then room = self.world:getRoom(x, y) - if room and (room.room_info.id == "training" - or room.room_info.id == "research") then + if room and (room.room_info.id == "training" or room.room_info.id == "research") then return false end end @@ -816,7 +833,7 @@ -- the salary by. function Staff:increaseWage(amount) self.profile.wage = self.profile.wage + amount - self.world.ui:playSound "cashreg.wav" + self.world.ui:playSound("cashreg.wav") if self.profile.wage > 2000 then -- What cap here? self.profile.wage = 2000 else -- If the cap has been reached this member of staff won't get unhappy @@ -883,6 +900,15 @@ end end + if old < 121 then + if self.humanoid_class == "Handyman" and self.user_of and self.user_of.object_type.class == "Litter" then + local litter = self.user_of + local hospital = self.world:getHospital(litter.tile_x, litter.tile_y) + local taskIndex = hospital:getIndexOfTask(litter.tile_x, litter.tile_y, "cleaning", litter) + hospital:removeHandymanTask(taskIndex, "cleaning") + end + end + Humanoid.afterLoad(self, old, new) end @@ -893,7 +919,7 @@ self.on_call = nil end self.task = nil - self:setNextAction{name = "answer_call"} + self:setNextAction(AnswerCallAction()) end function Staff:searchForHandymanTask() @@ -915,7 +941,7 @@ else if self.attributes[task] < 1 then local sum = self.attributes[task2] + self.attributes[task3] - if math.random(0, sum * 100) > self.attributes[task2] * 100 then + if math.random(0, math.floor(sum * 100)) > math.floor(self.attributes[task2] * 100) then task2, task3 = task3, task2 end index = self.hospital:searchForHandymanTask(self, task2) @@ -933,7 +959,7 @@ end if assignedTask == false then -- Make sure that the handyman isn't meandering already. - for i, action in ipairs(self.action_queue) do + for _, action in ipairs(self.action_queue) do if action.name == "meander" then return false end @@ -941,7 +967,7 @@ if self:getRoom() then self:queueAction(self:getRoom():createLeaveAction()) end - self:queueAction({name = "meander"}) + self:queueAction(MeanderAction()) end return assignedTask end @@ -953,12 +979,12 @@ if taskType == "cleaning" then if self:getRoom() then self:setNextAction(self:getRoom():createLeaveAction()) - self:queueAction{name = "walk", x = task.tile_x, y = task.tile_y} + self:queueAction(WalkAction(task.tile_x, task.tile_y)) else - self:setNextAction{name = "walk", x = task.tile_x, y = task.tile_y} + self:setNextAction(WalkAction(task.tile_x, task.tile_y)) end - self:queueAction{name = "sweep_floor", litter = task.object} - self:queueAction{name = "answer_call"} + self:queueAction(SweepFloorAction(task.object)) + self:queueAction(AnswerCallAction()) else if task.call.dropped then task.call.dropped = nil @@ -978,3 +1004,37 @@ return 4 end end + +--! Estimate staff service quality based on skills, fatigue and happiness. +--!return (float) between [0-1] indicating quality of the service. +function Staff:getServiceQuality() + -- weights + local skill_weight = 0.7 + local fatigue_weight = 0.2 + local happiness_weight = 0.1 + + local weighted_skill = skill_weight * self.profile.skill + local weighted_fatigue = fatigue_weight * self.attributes["fatigue"] + local weighted_happiness = happiness_weight * self.attributes["happiness"] + + return weighted_skill + weighted_fatigue + weighted_happiness +end + +--[[ Return string representation +! Adds Doctor statistics for a "Doctor" object +!return (string) +]] +function Staff:tostring() + local result = Humanoid.tostring(self) + if self.humanoid_class == "Doctor" then + result = result .. string.format("\nSkills: (%.3f) Surgeon (%.3f) Psych (%.3f) Researcher (%.3f)", + self.profile.skill or 0, + self.profile.is_surgeon or 0, + self.profile.is_psychiatrist or 0, + self.profile.is_researcher or 0) + end + return result +end + +-- Dummy callback for savegame compatibility +local callbackNewRoom = --[[persistable:staff_build_staff_room_callback]] function(room) end diff -Nru corsix-th-0.30/CorsixTH/Lua/entities/vip.lua corsix-th-0.62/CorsixTH/Lua/entities/vip.lua --- corsix-th-0.30/CorsixTH/Lua/entities/vip.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entities/vip.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,9 @@ --! A `Vip` who is in the hospital to evaluate the hospital and produce a report class "Vip" (Humanoid) +---@type Vip +local Vip = _G["Vip"] + function Vip:Vip(...) self:Humanoid(...) self.hover_cursor = TheApp.gfx:loadMainCursor("default") @@ -67,17 +70,18 @@ while self.next_room and not self.next_room.is_active do self.next_room_no, self.next_room = next(self.world.rooms, self.next_room_no) end - self:setNextAction{name = "vip_go_to_next_room"} + self:setNextAction(VipGoToNextRoomAction()) end end self.world:findObjectNear(self, "litter", 8, function(x, y) local litter = self.world:getObject(x, y, "litter") + if not litter then + return + end + local alreadyFound = false - if not litter then - return - end - for i=1,(self.num_vomit_noninducing + self.num_vomit_inducing) do + for i=1, (self.num_vomit_noninducing + self.num_vomit_inducing) do if self.found_vomit[i] == litter then alreadyFound = true break @@ -115,7 +119,7 @@ self.going_home = true -- save self.hospital so we can reference it in self:onDestroy self.last_hospital = self.hospital - self:setHospital(nil) + self:despawn() end -- called when the vip is out of the hospital grounds @@ -123,63 +127,59 @@ local message -- First of all there's a special message if we're in free build mode. if self.world.free_build_mode then - self.last_hospital.reputation = self.last_hospital.reputation+20 + self.last_hospital.reputation = self.last_hospital.reputation + 20 message = { {text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)}, - {text = _S.fax.vip_visit_result.remarks.free_build[math.random(1,3)]}, + {text = _S.fax.vip_visit_result.remarks.free_build[math.random(1, 3)]}, choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}} } elseif self.vip_rating == 1 then - self.last_hospital.reputation = self.last_hospital.reputation-10 + self.last_hospital.reputation = self.last_hospital.reputation - 10 message = { {text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)}, - {text = _S.fax.vip_visit_result.remarks.very_bad[math.random(1,3)]}, + {text = _S.fax.vip_visit_result.remarks.very_bad[math.random(1, 3)]}, {text = _S.fax.vip_visit_result.rep_loss}, choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}} } elseif self.vip_rating == 2 then - self.last_hospital.reputation = self.last_hospital.reputation-5 + self.last_hospital.reputation = self.last_hospital.reputation - 5 message = { {text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)}, - {text = _S.fax.vip_visit_result.remarks.bad[math.random(1,3)]}, + {text = _S.fax.vip_visit_result.remarks.bad[math.random(1, 3)]}, {text = _S.fax.vip_visit_result.rep_loss}, choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}} } elseif self.vip_rating == 3 then - self.last_hospital:receiveMoney(self.cash_reward, _S.transactions.vip_award) - self.last_hospital.reputation = self.last_hospital.reputation+(math.round(self.cash_reward/100)) message = { {text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)}, - {text = _S.fax.vip_visit_result.remarks.mediocre[math.random(1,3)]}, - {text = _S.fax.vip_visit_result.rep_boost}, - {text = _S.fax.vip_visit_result.cash_grant:format(self.cash_reward)}, + {text = _S.fax.vip_visit_result.remarks.mediocre[math.random(1, 3)]}, choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}} } elseif self.vip_rating == 4 then self.last_hospital:receiveMoney(self.cash_reward, _S.transactions.vip_award) - self.last_hospital.reputation = self.last_hospital.reputation+(math.round(self.cash_reward/100)) + self.last_hospital.reputation = self.last_hospital.reputation + (math.round(self.cash_reward / 100)) message = { {text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)}, - {text = _S.fax.vip_visit_result.remarks.good[math.random(1,3)]}, + {text = _S.fax.vip_visit_result.remarks.good[math.random(1, 3)]}, {text = _S.fax.vip_visit_result.rep_boost}, {text = _S.fax.vip_visit_result.cash_grant:format(self.cash_reward)}, choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}} } else self.last_hospital:receiveMoney(self.cash_reward, _S.transactions.vip_award) - self.last_hospital.reputation = self.last_hospital.reputation+(math.round(self.cash_reward/100)) - self.last_hospital.pleased_vips_ty = self.last_hospital.pleased_vips_ty +1 + self.last_hospital.reputation = self.last_hospital.reputation + (math.round(self.cash_reward / 100)) + self.last_hospital.pleased_vips_ty = self.last_hospital.pleased_vips_ty + 1 if self.vip_rating == 5 then message = { {text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)}, - {text = _S.fax.vip_visit_result.remarks.super[math.random(1,3)]}, + {text = _S.fax.vip_visit_result.remarks.super[math.random(1, 3)]}, {text = _S.fax.vip_visit_result.rep_boost}, {text = _S.fax.vip_visit_result.cash_grant:format(self.cash_reward)}, choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}} } end end - self.world.ui.bottom_panel:queueMessage("report", message, nil, 24*20, 1) + self.world.ui.bottom_panel:queueMessage("report", message, nil, 24 * 20, 1) self.world:nextVip() @@ -214,14 +214,14 @@ self.room_eval = self.room_eval + 3 end if room.staff_member.attributes["fatigue"] then - if (room.staff_member.attributes["fatigue"] < 0.4) then + if room.staff_member.attributes["fatigue"] < 0.4 then self.room_eval = self.room_eval + 2 end end end -- evaluate the room we're currently looking at - for object, value in pairs(room.objects) do + for object, _ in pairs(room.objects) do if object.object_type.id == "extinguisher" then self.room_eval = self.room_eval + 1 break @@ -257,182 +257,151 @@ function Vip:setVIPRating() --check the visitor to patient death ratio - local deathDiff = self.hospital.num_deaths - self.enter_deaths - local numberVisitorsDiff = self.hospital.num_visitors - self.enter_visitors - if deathDiff == 0 then - if numberVisitorsDiff ~= 0 then --if there have been no new patients, no +/- points + local death_diff = self.hospital.num_deaths - self.enter_deaths + local visitors_diff = self.hospital.num_visitors - self.enter_visitors + if death_diff == 0 then + if visitors_diff ~= 0 then --if there have been no new patients, no +/- points self.vip_rating = self.vip_rating + 20 end else - local deathRatio = numberVisitorsDiff / deathDiff - if deathRatio > 12 then - self.vip_rating = self.vip_rating + 10 - elseif deathRatio >= 8 then - self.vip_rating = self.vip_rating + 5 - elseif deathRatio >= 2 and deathRatio <= 4 then - self.vip_rating = self.vip_rating - 10 - elseif deathRatio < 2 then - self.vip_rating = self.vip_rating - 20 - end + local death_ratio = visitors_diff / death_diff + local death_ratio_rangemap = { + {upper = 2, value = -20}, + {upper = 4, value = -10}, + {upper = 8, value = 0}, + {upper = 12, value = 5}, + {value = 10} + } + self.vip_rating = self.vip_rating + rangeMapLookup(death_ratio, death_ratio_rangemap) end --check the visitor to patient cure ratio - local cureDiff = self.hospital.num_cured - self.enter_cures - local numberVisitorsDiff = self.hospital.num_visitors - self.enter_visitors - if cureDiff == 0 then - if numberVisitorsDiff ~= 0 then --if there have been no new patients, no +/- points + local cure_diff = self.hospital.num_cured - self.enter_cures + if cure_diff == 0 then + if visitors_diff ~= 0 then --if there have been no new patients, no +/- points self.vip_rating = self.vip_rating - 10 end else - local cureRatio = numberVisitorsDiff / cureDiff - if cureRatio > 12 then - self.vip_rating = self.vip_rating - 10 - elseif cureRatio >= 10 then - self.vip_rating = self.vip_rating - 5 - elseif cureRatio >= 3 and cureRatio <= 6 then - self.vip_rating = self.vip_rating + 10 - elseif cureRatio < 3 then - self.vip_rating = self.vip_rating + 20 - end + local cure_ratio = visitors_diff / cure_diff + local cure_ratio_rangemap = { + {upper = 3, value = 20}, + {upper = 6, value = 10}, + {upper = 10, value = 0}, + {upper = 12, value = -5}, + {value = -10} + } + self.vip_rating = self.vip_rating + rangeMapLookup(cure_ratio, cure_ratio_rangemap) end -- check for the average queue length - local queueCounter = 0 + local sum_queue = 0 + local room_count = 0 for _, room in pairs(self.world.rooms) do - -- this can be nil if there has been a room explosion if room.door.queue then - queueCounter = queueCounter + room.door.queue:size() + sum_queue = sum_queue + room.door.queue:size() + end + if not room.crashed then + room_count = room_count + 1 end end - if queueCounter == 0 then + if room_count == 0 then + self.vip_rating = self.vip_rating - 100 + elseif sum_queue == 0 then self.vip_rating = self.vip_rating + 6 else - local queueRatio = queueCounter / #self.world.rooms - if queueRatio < 2 then - self.vip_rating = self.vip_rating + 6 - else - if queueRatio >= 3 and queueRatio <=5 then - self.vip_rating = self.vip_rating + 3 - elseif queueRatio >= 9 and queueRatio <=11 then - self.vip_rating = self.vip_rating - 3 - elseif queueRatio > 11 then - self.vip_rating = self.vip_rating - 6 - end - end + local queue_ratio = sum_queue / room_count + local queue_ratio_rangemap = { + {upper = 2, value = 6}, + {upper = 5, value = 3}, + {upper = 9, value = 0}, + {upper = 11, value = -3}, + {value = -6} + } + self.vip_rating = self.vip_rating + rangeMapLookup(queue_ratio, queue_ratio_rangemap) end -- now we check for toilet presence - local toiletsFound = 0 - for i, room in pairs(self.world.rooms) do - if (room.room_info.id == "toilets") then - for object, value in pairs(room.objects) do - if (object.object_type.id == "loo") then - toiletsFound = toiletsFound + 1 + local sum_toilets = 0 + for _, room in pairs(self.world.rooms) do + if room.room_info.id == "toilets" then + for object, _ in pairs(room.objects) do + if object.object_type.id == "loo" then + sum_toilets = sum_toilets + 1 end end end end - if (toiletsFound == 0) then + if sum_toilets == 0 then self.vip_rating = self.vip_rating - 6 else - local patientToToilet = #self.hospital.patients / toiletsFound - if (patientToToilet <= 10) then - self.vip_rating = self.vip_rating + 6 - elseif (patientToToilet <= 20) then - self.vip_rating = self.vip_rating + 3 - elseif (patientToToilet > 40) then - self.vip_rating = self.vip_rating - 3 - end + local patients_per_toilet = #self.hospital.patients / sum_toilets + local toilet_ratio_rangemap = { + {upper = 10, value = 6}, + {upper = 20, value = 3}, + {upper = 40, value = 0}, + {value = -3} + } + self.vip_rating = self.vip_rating + rangeMapLookup(patients_per_toilet, toilet_ratio_rangemap) end -- check the levels of non-vomit inducing litter in the hospital - if (self.num_vomit_noninducing < 3) then - self.vip_rating = self.vip_rating + 4 - else - if (self.num_vomit_noninducing <5) then - self.vip_rating = self.vip_rating + 2 - elseif (self.num_vomit_noninducing >= 7 and self.num_vomit_noninducing <= 8) then - self.vip_rating = self.vip_rating - 2 - elseif (self.num_vomit_noninducing > 8) then - self.vip_rating = self.vip_rating - 4 - end - end + local litter_ratio_rangemap = { + {upper = 3, value = 4}, + {upper = 5, value = 2}, + {upper = 7, value = 0}, + {upper = 8, value = -2}, + {value = -4} + } + self.vip_rating = self.vip_rating + rangeMapLookup(self.num_vomit_noninducing, litter_ratio_rangemap) -- check the levels of vomit inducing litter in the hospital - if (self.num_vomit_inducing < 3) then - self.vip_rating = self.vip_rating + 8 - else - if (self.num_vomit_inducing < 5) then - self.vip_rating = self.vip_rating + 4 - else - if (self.num_vomit_inducing >= 6 and self.num_vomit_inducing <= 7) then - self.vip_rating = self.vip_rating - 6 - elseif (self.num_vomit_inducing < 10) then - self.vip_rating = self.vip_rating - 12 - elseif (self.num_vomit_inducing <= 12) then - self.vip_rating = self.vip_rating - 16 - elseif (self.num_vomit_inducing > 12) then - self.vip_rating = self.vip_rating - 20 - end - end - end + local inducing_ratio_rangemap = { + {upper = 3, value = 8}, + {upper = 5, value = 4}, + {upper = 6, value = 0}, + {upper = 7, value = -6}, + {upper = 10, value = -12}, + {upper = 12, value = -16}, + {value = -20} + } + self.vip_rating = self.vip_rating + rangeMapLookup(self.num_vomit_inducing, inducing_ratio_rangemap) -- if there were explosions, hit the user hard - local explosionsDiff = self.hospital.num_explosions - self.enter_explosions - if (explosionsDiff > 0) then + if self.hospital.num_explosions ~= self.enter_explosions then self.vip_rating = self.vip_rating - 70 end -- check the vip heat level - if self.attributes["warmth"] >= 0.80 then - self.vip_rating = self.vip_rating + 5 - elseif self.attributes["warmth"] >= 0.60 then - self.vip_rating = self.vip_rating + 3 - elseif self.attributes["warmth"] >= 0.20 and self.attributes["warmth"] < 0.40 then - self.vip_rating = self.vip_rating - 3 - elseif self.attributes["warmth"] < 0.20 then - self.vip_rating = self.vip_rating - 5 - end + local heat_ratio_rangemap = { + {upper = 0.20, value = -5}, + {upper = 0.40, value = -3}, + {upper = 0.60, value = 0}, + {upper = 0.80, value = 3}, + {value = 5} + } + self.vip_rating = self.vip_rating + rangeMapLookup(self.attributes["warmth"], heat_ratio_rangemap) -- check the seating : standing ratio of waiting patients -- find all the patients who are currently waiting around - local numberSitting = 0 - local numberStanding = 0 - for _, patient in ipairs(self.hospital.patients) do - if (patient.action_queue[1].name == "idle") then - numberStanding = numberStanding + 1 - elseif (patient.action_queue[1].name == "use_object" and - patient.action_queue[1].object.object_type.id == "bench") then - numberSitting = numberSitting + 1 - end - end - - if (numberSitting - numberStanding > 0) then + local sum_sitting, sum_standing = self.hospital:countSittingStanding() + if sum_sitting >= sum_standing then self.vip_rating = self.vip_rating + 4 - elseif (numberSitting - numberStanding < 0) then + else self.vip_rating = self.vip_rating - 4 end -- check average patient thirst - local totalThirst = 0 - for _, patient in ipairs(self.hospital.patients) do - if (patient.attributes["thirst"]) then - totalThirst = totalThirst + patient.attributes["thirst"] - end - end - - if #self.hospital.patients ~= 0 then - local averageThirst = totalThirst / #self.hospital.patients - if averageThirst >= 0.80 then - self.vip_rating = self.vip_rating + 3 - elseif averageThirst >= 0.60 then - self.vip_rating = self.vip_rating + 1 - elseif averageThirst >= 0.20 and averageThirst < 0.40 then - self.vip_rating = self.vip_rating - 1 - elseif averageThirst < 0.20 then - self.vip_rating = self.vip_rating - 5 - end + local avg_thirst = self.hospital:getAveragePatientAttribute("thirst", nil) + if avg_thirst then + local thirst_ratio_rangemap = { + {upper = 0.20, value = -5}, + {upper = 0.40, value = -1}, + {upper = 0.60, value = 0}, + {upper = 0.80, value = 1}, + {value = 3} + } + self.vip_rating = self.vip_rating + rangeMapLookup(avg_thirst, thirst_ratio_rangemap) end if self.num_visited_rooms ~= 0 then @@ -440,73 +409,58 @@ end -- check average patient happiness - local totalHappiness = 0 - for _, patient in ipairs(self.hospital.patients) do - totalHappiness = totalHappiness + patient.attributes["happiness"] - end - - if #self.hospital.patients ~= 0 then - local averageHappiness = totalHappiness / #self.hospital.patients - if averageHappiness >= 0.80 then - self.vip_rating = self.vip_rating + 10 - elseif averageHappiness >= 0.60 then - self.vip_rating = self.vip_rating + 5 - elseif averageHappiness >= 0.20 and averageHappiness < 0.40 then - self.vip_rating = self.vip_rating - 5 - else - self.vip_rating = self.vip_rating - 10 - end + local avg_happiness = self.hospital:getAveragePatientAttribute("happiness", nil) + if avg_happiness then + local patients_happy_ratio_rangemap = { + {upper = 0.20, value = -10}, + {upper = 0.40, value = -5}, + {upper = 0.60, value = 0}, + {upper = 0.80, value = 5}, + {value = 10} + } + self.vip_rating = self.vip_rating + rangeMapLookup(avg_happiness, patients_happy_ratio_rangemap) end -- check average staff happiness - local totalHappiness = 0 - for _, staff in ipairs(self.hospital.staff) do - totalHappiness = totalHappiness + staff.attributes["happiness"] - end - - if #self.hospital.staff ~= 0 then - local averageHappiness = totalHappiness / #self.hospital.staff - if averageHappiness >= 0.80 then - self.vip_rating = self.vip_rating + 10 - elseif averageHappiness >= 0.60 then - self.vip_rating = self.vip_rating + 5 - elseif averageHappiness >= 0.20 and averageHappiness < 0.40 then - self.vip_rating = self.vip_rating - 5 - else - self.vip_rating = self.vip_rating - 10 - end + avg_happiness = self.hospital:getAverageStaffAttribute("happiness", nil) + if avg_happiness then + local staff_happy_ratio_rangemap = { + {upper = 0.20, value = -10}, + {upper = 0.40, value = -5}, + {upper = 0.60, value = 0}, + {upper = 0.80, value = 5}, + {value = 10} + } + self.vip_rating = self.vip_rating + rangeMapLookup(avg_happiness, staff_happy_ratio_rangemap) end -- set the cash reward value if tonumber(self.world.map.level_number) then - self.cash_reward = math.round(self.world.map.level_number * self.vip_rating)*10 + self.cash_reward = math.round(self.world.map.level_number * self.vip_rating) * 10 else -- custom level, it has no level number. Default back to one. - self.cash_reward = math.round(1 * self.vip_rating)*10 + self.cash_reward = math.round(1 * self.vip_rating) * 10 end if self.cash_reward > 2000 then self.cash_reward = 2000 end -- give the rating between 1 and 5 - if (self.vip_rating < 25) then - self.vip_rating = 1 - elseif (self.vip_rating < 45) then - self.vip_rating = 2 - elseif (self.vip_rating < 65) then - self.vip_rating = 3 - elseif (self.vip_rating < 85) then - self.vip_rating = 4 - else - self.vip_rating = 5 - end + local rating_ratio_rangemap = { + {upper = 25, value = 1}, + {upper = 45, value = 2}, + {upper = 65, value = 3}, + {upper = 85, value = 4}, + {value = 5} + } + self.vip_rating = rangeMapLookup(self.vip_rating, rating_ratio_rangemap) self.hospital.num_vips_ty = self.hospital.num_vips_ty + 1 end function Vip:afterLoad(old, new) if old < 50 then self.num_visited_rooms = 0 - self:setNextAction{name = "idle"} + self:setNextAction(IdleAction()) self.waiting = 1 for _, room in pairs(self.world.rooms) do if room.door.reserved_for == self then diff -Nru corsix-th-0.30/CorsixTH/Lua/entity.lua corsix-th-0.62/CorsixTH/Lua/entity.lua --- corsix-th-0.30/CorsixTH/Lua/entity.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entity.lua 2018-07-21 11:13:17.000000000 +0000 @@ -21,27 +21,64 @@ --! Abstraction for visible gameplay things which sit somewhere on the map. class "Entity" -local TH = require "TH" +---@type Entity +local Entity = _G["Entity"] + +local TH = require("TH") function Entity:Entity(animation) self.th = animation self.layers = {} animation:setHitTestResult(self) self.ticks = true - self.dynamic_info = nil; + self.playing_sounds_in_random_sequence = false + self.waiting_for_sound_effects_to_be_turned_on = false + self.random_sound_sequence_parameters = nil + self.dynamic_info = nil end --- This plays a sound "at" the entity, meaning the sound will not be played --- if the entity is off-screen, and the volume will be quieter the further --- the entity is from the center of the screen. If this is not what you want --- then use UI:playSound instead. --- !param name (string, integer) The filename or ordinal of the sound to play. -function Entity:playSound(name) +--[[ +This plays a sound "at" the entity, meaning the sound will not be played +if the entity is off-screen, and the volume will be quieter the further +the entity is from the center of the screen. If this is not what you want +then use UI:playSound instead. +!param name (string, integer) The filename or ordinal of the sound to play. +!param played_callback (function) a optional parameter. +!param played_callback_delay (integer) a optional milliseconds parameter. +--]] +function Entity:playSound(name, played_callback, played_callback_delay) if TheApp.config.play_sounds then - TheApp.audio:playSound(name, self) + TheApp.audio:playSound(name, self, false, played_callback, played_callback_delay) end end +function Entity:setWaitingForSoundEffectsToBeTurnedOn(state) + self.waiting_for_sound_effects_to_be_turned_on = true +end + +--[[ +Plays a sequence of related sounds at an entity while entity.playing_sounds_in_random_sequence = true. + +The silences between these sounds can either have randomly generated lengths between the min and max length parameters or +they can all be a specified length by providing min and max tables with one value for the desired pause duration. + +!param name_pattern (String) example: LAVA00*.WAV +!param min_silence_lengths (table) the desired mininum silences length for the different tick rates, [3] = Normal +!param max_silence_lengths (table) the desired maximum silences length for the different tick rates, [3] = Normal +!param num_silences (integer) how many different silence lengths should be used, this can be a nil parameter. +-]] +function Entity:playEntitySounds(name_pattern, min_silence_lengths, max_silence_lengths, num_silences) + self.playing_sounds_in_random_sequence = true + self.random_sound_sequence_parameters = {} + self.random_sound_sequence_parameters["namePattern"] = name_pattern + self.random_sound_sequence_parameters["minSilence"] = min_silence_lengths + self.random_sound_sequence_parameters["maxSilence"] = max_silence_lengths + self.random_sound_sequence_parameters["numSilences"] = num_silences + + TheApp.audio:playEntitySounds(name_pattern, self, + min_silence_lengths, max_silence_lengths, num_silences) +end + --[[ Set which animation is used to give the entity a visual appearance. ! Until an entity is given an animation, it is invisible to the player. Note that some "animations" consist of a single frame, and hence the term animation @@ -73,6 +110,12 @@ if self.user_of then print("Warning: Entity tile changed while marked as using an object") end + local entity_map = self.world.entity_map + -- Remove the reference to the entity at it's previous coordinates + if entity_map then + entity_map:removeEntity(self.tile_x,self.tile_y, self) + end + self.tile_x = x self.tile_y = y self.th:setDrawingLayer(self:getDrawingLayer()) @@ -81,6 +124,12 @@ if self.mood_info then self.mood_info:setParent(self.th) end + + -- Update the entity map for the new position + if entity_map then + entity_map:addEntity(x,y,self) + end + return self end @@ -143,7 +192,7 @@ -- recurring or long-duration tasks. function Entity:tick() if self.num_animation_ticks then - for i = 1, self.num_animation_ticks do + for _ = 1, self.num_animation_ticks do self:_tick() end if self.num_animation_ticks == 1 then @@ -152,6 +201,7 @@ else self:_tick() end + -- Tick any mood animation if self.mood_info then self.mood_info:tick() end @@ -187,7 +237,7 @@ --[[ Register a function (related to the entity) to be called at a later time. ! Each `Entity` can have a single timer associated with it, and due to this limit of one, it is almost always the case that the currently active humanoid -action is the only thing wich calls `setTimer`. +action is the only thing which calls `setTimer`. If self.slow_animation is set then all timers will be doubled as animation length will be doubled. !param tick_count (integer) If 0, then `f` will be called during the entity's @@ -223,6 +273,8 @@ -- Function which is called when the entity is to be permanently removed from -- the world. function Entity:onDestroy() + -- Clear any mood + self:setMoodInfo() self:setTile(nil) self.world.dispatcher:dropFromQueue(self) -- Debug aid to check that there are no hanging references after the entity @@ -232,6 +284,9 @@ getmetatable(self.gc_dummy).__gc = function() print("Entity " .. tostring(self) .. " has been garbage collected.") end --]] + if self.waiting_for_sound_effects_to_be_turned_on then + TheApp.audio:entityNoLongerWaitingForSoundsToBeTurnedOn(self) + end end -- Function which is called at the end of each ingame day. Should be used to @@ -240,9 +295,18 @@ function Entity:tickDay() end +--! Notify the entity of a new object. +--!param id Name of the new object. +-- TODO Currently only used for benches placed nearby. +-- TODO Maybe also pass the object tile coordinates? function Entity:notifyNewObject(id) end +--! Notify the entity that a new room was built. +--!param room (Room) The new room. +function Entity:notifyNewRoom(room) +end + function Entity:setMood(mood_name, activate) end @@ -273,6 +337,21 @@ function Entity:afterLoad(old, new) end +function Entity:playAfterLoadSound() + if self.random_sound_sequence_parameters then + self.playing_sounds_in_random_sequence = true + self:playEntitySounds(self.random_sound_sequence_parameters["namePattern"], + self.random_sound_sequence_parameters["minSilence"], + self.random_sound_sequence_parameters["maxSilence"], + self.random_sound_sequence_parameters["numSilences"]) + end +end + +--! Stub to be extended in subclasses, if needed. +function Entity:eraseObject() + -- Give entity the chance to clear itself from the map before resetAnimation gets called. +end + function Entity:resetAnimation() self.th:setDrawingLayer(self:getDrawingLayer()) local x, y = self.tile_x, self.tile_y diff -Nru corsix-th-0.30/CorsixTH/Lua/entity_map.lua corsix-th-0.62/CorsixTH/Lua/entity_map.lua --- corsix-th-0.30/CorsixTH/Lua/entity_map.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/entity_map.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,196 @@ +--[[ Copyright (c) 2013 William "sadger" Gatens + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +class "EntityMap" + +---@type EntityMap +local EntityMap = _G["EntityMap"] + +--[[ An entity map is a structure is a 2 dimensional structure created from a +game map, it has the same dimensions as the game map which intitalises it. +The purpose of the map is store the location of entities in the map in +real-time. Each cell given by an (x, y) coordinate is a +table {humanoids ={}, objects = {}} where the tables of humanoids/objects +may be empty or contain the entity/entities that currently exist in that tile.]] +function EntityMap:EntityMap(map) + self.width, self.height = map.th:size() + self.entity_map = {} + for x = 1, self.width do + self.entity_map[x] = {} + for y = 1, self.height do + self.entity_map[x][y] = {humanoids = {}, objects = {}} + end + end +end + +local function add_entity_to_table(entity, entity_table) + entity_table[#entity_table+1] = entity +end + +--[[Adds an entity to the entity map in a specified location +@param x (integer) the x coordinate of the entity +@param y (integer) the y coordinate of the entity +@param entity (Entity) the entity to be added to the map in the (x, y) position]] +function EntityMap:addEntity(x, y, entity) + -- Distinguish between entity types and add them + -- to the respective tables + if x and y and entity then + if class.is(entity, Humanoid) then + add_entity_to_table(entity, self:getHumanoidsAtCoordinate(x, y)) + elseif class.is(entity, Object) then + add_entity_to_table(entity, self:getObjectsAtCoordinate(x, y)) + end + end +end + +-- Iterates through a table and removes the given entity +local function remove_entity_from_table(entity, entity_table) + local index = -1 + for i, h in ipairs(entity_table) do + if h == entity then + -- If we have found it no need to keep looking + index = i + break + end + end + -- We haven't found it so we have incorrectly tried to remove it + assert(index ~= -1, "Tried to remove entity from entity_map - entity not found") + table.remove(entity_table, index) +end + +--[[Removes an entity from the entity map given specified location +Assumes the entity already has been added in the (x, y) position or will cause +the assertion that the entity is contained in the map to fail. +@param x (integer) the x coordinate of the entity +@param y (integer) the y coordinate of the entity +@param entity (Entity) the entity to be removed from the map in the (x, y) position ]] +function EntityMap:removeEntity(x, y, entity) + -- Distinguish between entity types to find table to remove from + -- then remove the entity from that table + if x and y and entity then + if class.is(entity, Humanoid) then + remove_entity_from_table(entity, self:getHumanoidsAtCoordinate(x, y)) + elseif class.is(entity, Object) then + remove_entity_from_table(entity, self:getObjectsAtCoordinate(x, y)) + end + end +end + + +--[[Returns a map of all entities (objects and humanoids) at a specified coordinate +@param x (integer) the x coordinate to retrieve entities from +@param y (integer) the y coordinate to retrieve entities from +@return entity_map (table) containing the entities at the (x, y) coordinate ]] +function EntityMap:getEntitiesAtCoordinate(x, y) + --Add all the humanoids + local entity_table = {} + for _, obj in ipairs(self:getHumanoidsAtCoordinate(x, y)) do + table.insert(entity_table, obj) + end + + --Add all the objects + for _, obj in ipairs(self:getObjectsAtCoordinate(x, y)) do + table.insert(entity_table, obj) + end + + return entity_table +end + +--[[Returns a table of all humanoids at a specified coordinate +@param x (integer) the x coordinate to retrieve entities from +@param y (integer) the y coordinate to retrieve entities from +@return (table) containing the humanoids at the (x, y) coordinate ]] +function EntityMap:getHumanoidsAtCoordinate(x, y) + assert(x >= 1 and y >= 1 and x <= self.width and y <= self.height, + "Coordinate requested is out of the entity map bounds") + return self.entity_map[x][y]["humanoids"] +end + +--[[Returns a table of all objects at a specified coordinate +@param x (integer) the x coordinate to retrieve entities from +@param y (integer) the y coordinate to retrieve entities from +@return (table) containing the objects at the (x, y) coordinate ]] +function EntityMap:getObjectsAtCoordinate(x, y) + assert(x >= 1 and y >= 1 and x <= self.width and y <= self.height, + "Coordinate requested is out of the entity map bounds") + return self.entity_map[x][y]["objects"] +end + + +--[[ Returns a map of coordinates {{x1, y1}, ... {xn, yn}} directly +adjacent to a given (x, y) coordinate - no diagonals +@param x (integer) the x coordinate to obtain adjacent tiles from +@param y (integer) the y coordinate to obtain adjacent tiles from ]] +function EntityMap:getAdjacentSquares(x, y) + -- Table of coordinates {x=integer, y=integer} representing (x, y) coordinates + local adjacent_squares = {} + if x and y then + if x ~= 1 then + adjacent_squares[#adjacent_squares+1] = {x = x-1, y = y} + end + if x ~= self.width then + adjacent_squares[#adjacent_squares+1] = {x = x+1, y = y} + end + if y ~= 1 then + adjacent_squares[#adjacent_squares+1] = {x = x, y = y-1} + end + if y ~= self.height then + adjacent_squares[#adjacent_squares+1] = {x = x, y = y+1} + end + end + return adjacent_squares +end + +--[[ Returns all the entities which are patients in the squares directly adjacent +to the given (x, y) coordinate - diagonals are not considered +@param x (integer) the x coordinate to obtain adjacent patients from +@param y (integer) the y coordinate to obtain adjacent patients from ]] +function EntityMap:getPatientsInAdjacentSquares(x, y) + local adjacent_patients = {} + for _, coord in ipairs(self:getAdjacentSquares(x, y)) do + for _, humanoid in ipairs(self:getHumanoidsAtCoordinate(coord.x, coord.y)) do + if class.is(humanoid, Patient) then + adjacent_patients[#adjacent_patients + 1] = humanoid + end + end + end + return adjacent_patients +end + +--[[ Returns a map of coordinates {{x1, y1}, ... {xn, yn}} of +the adjacent tiles (no diagonals) which do not contain any humanoids or objects +does NOT determine if the tile is reachable from (x, y) may even be in a +different room +@param x (integer) the x coordinate to obtain free tiles from +@param y (integer) the y coordinate to obtain free tiles from ]] +function EntityMap:getAdjacentFreeTiles(x, y) + local adjacent_free_tiles = {} + for _, coord in ipairs(self:getAdjacentSquares(x, y)) do + local x_coord = coord['x'] + local y_coord = coord['y'] + -- If no object or humanoid occupy the til_coorde + if #self:getHumanoidsAtCoordinate(x_coord, y_coord) == 0 and + #self:getObjectsAtCoordinate(x_coord, y_coord) == 0 then + adjacent_free_tiles[#adjacent_free_tiles+1] = coord + end + end + return adjacent_free_tiles +end + diff -Nru corsix-th-0.30/CorsixTH/Lua/epidemic.lua corsix-th-0.62/CorsixTH/Lua/epidemic.lua --- corsix-th-0.30/CorsixTH/Lua/epidemic.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/epidemic.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,704 @@ +--[[ Copyright (c) 2013 William "sadger" Gatens + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +class "Epidemic" + +---@type Epidemic +local Epidemic = _G["Epidemic"] + +--[[Manages the epidemics that occur in hospitals. Generally, any epidemic +logic that happens outside this class will call functions contained here.]] +function Epidemic:Epidemic(hospital, contagious_patient) + self.hospital = hospital + self.world = self.hospital.world + + self.infected_patients = {} + + -- The contagious disease the epidemic is based around + self.disease = contagious_patient.disease + + -- Can the epidemic be revealed to the player + self.ready_to_reveal = false + + -- Is the epidemic revealed to the player? + self.revealed = false + + -- Various values for the different outcomes - used when result fax is sent + self.declare_fine = 0 + self.reputation_hit = 0 + self.coverup_fine = 0 + self.compensation = 0 + + -- Is the epidemic bad enough to deserve the whole hospital to be evacuated + self.will_be_evacuated = false + + -- Fax sent when the result of the cover up is revealed to the player + self.cover_up_result_fax = {} + + -- Set if the user choses the cover up option instead of declaring + self.coverup_in_progress = false + + --Cover up timer and amount of intervals the timer has + self.timer = nil + self.countdown_intervals = 0 + + -- Set when we know if the player has passed/failed the epidemic + -- generally used to test if infected patients can still infect others + self.result_determined = false + + -- Vaccination mode is activated when the icon on the timer + -- is clicked - used to determine what the cursor should look like + self.vaccination_mode_active = false + + -- For Cheat - Show the contagious icon even before the epidemic is revealed? + self.cheat_always_show_mood = false + + -- Number of times an infect patient has successfully infected another + self.total_infections = 0 + -- Number of times any infected patient has tried to infected another - successful or not + self.attempted_infections = 0 + + local level_config = self.world.map.level_config + -- How often is the epidemic disease passed on? Represents a percentage + -- spread_factor% of the time a disease is passed on to a suitable target + self.spread_factor = level_config.gbv.ContagiousSpreadFactor or 25 + -- How many people still infected and not cure causes the player to take a reputation hit as well as a fine + -- has no effect if more than evacuation_minimum - hospital is evacuated anyway + self.reputation_loss_minimum = level_config.gbv.EpidemicRepLossMinimum or 5 + -- How many people need to still be infected and not cure to cause the + -- inspector to evacuate the hospital + self.evacuation_minimum = level_config.gbv.EpidemicEvacMinimum or 10 + + -- The health inspector who reveals the result of the epidemic + self.inspector = nil + + self:addContagiousPatient(contagious_patient) + -- Mark all the patients currently in the hospital as passed reception - for compatibility + self:markPatientsAsPassedReception() +end + +--[[ The epidemic tick - currently the same rate as the hospital's tick but +not necessary dependent on it - could potentially be reduced for performance.]] +function Epidemic:tick() + if not self.ready_to_reveal then + self:checkIfReadyToReveal() + end + if not self.result_determined then + self:infectOtherPatients() + end + if self.coverup_in_progress then + if not self.result_determined then + self:checkNoInfectedPlayerHasLeft() + self:markedPatientsCallForVaccination() + self:showAppropriateAdviceMessages() + end + self:tryAnnounceInspector() + end + self:checkPatientsForRemoval() +end + + +--[[ Adds a new patient to the epidemic who is actively contagious: infected but + not vaccinated or cured]] +function Epidemic:addContagiousPatient(patient) + patient.infected = true + patient:updateDynamicInfo() + self.infected_patients[#self.infected_patients + 1] = patient + if self.coverup_in_progress or self.cheat_always_show_mood then + patient:setMood("epidemy4","activate") + end +end + +--[[ Goes through all infected patients checking if there are any other patients + in adjacent squares that can be infected, and if so infects them turning + them into an infected patient too. ]] +function Epidemic:infectOtherPatients() + --[[ Can an infected patient infect another patient - taking into account + spread factor as defined in the configuration. Patients must be both in the + corridors or in the same room - don't infect through walls. + @param patient (Patient) already infected patient + @param other (Patient) target to possibly infect + @return true if patient can infect other, false otherwise (boolean) ]] + local function canInfectOther(patient, other) + -- Patient is not infectious. + if patient.cured or patient.vaccinated then return false end + + -- 'other' is already infected or is going home. + if other.infected or other.cured or other.vaccinated then return false end + if other.is_emergency then return false end -- Don't interact with emergencies. + + -- If the other patient has a different disease OR the other patient's + -- disease cannot be changed. + if patient.disease ~= other.disease and + (not other.disease.contagious or other.diagnosed) then return false end + + if other.attempted_to_infect then return false end + + -- Only infect if both are in the same room. + return patient:getRoom() == other:getRoom() + end + + local function infect_other(infected_patient, patient) + if infected_patient.disease == patient.disease then + self:addContagiousPatient(patient) + self.total_infections = self.total_infections + 1 + else + patient:changeDisease(infected_patient.disease) + self:addContagiousPatient(patient) + self.total_infections = self.total_infections + 1 + end + end + + -- Scale the chance of spreading the disease infecting spread_factor% + -- of patients results in too large an epidemic typically so infect + -- spread_factor/spread_scale_factor patients. + -- This scale factor is purely for balance purposes, the larger the + -- value the less spreading the epidemics will be, all relative to spread_factor. + -- Must be > 0. + local spread_scale_factor = 200 + + -- Go through all infected patients making the check if they can infect + -- and making any patient they can infect contagious too. + local entity_map = self.world.entity_map + if entity_map then + for _, infected_patient in ipairs(self.infected_patients) do + local adjacent_patients = + entity_map:getPatientsInAdjacentSquares(infected_patient.tile_x, infected_patient.tile_y) + for _, patient in ipairs(adjacent_patients) do + if canInfectOther(infected_patient, patient) then + patient.attempted_to_infect = true + self.attempted_infections = self.attempted_infections + 1 + if (self.total_infections / self.attempted_infections) < + (self.spread_factor / spread_scale_factor) then + infect_other(infected_patient, patient) + end + end + end + end + end + +end + +--[[ The epidemic is ready to be revealed to the player if any infected patient + is fully diagnosed. N.B. because multiple epidemics are queued to become + the "active" one, being ready to reveal does NOT guarantee an epidemic + WILL be revealed to the player and may even terminate before they are even + aware it existed. ]] +function Epidemic:checkIfReadyToReveal() + for _, infected_patient in ipairs(self.infected_patients) do + if infected_patient.diagnosed then + self.ready_to_reveal = true + break + end + end +end + +--[[ Show the player the have an epidemic - send a fax + This happens when the epidemic is chosen to the be + the "active" epidemic out of all the queued ones.]] +function Epidemic:revealEpidemic() + assert(self.ready_to_reveal) + self.revealed = true + self:sendInitialFax() + self:announceStartOfEpidemic() +end + +--[[ Plays the announcement for the start of the epidemic ]] +function Epidemic:announceStartOfEpidemic() + local announcements = {"EPID001.wav", "EPID002.wav", "EPID003.wav", "EPID004.wav"} + if self.hospital:isPlayerHospital() then + self.world.ui:playAnnouncement(announcements[math.random(1, #announcements)]) + end +end + + +--[[ Plays the announcement for the end of the epidemic ]] +function Epidemic:announceEndOfEpidemic() + local announcements = {"EPID005.wav", "EPID006.wav", "EPID007.wav", "EPID008.wav"} + if self.hospital:isPlayerHospital() then + self.world.ui:playAnnouncement(announcements[math.random(1, #announcements)]) + end +end + +--[[ Checks for conditions that could end the epidemic earlier than + the length of the timer. If an infected patient leaves the + hospital it's discovered instantly and will result in a fail.]] +function Epidemic:checkNoInfectedPlayerHasLeft() + if self.result_determined then return end + + -- Check whether a patient has left. + for _, infected_patient in ipairs(self.infected_patients) do + local px, py = infected_patient.tile_x, infected_patient.tile_y + -- If leaving and no longer in the hospital. + if infected_patient.going_home and not infected_patient.cured and + px and py and not self.hospital:isInHospital(px,py) then + -- Patient escaped from the hospital, discovery is inevitable. + self.result_determined = true + if not self.inspector then + self:spawnInspector() + end + self:finishCoverUp() + return + end + end +end + +--[[Remove any patients which were already on their way out or died before the +epidemic was started to be fair on the players so they don't instantly fail. +Additionally if any patients die during an epidemic we also remove them, +otherwise a player may never win the epidemic in such a case.]] +function Epidemic:checkPatientsForRemoval() + for i, infected_patient in ipairs(self.infected_patients) do + if (not self.coverup_in_progress and infected_patient.going_home) or + infected_patient.dead then + table.remove(self.infected_patients,i) + end + end +end + +--[[ Toggle the vaccination mode changes how the cursor interacts with + the hospital. Toggled by pressing the button on the watch +(@see UIWatch:UIWatch) ]] +function Epidemic:toggleVaccinationMode() + self.vaccination_mode_active = not self.vaccination_mode_active + local cursor = self.vaccination_mode_active and "epidemic_hover" or "default" + self.world.ui:setCursor(self.world.ui.app.gfx:loadMainCursor(cursor)) +end + +--[[ Show a patient is able to be vaccinated, this is shown to the player by + changing the icon, once a player has been marked for vaccination they may + possibly become a vaccination candidate. Marking is done by clicking + the player and can only happen during a cover up. ]] +function Epidemic:markForVaccination(patient) + if patient.infected and not patient.vaccinated and + not patient.marked_for_vaccination then + patient.marked_for_vaccination = true + patient:setMood("epidemy4","deactivate") + patient:setMood("epidemy2","activate") + end +end + + + +--[[ Counts the number of patients that have been infected that are still +-- infected +-- @return infected_count (Integer) the number of patients still infected.]] +function Epidemic:countInfectedPatients() + local infected_count = 0 + for _, patient in pairs(self.infected_patients) do + if patient.infected and not patient.cured then + infected_count = infected_count + 1 + end + end + return infected_count +end + +--[[ Sends the initial fax to the player when the epidemic is revealed.]] +function Epidemic:sendInitialFax() + local num_infected = self:countInfectedPatients() + --Save it in a global variable so we can apply the fine in the declare function + self.declare_fine = self:calculateInfectedFine(num_infected) + + local message = { + {text = _S.fax.epidemic.disease_name:format(self.disease.name)}, + {text = _S.fax.epidemic.declare_explanation_fine:format(self.declare_fine)}, + {text = _S.fax.epidemic.cover_up_explanation_1}, + {text = _S.fax.epidemic.cover_up_explanation_2}, + choices = { + {text = _S.fax.epidemic.choices.declare, choice = "declare_epidemic"}, + {text = _S.fax.epidemic.choices.cover_up, choice = "cover_up_epidemic"}, + }, + } + self.world.ui.bottom_panel:queueMessage("epidemy", message, nil, 24*20,2) +end + +--[[ Calculate the fine for having a given number of infected patients +--Used to determine the initial declaration fine as the cover up fine. +--@param infected_count (Integer) number of patients still infected +--@return fine (Integer) the fine amount ]] +function Epidemic:calculateInfectedFine(infected_count) + local level_config = self.world.map.level_config + local fine_per_infected = level_config.gbv.EpidemicFine or 2000 + return math.max(2000, infected_count * fine_per_infected) +end + +--[[ Gets the amount of reputation to add/remove from the player + based on a given fine. Reputation gain/loss isn't specified + in the configs so we use a percentage of the fine as a base + value with extra being gained/lost for specific circumstances. + @param fine_amount (Integer) amount the player will be fined + @return reputation hit (Integer) reputation to be deducted relative to fine]] +local function getBaseReputationFromFine(fine_amount) + return math.round(fine_amount / 100) +end + +--[[ When the player chooses to declare the epidemic instead of trying + to cover up it from the initial faxes - ends the epidemic immediately + after applying fine.]] +function Epidemic:resolveDeclaration() + self.result_determined = true + self:clearAllInfectedPatients() + + --No fax for declaration just apply fines and rep hit + self.hospital:spendMoney(self.declare_fine, _S.transactions.epidemy_fine) + local reputation_hit = getBaseReputationFromFine(self.declare_fine) + self.hospital.reputation = self.hospital.reputation - reputation_hit + self.hospital.epidemic = nil +end + +--[[ Remove all infected patients by vaccinating from the hospital and clear + any epidemic-specific icons from their heads.]] +function Epidemic:clearAllInfectedPatients() + for _, infected_patient in ipairs(self.infected_patients) do + -- Remove any vaccination calls still open + infected_patient:removeVaccinationCandidateStatus() + self.world.dispatcher:dropFromQueue(infected_patient) + infected_patient.vaccinated = true + infected_patient:setMood("epidemy1","deactivate") + infected_patient:setMood("epidemy2","deactivate") + infected_patient:setMood("epidemy3","deactivate") + infected_patient:setMood("epidemy4","deactivate") + end +end + + +--[[ When the player chooses to begin the cover up over declaring from the + initial fax (@see sendInitialFax) ]] +function Epidemic:startCoverUp() + self.timer = UIWatch(self.world.ui, "epidemic") + self.countdown_intervals = self.timer.open_timer + self.world.ui:addWindow(self.timer) + self.coverup_in_progress = true + --Set the mood icon for all infected patients + for _, infected_patient in ipairs(self.infected_patients) do + infected_patient:updateDynamicInfo() + infected_patient:setMood("epidemy4","activate") + end +end + +--[[ Ends the cover up of the epidemic with the result to be applied +later (@see applyOutcome) ]] +function Epidemic:finishCoverUp() + self.result_determined = true + + self.timer:close() + + -- Turn vaccination mode off + if self.vaccination_mode_active then + self:toggleVaccinationMode() + end + + local still_infected = self:countInfectedPatients() + self:determineFaxAndFines(still_infected) + self:clearAllInfectedPatients() +end + +--[[ Calculates the contents of the fax and the appropriate fines based on the +result of a cover up, results are stored globally to the class to be applied later. + @param still_infected (Integer) the number of patients still infected]] +function Epidemic:determineFaxAndFines(still_infected) + + -- Losing text + local fail_text_1 = _S.fax.epidemic_result.failed.part_1_name:format(self.disease.name) + local fail_text_2 = _S.fax.epidemic_result.failed.part_2 + local close_option = {text = _S.fax.epidemic_result.close_text, choice = "close"} + + -- Losing fine (if epidemic is "lost") + self.coverup_fine = self:calculateInfectedFine(still_infected) + + if still_infected == 0 then + -- Compensation fine (if epidemic is "won") + local level_config = self.world.map.level_config + local compensation_low_value = level_config.gbv.EpidemicCompLo or 1000 + local compensation_high_value = level_config.gbv.EpidemicCompHi or 5000 + self.compensation = math.random(compensation_low_value,compensation_high_value) + + self.cover_up_result_fax = { + {text = _S.fax.epidemic_result.succeeded.part_1_name:format(self.disease.name)}, + {text = _S.fax.epidemic_result.succeeded.part_2}, + {text = _S.fax.epidemic_result.compensation_amount:format(self.compensation)}, + choices = {close_option} + } + elseif still_infected < self.reputation_loss_minimum and still_infected < self.evacuation_minimum then + self.cover_up_result_fax = { + {text = fail_text_1}, + {text = fail_text_2}, + {text = _S.fax.epidemic_result.fine_amount:format(self.coverup_fine)}, + choices = {close_option} + } + elseif still_infected >= self.reputation_loss_minimum and still_infected < self.evacuation_minimum then + self.cover_up_result_fax = { + {text = fail_text_1}, + {text = fail_text_2}, + {text = _S.fax.epidemic_result.rep_loss_fine_amount:format(self.coverup_fine)}, + choices = {close_option} + } + else + self.will_be_evacuated = true + self.cover_up_result_fax = { + {text = fail_text_1}, + {text = fail_text_2}, + {text = _S.fax.epidemic_result.hospital_evacuated}, + choices = {close_option} + } + end +end + +--[[ Apply the compensation or fines where appropriate to the player as +determined when the cover up was completed (@see finishCoverUp) ]] +function Epidemic:applyOutcome() + -- If there is no compensation to apply the epidemic has been failed + if self.compensation == 0 then + if self.will_be_evacuated then + self.reputation_hit = math.round(self.hospital.reputation * (1/3)) + self:evacuateHospital() + else + self.reputation_hit = getBaseReputationFromFine(self.coverup_fine) + end + -- Apply fine and reputation hit + self.hospital:spendMoney(self.coverup_fine,_S.transactions.epidemy_coverup_fine) + self.hospital.reputation = self.hospital.reputation - self.reputation_hit + else + self.hospital:receiveMoney(self.compensation, _S.transactions.compensation) + end + -- Finally send the fax confirming the outcome + self:sendResultFax() + --Remove epidemic from hospital so another epidemic may be assigned + self.hospital.epidemic = nil +end + +--[[ For compatibility. Mark all the current patients who are in the hospital +--but not in the reception queues as being "passed reception" used to decide +--who is evacuated @see evacuateHospital. For new patients they are marked +--as they leave the reception desks.]] +function Epidemic:markPatientsAsPassedReception() + local queuing_patients = {} + for _, desk in ipairs(self.hospital:findReceptionDesks()) do + for _, patient in ipairs(desk.queue) do + -- Use patient as map key to speed up lookup + queuing_patients[patient] = true + end + end + + for _, patient in ipairs(self.hospital.patients) do + -- Patient is not queuing for reception + local px, py = patient.tile_x, patient.tile_y + if px and py and self.hospital:isInHospital(px,py) and queuing_patients[patient] == nil then + patient.has_passed_reception = true + end + end +end + +--[[ Forces evacuation of the hospital - it makes ALL patients leave and storm out. ]] +function Epidemic:evacuateHospital() + for _, patient in ipairs(self.hospital.patients) do + local patient_room = patient:getRoom() + if patient_room then + patient_room:makeHumanoidDressIfNecessaryAndThenLeave(patient) + end + if patient.has_passed_reception then + patient:clearDynamicInfo() + patient:setDynamicInfo('text', {_S.dynamic_info.patient.actions.epidemic_sent_home}) + patient:setMood("exit","activate") + local spawn_point = self.world.spawn_points[math.random(1, #self.world.spawn_points)] + patient:setNextAction(SpawnAction("despawn", spawn_point):setMustHappen(true)) + end + end +end + +--[[ Send the results of the cover up to the player - will be a +success/compensation or fail/fines + reputation hit]] +function Epidemic:sendResultFax() + self.world.ui.bottom_panel:queueMessage("report", self.cover_up_result_fax, nil, 24*20, 1) + self:announceEndOfEpidemic() +end + +--[[ Spawns the inspector who will walk to the reception desk. ]] +function Epidemic:spawnInspector() + self.world.ui.adviser:say(_A.information.epidemic_health_inspector) + local inspector = self.world:newEntity("Inspector", 2) + self.inspector = inspector + inspector:setType("Inspector") + + local spawn_point = self.world.spawn_points[math.random(1, #self.world.spawn_points)] + inspector:setNextAction(SpawnAction("spawn", spawn_point)) + inspector:setHospital(self.hospital) + inspector:queueAction(SeekReceptionAction()) +end + +--[[ Is the patient "still" either idle queuing or sitting on a bench + Typically this is used to determine if a patient can be vaccinated + @param patient (Patient) the patient we wish to determine if they are static.]] +local function is_static(patient) + local action = patient:getCurrentAction() + return action.name == "queue" or action.name == "idle" or + (action.name == "use_object" and action.object.object_type.id == "bench") +end + +--[[ During a cover up every patient marked for vaccination (clicked) + creates a call to be vaccinated by a nurse - patients must also be static + (seated or standing queuing) ]] +function Epidemic:markedPatientsCallForVaccination() + for _, infected_patient in ipairs(self.infected_patients) do + if infected_patient.marked_for_vaccination and + not infected_patient.reserved_for and is_static(infected_patient) then + self.world.dispatcher:callNurseForVaccination(infected_patient) + end + end +end + +--[[ In response to a vaccination call by the vaccination candidate + (@see makeVaccinationCandidateCallForNurse) perform the vaccination + actions or deal with call if unable to vaccinate. + @param patient (Patient) the patient who make the original call + @param nurse (Nurse) the nurse attempting to vaccinate the patient]] +function Epidemic:createVaccinationActions(patient,nurse) + patient.reserved_for = nurse + -- Check square is reachable first + local x,y = self:getBestVaccinationTile(nurse,patient) + -- If unreachable patient keep the call open for now + if not x or not y then + nurse:setCallCompleted() + patient.reserved_for = nil + nurse:setNextAction(MeanderAction()) + patient:removeVaccinationCandidateStatus() + else + -- Give selected patient the cursor with the arrow once they are next + -- in line for vaccination i.e. call assigned + patient:giveVaccinationCandidateStatus() + local level_config = self.world.map.level_config + local fee = level_config.gbv.VacCost or 50 + nurse:setNextAction(WalkAction(x, y):setMustHappen(true):enableWalkingToVaccinate()) + nurse:queueAction(VaccinateAction(patient, fee)) + end +end + + +--[[Find the best tile to stand on to vaccinate a patient + @param nurse (Nurse) the nurse performing the vaccination + @param patient (Patient) the patient to be vaccinated + @return best_x,best_y (Integer,nil) the best tiles to vaccinate from.]] +function Epidemic:getBestVaccinationTile(nurse, patient) + local px, py = patient.tile_x, patient.tile_y + -- If the patient is using a bench the best tile to use is + -- directly in front of them + local action = patient:getCurrentAction() + if action.name == "use_object" then + local object_in_use = action.object + if object_in_use.object_type.id == "bench" then + local direction = object_in_use.direction + if direction == "north" then + return px, py - 1 + + elseif direction == "south" then + return px, py + 1 + + elseif direction == "east" then + return px + 1, py + + elseif direction == "west" then + return px - 1, py + end + end + end + + -- General usage tile finder, used in the other cases + -- when the patient isn't sitting on a bench + + -- Location of the nurse + local nx, ny = nurse.tile_x, nurse.tile_y + + local best_x, best_y = nil + local shortest_distance = nil + local free_tiles = self.world.entity_map:getAdjacentFreeTiles(px, py) + + for _, coord in ipairs(free_tiles) do + local x = coord['x'] + local y = coord['y'] + + local distance = self.world:getPathDistance(nx, ny, x, y) + -- If the tile is reachable for the nurse + if distance then + -- If the tile is closer then it's a better choice + if not shortest_distance or distance < shortest_distance then + shortest_distance = distance + best_x, best_y = x, y + end + end + end + return best_x, best_y +end + +--[[When the nurse is interrupted unreserve the patient and unassign the call. + @param nurse (Nurse) the nurse whose vaccination actions we are interrupting]] +function Epidemic:interruptVaccinationActions(nurse) + assert(nurse.humanoid_class == "Nurse") + local call = nurse.on_call + if call then + local patient = call.object + if patient and patient.vaccination_candidate and not patient.vaccinated then + patient:removeVaccinationCandidateStatus() + end + call.object.reserved_for = nil + call.assigned = nil + nurse.on_call = nil + end +end + +--[[ Make the advisor show appropriate messages under certain + conditions of the epidemic.]] +function Epidemic:showAppropriateAdviceMessages() + if self.countdown_intervals then + if not self.has_said_hurry_up and self:countInfectedPatients() > 0 and + -- If only 1/4 of the countdown_intervals remaining on the timer + self.timer.open_timer == math.floor(self.countdown_intervals * 1 / 4) then + self.world.ui.adviser:say(_A.epidemic.hurry_up) + self.has_said_hurry_up = true + + -- Wait until at least 1/4 of the countdown_intervals has expired before giving + -- this warning so it doesn't happen straight away + elseif self.timer.open_timer <= math.floor(self.countdown_intervals * 3 / 4) and + not self.has_said_serious and self:countInfectedPatients() > 10 then + self.world.ui.adviser:say(_A.epidemic.serious_warning) + self.has_said_serious = true + end + end +end + +--[[ Are no infected patients, cured or still infected in the hospital? +@returns true if so, false otherwise. (boolean) ]] +function Epidemic:hasNoInfectedPatients() + return #self.infected_patients == 0 +end + +function Epidemic:tryAnnounceInspector() + local inspector = self.inspector + if inspector and not inspector.has_been_announced and + self.hospital:isInHospital(inspector.tile_x, inspector.tile_y) then + inspector:announce() + inspector.has_been_announced = true + end +end + +function Epidemic:afterLoad(old, new) + if old < 106 then + self.level_config = nil + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/filesystem.lua corsix-th-0.62/CorsixTH/Lua/filesystem.lua --- corsix-th-0.30/CorsixTH/Lua/filesystem.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/filesystem.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,14 +18,17 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local LFS = require "lfs" local pathsep = package.config:sub(1, 1) -local part_pattern = "[^".. pathsep .."]+" -local ISO_FS = require "ISO_FS" +local part_pattern = "[^" .. pathsep .. "]+" + +local ISO_FS = require("ISO_FS") --! Layer for abstracting away differences in file systems class "FileSystem" +---@type FileSystem +local FileSystem = _G["FileSystem"] + function FileSystem:FileSystem() end @@ -64,7 +67,7 @@ physical_path = physical_path:sub(1, -2) end if lfs.attributes(physical_path, "mode") ~= "directory" then - return nil, "Specified path ('".. physical_path .. "') is not a directory" + return nil, "Specified path ('" .. physical_path .. "') is not a directory" end self.physical_path = physical_path self:_enumerate() diff -Nru corsix-th-0.30/CorsixTH/Lua/game_ui.lua corsix-th-0.62/CorsixTH/Lua/game_ui.lua --- corsix-th-0.30/CorsixTH/Lua/game_ui.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/game_ui.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,49 +18,64 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -dofile "ui" +corsixth.require("ui") --! Variant of UI for running games class "GameUI" (UI) -local TH = require "TH" -local WM = require "sdl".wm -local SDL = require "sdl" -local lfs = require "lfs" -local pathsep = package.config:sub(1, 1) +---@type GameUI +local GameUI = _G["GameUI"] -function GameUI:GameUI(app, local_hospital) +local TH = require("TH") + +-- The maximum distance to shake the screen from the origin during an +-- earthquake with full intensity. +local shake_screen_max_movement = 50 --pixels + +-- 0.002 is about 5 pixels on a 1920 pixel display +local multigesture_pinch_sensitivity_factor = 0.002 +-- combined with the above, multiplying by 100 means minimum current_momentum.z for any detected pinch +-- will result in a call to adjustZoom in the onTick method +local multigesture_pinch_amplification_factor = 100 + +--! Game UI constructor. +--!param app (Application) Application object. +--!param local_hospital Hospital to display +--!param map_editor (bool) Whether the map is editable. +function GameUI:GameUI(app, local_hospital, map_editor) self:UI(app) self.hospital = local_hospital self.tutorial = { chapter = 0, phase = 0 } - - if _MAP_EDITOR then - self:addWindow(UIMapEditor(self)) + if map_editor then + self.map_editor = UIMapEditor(self) + self:addWindow(self.map_editor) else self.adviser = UIAdviser(self) self.bottom_panel = UIBottomPanel(self) - self.menu_bar = UIMenuBar(self) self.bottom_panel:addWindow(self.adviser) self:addWindow(self.bottom_panel) - self:addWindow(self.menu_bar) end + -- UI widgets + self.menu_bar = UIMenuBar(self, self.map_editor) + self:addWindow(self.menu_bar) + local scr_w = app.config.width local scr_h = app.config.height self.visible_diamond = self:makeVisibleDiamond(scr_w, scr_h) if self.visible_diamond.w <= 0 or self.visible_diamond.h <= 0 then -- For a standard 128x128 map, screen size would have to be in the -- region of 3276x2457 in order to be too large. - if not _MAP_EDITOR then - error "Screen size too large for the map" + if not self.map_editor then + error("Screen size too large for the map") end end self.screen_offset_x, self.screen_offset_y = app.map:WorldToScreen( app.map.th:getCameraTile(local_hospital:getPlayerIndex())) self.zoom_factor = 1 self:scrollMap(-scr_w / 2, 16 - scr_h / 2) - self.limit_to_visible_diamond = not _MAP_EDITOR + self.limit_to_visible_diamond = not self.map_editor self.transparent_walls = false self.do_world_hit_test = true @@ -69,13 +84,21 @@ self.momentum = app.config.scrolling_momentum self.current_momentum = {x = 0.0, y = 0.0, z = 0.0} + self.multigesturemove = {x = 0.0, y = 0.0} + + self.speed_up_key_pressed = false + + -- The currently specified intensity value for earthquakes. To abstract + -- the effect from the implementation this value is a number between 0 + -- and 1. + self.shake_screen_intensity = 0 end function GameUI:setupGlobalKeyHandlers() UI.setupGlobalKeyHandlers(self) - self:addKeyHandler("esc", self, self.setEditRoom, false) - self:addKeyHandler("esc", self, self.showMenuBar) + self:addKeyHandler("escape", self, self.setEditRoom, false) + self:addKeyHandler("escape", self, self.showMenuBar) self:addKeyHandler("z", self, self.keySpeedUp) self:addKeyHandler("x", self, self.keyTransparent) self:addKeyHandler({"shift", "a"}, self, self.toggleAdviser) @@ -97,7 +120,7 @@ -- The visible diamond is the region which the top-left corner of the screen -- is limited to, and ensures that the map always covers all of the screen. - -- Its verticies are at (x + w, y), (x - w, y), (x, y + h), (x, y - h). + -- Its vertices are at (x + w, y), (x - w, y), (x, y + h), (x, y - h). return { x = - scr_w / 2, y = 16 * map_h - scr_h / 2, @@ -106,44 +129,71 @@ } end +--! Calculate the minimum valid zoom value +--! +--! Zooming out too much would cause negative width/height to be returned from +--! makeVisibleDiamond. This function calculates the minimum zoom_factor that +--! would be allowed. +function GameUI:calculateMinimumZoom() + local scr_w = self.app.config.width + local scr_h = self.app.config.height + local map_h = self.app.map.height + + -- Minimum width: 0 = 32 * map_h - (scr_h/factor) - (scr_w/factor) / 2, + -- Minimum height: 0 = 16 * map_h - (scr_h/factor) / 2 - (scr_w/factor) / 4 + -- Both rearrange to: + local factor = (scr_w + 2 * scr_h) / (64 * map_h) + + -- Due to precision issues a tolerance is needed otherwise setZoom might fail + factor = factor + 0.001 + + return factor +end + function GameUI:setZoom(factor) if factor <= 0 then - return + return false end - local old_factor = self.zoom_factor if not factor or math.abs(factor - 1) < 0.001 then factor = 1 end + local scr_w = self.app.config.width local scr_h = self.app.config.height + local new_diamond = self:makeVisibleDiamond(scr_w / factor, scr_h / factor) + if new_diamond.w < 0 or new_diamond.h < 0 then + return false + end + + self.visible_diamond = new_diamond local refx, refy = self.cursor_x or scr_w / 2, self.cursor_y or scr_h / 2 local cx, cy = self:ScreenToWorld(refx, refy) self.zoom_factor = factor - self.visible_diamond = self:makeVisibleDiamond(scr_w / factor, scr_h / factor) - if self.visible_diamond.w < 0 or self.visible_diamond.h < 0 then - self:setZoom(old_factor) - return false - else - cx, cy = self.app.map:WorldToScreen(cx, cy) - self:scrollMap(cx - self.screen_offset_x - refx / factor, - cy - self.screen_offset_y - refy / factor) - return true - end + + cx, cy = self.app.map:WorldToScreen(cx, cy) + cx = cx - self.screen_offset_x - refx / factor + cy = cy - self.screen_offset_y - refy / factor + self:scrollMap(cx, cy) + return true end function GameUI:draw(canvas) local app = self.app local config = app.config - if _MAP_EDITOR or not self.in_visible_diamond then + if self.map_editor or not self.in_visible_diamond then canvas:fillBlack() end local zoom = self.zoom_factor + local dx = self.screen_offset_x + + math.floor((0.5 - math.random()) * self.shake_screen_intensity * shake_screen_max_movement * 2) + local dy = self.screen_offset_y + + math.floor((0.5 - math.random()) * self.shake_screen_intensity * shake_screen_max_movement * 2) if canvas:scale(zoom) then - app.map:draw(canvas, self.screen_offset_x, self.screen_offset_y, config.width / zoom, config.height / zoom, 0, 0) + app.map:draw(canvas, dx, dy, math.floor(config.width / zoom), math.floor(config.height / zoom), 0, 0) canvas:scale(1) else self:setZoom(1) - app.map:draw(canvas, self.screen_offset_x, self.screen_offset_y, config.width, config.height, 0, 0) + app.map:draw(canvas, dx, dy, config.width, config.height, 0, 0) end Window.draw(self, canvas, 0, 0) -- NB: not calling UI.draw on purpose self:drawTooltip(canvas) @@ -153,6 +203,11 @@ end function GameUI:onChangeResolution() + -- Calculate and enforce minimum zoom + local minimum_zoom = self:calculateMinimumZoom() + if self.zoom_factor < minimum_zoom then + self:setZoom(minimum_zoom) + end -- Recalculate scrolling bounds local scr_w = self.app.config.width local scr_h = self.app.config.height @@ -191,8 +246,6 @@ self.key_remaps = ui.key_remaps self.key_to_button_remaps = ui.key_to_button_remaps - self.key_codes = ui.key_codes - self.key_code_to_rawchar = ui.key_code_to_rawchar end local scroll_keys = { @@ -200,6 +253,10 @@ right = {x = 10, y = 0}, down = {x = 0, y = 10}, left = {x = -10, y = 0}, + ["keypad 8"] = {x = 0, y = -10}, + ["keypad 6"] = {x = 10, y = 0}, + ["keypad 2"] = {x = 0, y = 10}, + ["keypad 4"] = {x = -10, y = 0}, } function GameUI:updateKeyScroll() @@ -220,46 +277,45 @@ end function GameUI:keySpeedUp() - if self.key_codes[122] then - self.app.world:speedUp() - end + self.speed_up_key_pressed = true + self.app.world:speedUp() end function GameUI:keyTransparent() - if self.key_codes[120] then - self:makeTransparentWalls() - end + self:setWallsTransparent(true) end -function GameUI:onKeyDown(code, rawchar) - if UI.onKeyDown(self, code, rawchar) then +function GameUI:onKeyDown(rawchar, modifiers, is_repeat) + if UI.onKeyDown(self, rawchar, modifiers, is_repeat) then -- Key has been handled already return true end - rawchar = self.key_code_to_rawchar[code] -- UI may have translated rawchar - local key = self:_translateKeyCode(code, rawchar) + local key = rawchar:lower() if scroll_keys[key] then self:updateKeyScroll() return end end -function GameUI:onKeyUp(code) - local rawchar = self.key_code_to_rawchar[code] or "" - if UI.onKeyUp(self, code) then +function GameUI:onKeyUp(rawchar) + if UI.onKeyUp(self, rawchar) then return true end - local key = self:_translateKeyCode(code, rawchar) + + local key = rawchar:lower() if scroll_keys[key] then self:updateKeyScroll() return end - if self.app.world:isCurrentSpeed("Speed Up") then + + -- Guess that the "Speed Up" key was released because the + -- code parameter can't provide UTF-8 key codes: + self.speed_up_key_pressed = false + if self.app.world:isCurrentSpeed("Speed Up") then self.app.world:previousSpeed() end - if self.transparent_walls then - self:removeTransparentWalls() - end + + self:setWallsTransparent(false) end function GameUI:makeDebugFax() @@ -298,16 +354,16 @@ function GameUI:onCursorWorldPositionChange() local zoom = self.zoom_factor - local x = self.screen_offset_x + self.cursor_x / zoom - local y = self.screen_offset_y + self.cursor_y / zoom + local x = math.floor(self.screen_offset_x + self.cursor_x / zoom) + local y = math.floor(self.screen_offset_y + self.cursor_y / zoom) local entity = nil if self.do_world_hit_test and not self:hitTest(self.cursor_x, self.cursor_y) then entity = self.app.map.th:hitTestObjects(x, y) if self.do_world_hit_test ~= true then -- limit to non-door objects in room local room = self.do_world_hit_test - entity = entity and class.is(entity, Object) and entity:getRoom() == room - and entity ~= room.door and entity + entity = entity and class.is(entity, Object) and + entity:getRoom() == room and entity ~= room.door and entity end end if entity ~= self.cursor_entity then @@ -321,12 +377,26 @@ self.debug_cursor_entity = entity end + local epidemic = self.hospital.epidemic + local infected_cursor = TheApp.gfx:loadMainCursor("epidemic") + local epidemic_cursor = TheApp.gfx:loadMainCursor("epidemic_hover") + self.cursor_entity = entity if self.cursor ~= self.edit_room_cursor and self.cursor ~= self.waiting_cursor then local cursor = self.default_cursor if self.app.world.user_actions_allowed then - cursor = entity and entity.hover_cursor or - (self.down_count ~= 0 and self.down_cursor or self.default_cursor) + --- If the patient is infected show the infected cursor + if epidemic and epidemic.coverup_in_progress and + entity and entity.infected and not epidemic.timer.closed then + cursor = infected_cursor + -- In vaccination mode display epidemic hover cursor for all entities + elseif epidemic and epidemic.vaccination_mode_active then + cursor = epidemic_cursor + -- Otherwise just show the normal cursor and hover if appropriate + else + cursor = entity and entity.hover_cursor or + (self.down_count ~= 0 and self.down_cursor or self.default_cursor) + end end self:setCursor(cursor) end @@ -367,7 +437,7 @@ -- Any hoverable mood should be displayed on the new entity if class.is(entity, Humanoid) then - for key, value in pairs(entity.active_moods) do + for _, value in pairs(entity.active_moods) do if value.on_hover then entity:setMoodInfo(value) break @@ -429,28 +499,29 @@ -- In windowed mode, a reasonable size is needed, though not too large. scroll_region_size = 8 end - if not self.app.config.prevent_edge_scrolling and (x < scroll_region_size - or y < scroll_region_size or x >= self.app.config.width - scroll_region_size - or y >= self.app.config.height - scroll_region_size) then - local dx = 0 - local dy = 0 + if not self.app.config.prevent_edge_scrolling and + (x < scroll_region_size or y < scroll_region_size or + x >= self.app.config.width - scroll_region_size or + y >= self.app.config.height - scroll_region_size) then + local scroll_dx = 0 + local scroll_dy = 0 local scroll_power = 7 if x < scroll_region_size then - dx = -scroll_power + scroll_dx = -scroll_power elseif x >= self.app.config.width - scroll_region_size then - dx = scroll_power + scroll_dx = scroll_power end if y < scroll_region_size then - dy = -scroll_power + scroll_dy = -scroll_power elseif y >= self.app.config.height - scroll_region_size then - dy = scroll_power + scroll_dy = scroll_power end if not self.tick_scroll_amount_mouse then - self.tick_scroll_amount_mouse = {x = dx, y = dy} + self.tick_scroll_amount_mouse = {x = scroll_dx, y = scroll_dy} else - self.tick_scroll_amount_mouse.x = dx - self.tick_scroll_amount_mouse.y = dy + self.tick_scroll_amount_mouse.x = scroll_dx + self.tick_scroll_amount_mouse.y = scroll_dy end else self.tick_scroll_amount_mouse = false @@ -486,25 +557,13 @@ return UI.onMouseUp(self, code, x, y) end - if code == 4 or code == 5 then - -- Mouse wheel - local window = self:getWindow(UIFullscreen) - if not window or not window:hitTest(x - window.x, y - window.y) then - - -- Apply momentum to the zoom - if math.abs(self.current_momentum.z) < 12 then - self.current_momentum.z = self.current_momentum.z + (4.5 - code)*2 - end - end - end - local button = self.button_codes[code] - if button == "right" and not _MAP_EDITOR and highlight_x then + if button == "right" and not self.map_editor and highlight_x then local window = self:getWindow(UIPatient) local patient = (window and window.patient.is_debug and window.patient) or self.hospital:getDebugPatient() if patient then patient:walkTo(highlight_x, highlight_y) - patient:queueAction{name = "idle"} + patient:queueAction(IdleAction()) end end @@ -528,18 +587,93 @@ end end + -- During vaccination mode you can only interact with infected patients + local epidemic = self.hospital.epidemic + if epidemic and epidemic.vaccination_mode_active then + if button == "left" then + if self.cursor_entity then + -- Allow click behaviour for infected patients + if self.cursor_entity.infected then + self.cursor_entity:onClick(self,button) + end + end + elseif button == "right" then + --Right click turns vaccination mode off + local watch = TheApp.ui:getWindow(UIWatch) + watch:toggleVaccinationMode() + end + end + return UI.onMouseUp(self, code, x, y) end +--! Process SDL_MULTIGESTURE events for zoom and map move functionality +--!param numfingers (integer) number of touch points, received from the SDL event +--! This is still more info about param x. +--!param dTheta (float) rotation in radians of the gesture from the SDL event +--!param dDist (float) magnitude of pinch from the SDL event +--!param x (float) normalised x value of the gesture +--!param y (float) normalised y value of the gesture +--!return (boolean) event processed indicator +function GameUI:onMultiGesture(numfingers, dTheta, dDist, x, y) + -- only deal with 2 finger events for now + if numfingers == 2 then + -- calculate magnitude of pinch + local mag = math.abs(dDist) + if mag > multigesture_pinch_sensitivity_factor then + -- pinch action - constant needs to be tweaked + self.current_momentum.z = self.current_momentum.z + dDist * multigesture_pinch_amplification_factor + return true + else + -- scroll map + local normx = self.app.config.width * x + local normy = self.app.config.height * y + + if self.multigesturemove.x == 0.0 then + self.multigesturemove.x = normx + self.multigesturemove.y = normy + else + local dx = normx - self.multigesturemove.x + local dy = normy - self.multigesturemove.y + self.current_momentum.x = self.current_momentum.x - dx + self.current_momentum.y = self.current_momentum.y - dy + self.multigesturemove.x = normx + self.multigesturemove.y = normy + end + return true + end + end + return false +end + +function GameUI:onMouseWheel(x, y) + local inside_window = false + if self.windows then + for _, window in ipairs(self.windows) do + if window:hitTest(self.cursor_x - window.x, self.cursor_y - window.y) then + inside_window = true + break + end + end + end + if not inside_window then + -- Apply momentum to the zoom + if math.abs(self.current_momentum.z) < 12 then + self.current_momentum.z = self.current_momentum.z + y + end + end + return UI.onMouseWheel(self, x, y) +end + function GameUI:setRandomAnnouncementTarget() -- NB: Every tick is 30ms, so 2000 ticks is 1 minute self.random_announcement_ticks_target = math.random(8000, 12000) end -function GameUI:playAnnouncement(name) +function GameUI:playAnnouncement(name, played_callback, played_callback_delay) self.ticks_since_last_announcement = 0 if self.app.world:getLocalPlayerHospital():hasStaffedDesk() then - UI.playAnnouncement(self, name) + UI.playAnnouncement(self, name, played_callback, played_callback_delay) end end @@ -561,8 +695,10 @@ self.current_momentum.z = self.current_momentum.z * self.momentum self.app.world:adjustZoom(self.current_momentum.z) end + self.multigesturemove.x = 0.0 + self.multigesturemove.y = 0.0 end - do + if not self.app.world:isCurrentSpeed("Pause") then local ticks_since_last_announcement = self.ticks_since_last_announcement if ticks_since_last_announcement >= self.random_announcement_ticks_target then self:playAnnouncement("rand*.wav") @@ -597,10 +733,18 @@ dy = dy + self.tick_scroll_amount.y end - -- Faster scrolling with shift key - local factor = self.app.config.scroll_speed - if self.buttons_down.shift then - mult = mult * factor + -- Adjust scroll speed based on config value: + -- there is a separate config value for whether or not shift is held. + -- the speed is multiplied by 0.5 for consistency between the old and + -- new configuration. In the past scroll_speed applied only to shift + -- and defaulted to 2, where 1 was regular scroll speed. By + -- By multiplying by 0.5, we allow for setting slower than normal + -- scroll speeds, and ensure there is no behaviour change for players + -- who do not modify their config file. + if self.app.key_modifiers.shift then + mult = mult * self.app.config.shift_scroll_speed * 0.5 + else + mult = mult * self.app.config.scroll_speed * 0.5 end self:scrollMap(dx * mult, dy * mult) @@ -653,8 +797,8 @@ vx, vy = -sqrt_5, -2 * sqrt_5 d = (rx * vx + ry * vy) - (p1x * vx) end - -- In the unit vector parallel to the diamond edge, resolve the two verticies and - -- the point, and either move the point to the edge or to one of the two verticies. + -- In the unit vector parallel to the diamond edge, resolve the two vertices and + -- the point, and either move the point to the edge or to one of the two vertices. -- NB: vx, vy, p1x, p1y, p2x, p2y are set such that p1 < p2. local p1 = vx * p1y - vy * p1x local p2 = vx * p2y - vy * p2x @@ -666,6 +810,7 @@ else--if p1 <= pd and pd <= p2 then dx, dy = dx - d * vx, dy - d * vy end + return math.floor(dx), math.floor(dy), true else return dx, dy, false end @@ -684,6 +829,18 @@ self.screen_offset_y = floor(dy + 0.5) end +--! Start shaking the screen, e.g. an earthquake effect +--!param intensity (number) The magnitude of the effect, between 0 for no +-- movement to 1 for significant shaking. +function GameUI:beginShakeScreen(intensity) + self.shake_screen_intensity = intensity +end + +--! Stop the screen from shaking after beginShakeScreen is called. +function GameUI:endShakeScreen() + self.shake_screen_intensity = 0 +end + function GameUI:limitCamera(mode) self.limit_to_visible_diamond = mode self:scrollMap(0, 0) @@ -697,17 +854,10 @@ --! Sets wall transparency to the specified parameter --!param mode (boolean) whether to enable or disable wall transparency function GameUI:setWallsTransparent(mode) - self.transparent_walls = mode - self:applyTransparency() -end - ---! Toggles transparency of walls, i.e. enables if currently disabled, and vice versa -function GameUI:makeTransparentWalls() - self:setWallsTransparent(true) -end - -function GameUI:removeTransparentWalls() - self:setWallsTransparent(not self.transparent_walls) + if mode ~= self.transparent_walls then + self.transparent_walls = mode + self:applyTransparency() + end end function UI:toggleAdviser() @@ -717,7 +867,7 @@ function UI:togglePlaySounds() self.app.config.play_sounds = not self.app.config.play_sounds - + self.app.audio:playSoundEffects(self.app.config.play_sounds) self.app:saveConfig() end @@ -842,15 +992,15 @@ -- The demo uses a single string for the post-tutorial info while -- the real game uses three. local texts = TheApp.using_demo_files and { - _S.introduction_texts["level15"], - _S.introduction_texts["demo"], + {_S.introduction_texts["level15"]}, + {_S.introduction_texts["demo"]}, } or { - _S.introduction_texts["level15"], - _S.introduction_texts["level16"], - _S.introduction_texts["level17"], - _S.introduction_texts["level1"], + {_S.introduction_texts["level15"]}, + {_S.introduction_texts["level16"]}, + {_S.introduction_texts["level17"]}, + {_S.introduction_texts["level1"]}, } - TheApp.ui:addWindow(UIInformation(TheApp.ui, {texts})) + TheApp.ui:addWindow(UIInformation(TheApp.ui, texts)) TheApp.ui:addWindow(UIWatch(TheApp.ui, "initial_opening")) end, }, @@ -988,6 +1138,12 @@ self:addKeyHandler("z", self, self.keySpeedUp) self:addKeyHandler("x", self, self.keyTransparent) end + if old < 115 then + self.shake_screen_intensity = 0 + end + if old < 122 then + self.multigesturemove = {x = 0.0, y = 0.0} + end return UI.afterLoad(self, old, new) end @@ -995,7 +1151,7 @@ local level = self.app.world.map.level_number local text = {_S.information.custom_game} if type(level) == "number" then - text = _S.introduction_texts[TheApp.using_demo_files and "demo" or "level" .. level] + text = {_S.introduction_texts[TheApp.using_demo_files and "demo" or "level" .. level]} elseif self.app.world.map.level_intro then text = {self.app.world.map.level_intro} end diff -Nru corsix-th-0.30/CorsixTH/Lua/graphics.lua corsix-th-0.62/CorsixTH/Lua/graphics.lua --- corsix-th-0.30/CorsixTH/Lua/graphics.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/graphics.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,11 +18,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" -local SDL = require "sdl" +local TH = require("TH") + local pathsep = package.config:sub(1, 1) -local assert, string_char, table_concat, unpack, type, pairs, ipairs - = assert, string.char, table.concat, unpack, type, pairs, ipairs +local ourpath = debug.getinfo(1, "S").source:sub(2, -17) --! Layer for loading (and subsequently caching) graphical resources. --! The Graphics class handles loading and caching of graphics resources. @@ -30,6 +29,9 @@ -- the other Lua code. class "Graphics" +---@type Graphics +local Graphics = _G["Graphics"] + local cursors_name = { default = 1, clicked = 2, @@ -73,6 +75,8 @@ language_fonts = {}, cursors = setmetatable({}, {__mode = "k"}), } + + self.custom_graphics = {} -- The load info table records how objects were loaded, and is used to -- persist objects as instructions on how to load them. self.load_info = setmetatable({}, {__mode = "k"}) @@ -83,11 +87,34 @@ -- be done with a different graphics engine, or might only need to grab an -- object from the cache. self.reload_functions = setmetatable({}, {__mode = "k"}) - -- Cursors need to be reloaded after sprite sheets, as they are created - -- from a sprite sheet. - self.reload_functions_cursors = setmetatable({}, {__mode = "k"}) + -- Cursors and fonts need to be reloaded after sprite sheets, as they are + -- created from sprite sheets. + self.reload_functions_last = setmetatable({}, {__mode = "k"}) self:loadFontFile() + + local graphics_folder = nil + if self.app.config.use_new_graphics then + -- Check if the config specifies a place to look for graphics in. + -- Otherwise check in the default "Graphics" folder. + graphics_folder = self.app.config.new_graphics_folder or ourpath .. "Graphics" + if graphics_folder:sub(-1) ~= pathsep then + graphics_folder = graphics_folder .. pathsep + end + + local graphics_config_file = graphics_folder .. "file_mapping.txt" + local result, err = loadfile_envcall(graphics_config_file) + + if not result then + print("Warning: Failed to read custom graphics configuration:\n" .. err) + else + result(self.custom_graphics) + if not self.custom_graphics.file_mapping then + print("Error: An invalid custom graphics mapping file was found") + end + end + end + self.custom_graphics_folder = graphics_folder end --! Tries to load the font file given in the config file as unicode_font. @@ -142,10 +169,10 @@ end, } else - local function reloader(res) + local function cursor_reloader(res) assert(res:load(sheet, index, hot_x, hot_y)) end - self.reload_functions_cursors[cursor] = reloader + self.reload_functions_last[cursor] = cursor_reloader end sheet_cache[index] = cursor self.load_info[cursor] = {self.loadCursor, self, sheet, index, hot_x, hot_y} @@ -153,7 +180,7 @@ return cursor end -function Graphics:makeGreyscaleGhost(pal) +local function makeGreyscaleGhost(pal) local remap = {} -- Convert pal from a string to an array of palette entries local entries = {} @@ -165,22 +192,24 @@ -- entry in the palette to that grey. for i = 0, #entries do local entry = entries[i] - -- NB: g is for grey, not green - local g = entry[1] * 0.299 + entry[2] * 0.587 + entry[3] * 0.114 - local g_index = 0 - local g_diff = 100000 -- greater than 3*63^2 (TH uses 6 bit colour channels) + local grey = entry[1] * 0.299 + entry[2] * 0.587 + entry[3] * 0.114 + local grey_index = 0 + local grey_diff = 100000 -- greater than 3*63^2 (TH uses 6 bit colour channels) for j = 0, #entries do - local entry = entries[j] - local diff = (entry[1] - g)^2 + (entry[2] - g)^2 + (entry[3] - g)^2 - if diff < g_diff then - g_diff = diff - g_index = j + local replace_entry = entries[j] + local diff_r = replace_entry[1] - grey + local diff_g = replace_entry[2] - grey + local diff_b = replace_entry[3] - grey + local diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b + if diff < grey_diff then + grey_diff = diff + grey_index = j end end - remap[i] = string_char(g_index) + remap[i] = string.char(grey_index) end -- Convert remap from an array to a string - return table_concat(remap, "", 0, 255) + return table.concat(remap, "", 0, 255) end function Graphics:loadPalette(dir, name) @@ -193,7 +222,7 @@ local data = self.app:readDataFile(dir or "Data", name) local palette = TH.palette() palette:load(data) - self.cache.palette_greyscale_ghost[name] = self:makeGreyscaleGhost(data) + self.cache.palette_greyscale_ghost[name] = makeGreyscaleGhost(data) self.cache.palette[name] = palette self.load_info[palette] = {self.loadPalette, self, dir, name} return palette, self.cache.palette_greyscale_ghost[name] @@ -229,13 +258,14 @@ end bitmap:setPalette(palette) assert(bitmap:load(data, width, self.target)) - local function reloader(bitmap) - bitmap:setPalette(palette) - local data = self.app:readDataFile(dir, name .. ".dat") - data = data:sub(1, width * height) - assert(bitmap:load(data, width, self.target)) + + local function bitmap_reloader(bm) + bm:setPalette(palette) + local bitmap_data = self.app:readDataFile(dir, name .. ".dat") + bitmap_data = bitmap_data:sub(1, width * height) + assert(bm:load(bitmap_data, width, self.target)) end - self.reload_functions[bitmap] = reloader + self.reload_functions[bitmap] = bitmap_reloader self.cache.raw[name] = bitmap self.load_info[bitmap] = {self.loadRaw, self, name, width, height, dir, paldir, pal} @@ -284,6 +314,7 @@ end end +--! Font proxy meta table wrapping the C++ class. local font_proxy_mt = { __index = { sizeOf = function(self, ...) @@ -307,16 +338,33 @@ self.load_info = {} -- Any newly made objects are temporary, and shouldn't -- remember reload information (also avoids insertions -- into a table being iterated over). - for object, load_info in pairs(load_info) do + for object, info in pairs(load_info) do if object._proxy then - local fn = load_info[1] - local new_object = fn(unpack(load_info, 2)) + local fn = info[1] + local new_object = fn(unpack(info, 2)) object._proxy = new_object._proxy end end self.load_info = load_info end +--! Font reload function. +--!param font The font to (force) reloading. +local function font_reloader(font) + font:clearCache() +end + +--! Utility function to return preferred font for main menu ui +function Graphics:loadMenuFont() + local font + if self.language_font then + font = self:loadFont("QData", "Font01V") + else + font = self:loadBuiltinFont() + end + return font +end + function Graphics:loadLanguageFont(name, sprite_table, ...) local font if name == nil then @@ -329,6 +377,8 @@ -- TODO: Choose face based on "name" rather than always using same face. font:setFace(self.ttf_font_data) font:setSheet(sprite_table) + self.reload_functions_last[font] = font_reloader + if not cache then cache = {} self.cache.language_fonts[name] = cache @@ -356,14 +406,13 @@ if n_pass_on_args < #arg then x_sep, y_sep = unpack(arg, n_pass_on_args + 1, #arg) else - x_sep, y_sep = nil + x_sep, y_sep = nil, nil end end - local font local use_bitmap_font = true if not sprite_table:isVisible(46) then -- uppercase M - -- The font doesn't contain an uppercase M, so (in all liklihood) is used + -- The font doesn't contain an uppercase M, so (in all likelihood) is used -- for drawing special symbols rather than text, so the original bitmap -- font should be used. elseif self.language_font then @@ -390,6 +439,18 @@ return self.cache.anims[prefix] end + --! Load a custom animation file (if it can be found) + --!param path Path to the file. + local function loadCustomAnims(path) + local file, err = io.open(path, "rb") + if not file then + return nil, err + end + local data = file:read"*a" + file:close() + return data + end + local sheet = self:loadSpriteTable(dir, prefix .. "Spr-0") local anims = TH.anims() anims:setSheet(sheet) @@ -399,7 +460,19 @@ self.app:readDataFile(dir, prefix .. "List-1.ani"), self.app:readDataFile(dir, prefix .. "Ele-1.ani")) then - error("Cannot load animations " .. prefix) + error("Cannot load original animations " .. prefix) + end + + if self.custom_graphics_folder and self.custom_graphics.file_mapping then + for _, fname in pairs(self.custom_graphics.file_mapping) do + anims:setCanvas(self.target) + local data, err = loadCustomAnims(self.custom_graphics_folder .. fname) + if not data then + print("Error when loading custom animations:\n" .. err) + elseif not anims:loadCustom(data) then + print("Warning: custom animations loading failed") + end + end end self.cache.anims[prefix] = anims @@ -413,8 +486,7 @@ return cached end - local sheet = TH.sheet() - local function reloader(sheet) + local function sheet_reloader(sheet) sheet:setPalette(palette or self:loadPalette()) local data_tab, data_dat data_tab = self.app:readDataFile(dir, name .. ".tab") @@ -423,8 +495,9 @@ error("Cannot load sprite sheet " .. dir .. ":" .. name) end end - self.reload_functions[sheet] = reloader - reloader(sheet) + local sheet = TH.sheet() + self.reload_functions[sheet] = sheet_reloader + sheet_reloader(sheet) if name ~= "SPointer" then self.cache.tabled[name] = sheet @@ -435,7 +508,7 @@ function Graphics:updateTarget(target) self.target = target - for _, res_set in ipairs{"reload_functions", "reload_functions_cursors"} do + for _, res_set in ipairs({"reload_functions", "reload_functions_last"}) do for resource, reloader in pairs(self[res_set]) do reloader(resource) end @@ -445,6 +518,9 @@ --! Utility class for setting animation markers and querying animation length. class "AnimationManager" +---@type AnimationManager +local AnimationManager = _G["AnimationManager"] + function AnimationManager:AnimationManager(anims) self.anim_length_cache = {} self.anims = anims @@ -496,15 +572,12 @@ return self:setMarkerRaw(anim, "setFrameMarker", ...) end -function AnimationManager:setSecondaryMarker(anim, ...) - return self:setMarkerRaw(anim, "setFrameSecondaryMarker", ...) -end - local function TableToPixels(t) if t[3] == "px" then return t[1], t[2] else - return Map:WorldToScreen(t[1] + 1, t[2] + 1) + local x, y = Map:WorldToScreen(t[1] + 1, t[2] + 1) + return math.floor(x), math.floor(y) end end @@ -515,29 +588,29 @@ end return end - local type = type(arg1) + local tp_arg1 = type(arg1) local anim_length = self:getAnimLength(anim) local anims = self.anims local frame = anims:getFirstFrame(anim) - if type == "table" then + if tp_arg1 == "table" then if arg2 then -- Linear-interpolation positions local x1, y1 = TableToPixels(arg1) local x2, y2 = TableToPixels(arg2) for i = 0, anim_length - 1 do - local n = i / (anim_length - 1) + local n = math.floor(i / (anim_length - 1)) anims[fn](anims, frame, (x2 - x1) * n + x1, (y2 - y1) * n + y1) frame = anims:getNextFrame(frame) end else -- Static position local x, y = TableToPixels(arg1) - for i = 1, anim_length do + for _ = 1, anim_length do anims[fn](anims, frame, x, y) frame = anims:getNextFrame(frame) end end - elseif type == "number" then + elseif tp_arg1 == "number" then -- Keyframe positions local f1, x1, y1 = 0, 0, 0 local args @@ -552,7 +625,7 @@ for f = 0, anim_length - 1 do if f2 and f == f2 then f1, x1, y1 = f2, x2, y2 - f2, x2, y2 = nil + f2, x2, y2 = nil, nil, nil end if not f2 then f2 = args[args_i] @@ -562,15 +635,15 @@ end end if f2 then - local n = (f - f1) / (f2 - f1) + local n = math.floor((f - f1) / (f2 - f1)) anims[fn](anims, frame, (x2 - x1) * n + x1, (y2 - y1) * n + y1) else anims[fn](anims, frame, x1, y1) end frame = anims:getNextFrame(frame) end - elseif type == "string" then - error "TODO" + elseif tp_arg1 == "string" then + error("TODO") else error("Invalid arguments to setMarker", 2) end diff -Nru corsix-th-0.30/CorsixTH/Lua/hospital.lua corsix-th-0.62/CorsixTH/Lua/hospital.lua --- corsix-th-0.30/CorsixTH/Lua/hospital.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/hospital.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,7 +20,10 @@ class "Hospital" -function Hospital:Hospital(world, name) +---@type Hospital +local Hospital = _G["Hospital"] + +function Hospital:Hospital(world, avail_rooms, name) self.world = world local level_config = world.map.level_config local level = world.map.level_number @@ -34,10 +37,6 @@ balance = level_config.town.StartCash interest_rate = level_config.town.InterestRate / 10000 end - -- Check if awards are available - if level_config.awards_trophies then - self.win_awards = true - end end self.name = name or "PLAYER" -- TODO: Variate initial reputation etc based on level @@ -49,7 +48,6 @@ self.acc_overdraft = 0 self.acc_heating = 0 self.discover_autopsy_risk = 10 - self.initial_grace = true -- The sum of all material values (tiles, rooms, objects). -- Initial value: hospital tile count * tile value + 20000 @@ -61,7 +59,20 @@ self.handymanTasks = {} - + -- Represents the "active" epidemic non-nil if + -- an epidemic is happening currently in the hospital + -- Only one epidemic is ever "active" + self.epidemic = nil + + -- The pool of epidemics which may happen in the future. + -- Epidemic in this table continue in the background its + -- patients infecting each other. Epidemics are chosen from + -- this pool to become the "active" epidemic + self.future_epidemics_pool = {} + -- How many epidemics can exist simultaneously counting current and future + -- epidemics. If epidemic_limit = 1 then only one epidemic can exist at a + -- time either in the futures pool or as a current epidemic. + self.concurrent_epidemic_limit = level_config.gbv.EpidemicConcurrentLimit or 1 -- Initial values self.interest_rate = interest_rate @@ -71,6 +82,17 @@ self.reputation = 500 self.reputation_min = 0 self.reputation_max = 1000 + + -- Price distortion level under which the patients might consider the + -- treatment to be under-priced (TODO: This could depend on difficulty and/or + -- level; e.g. Easy: -0.3 / Difficult: -0.5) + self.under_priced_threshold = -0.4 + + -- Price distortion level over which the patients might consider the + -- treatment to be over-priced (TODO: This could depend on difficulty and/or + -- level; e.g. Easy: 0.4 / Difficult: 0.2) + self.over_priced_threshold = 0.3 + self.radiator_heat = 0.5 self.num_visitors = 0 self.num_deaths = 0 @@ -80,6 +102,7 @@ self.seating_warning = 0 self.num_explosions = 0 self.announce_vip = 0 + self.vip_declined = 0 self.num_vips = 0 -- used to check if it's the user's first vip self.percentage_cured = 0 self.percentage_killed = 0 @@ -110,26 +133,35 @@ -- Other statistics, back to zero each year self.sodas_sold = 0 - self.reputation_above_threshold = self.win_awards and level_config.awards_trophies.Reputation < self.reputation or false + self:checkReputation() -- Reset self.reputation_above_threshold self.num_vips_ty = 0 -- used to count how many VIP visits in the year for an award self.pleased_vips_ty = 0 self.num_cured_ty = 0 self.not_cured_ty = 0 self.num_visitors_ty = 0 - self.ownedPlots = {1} - self.is_in_world = true + self.ownedPlots = {1} -- Plots owned by the hospital + self.ratholes = {} -- List of table {x, y, wall, parcel, optional object} for ratholes in the hospital corridors. + self.is_in_world = true -- Whether the hospital is in this world (AI hospitals are not) self.opened = false self.transactions = {} self.staff = {} - self.reception_desks = {} self.patients = {} self.debug_patients = {} -- right-click-commandable patients for testing self.disease_casebook = {} self.policies = {} self.discovered_diseases = {} -- a list + self.discovered_rooms = {} -- a set; keys are the entries of TheApp.rooms, values are true or nil self.undiscovered_rooms = {} -- NB: These two together must form the list world.available_rooms + for _, avail_room in ipairs(avail_rooms) do + if avail_room.is_discovered then + self.discovered_rooms[avail_room.room] = true + else + self.undiscovered_rooms[avail_room.room] = true + end + end + self.policies["staff_allowed_to_move"] = true self.policies["send_home"] = 0.1 self.policies["guess_cure"] = 0.9 @@ -151,15 +183,15 @@ -- A list of how much each insurance company owes you. The first entry for -- each company is the current month's dept, the second the previous -- month and the third the month before that. - -- All payment that goes through an insurance company a given month is payed two - -- months later. For example diagnoses in April are payed the 1st of July + -- All payment that goes through an insurance company a given month is paid two + -- months later. For example diagnoses in April are paid the 1st of July self.insurance_balance = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}} -- Initialize diseases local diseases = TheApp.diseases - local expertise = self.world.map.level_config.expertise - local gbv = self.world.map.level_config.gbv - for i, disease in ipairs(diseases) do + local expertise = level_config.expertise + local gbv = level_config.gbv + for _, disease in ipairs(diseases) do local disease_available = true local drug_effectiveness = 95 local drug = disease.treatment_rooms and disease.treatment_rooms[1] == "pharmacy" or nil @@ -199,6 +231,14 @@ end end self.research = ResearchDepartment(self) + + -- Initialize build cost for all available rooms. + for _, avail_room in ipairs(avail_rooms) do + self.research.research_progress[avail_room.room] = { + -- In free build mode, everything is freely available. + build_cost = not self.free_build_mode and avail_room.build_cost or 0, + } + end end -- Seasoned players will know these things, but it does not harm to be reminded if there is no staff room or toilet! @@ -330,7 +370,7 @@ } if hosp.balance < 2000 and hosp.balance >= -500 then hosp.world.ui.adviser:say(cashlowmessage[math.random(1, #cashlowmessage)]) - elseif hosp.balance < -2000 and hosp.world.month > 8 then + elseif hosp.balance < -2000 and hosp.world:date():monthOfYear() > 8 then -- ideally this should be linked to the lose criteria for balance hosp.world.ui.adviser:say(_A.warnings.bankruptcy_imminent) end @@ -359,9 +399,6 @@ self.num_visitors = 0 self.player_salary = 10000 self.sodas_sold = 0 - if self.world.map.level_config and self.world.map.level_config.awards_trophies then - self.win_awards = true - end end if old < 20 then -- New variables @@ -429,19 +466,17 @@ local research = ResearchDepartment(self) self.undiscovered_rooms = {} local cure, diagnosis - local config = self.world.map.level_config.objects + local cfg_objects = self.world.map.level_config.objects for _, room in ipairs(self.world.available_rooms) do -- If a room is discovered, make sure its objects are also -- discovered, otherwise add it to the undiscovered list. if self.discovered_rooms[room] then for name, _ in pairs(room.objects_needed) do local object = TheApp.objects[name] - if config[object.thob] and (config[object.thob].AvailableForLevel == 1) - and object.research_category - and not research.research_progress[object].discovered then + if cfg_objects[object.thob] and cfg_objects[object.thob].AvailableForLevel == 1 and + object.research_category and not research.research_progress[object].discovered then local progress = self.research_rooms[room] - if self.research.cure.current == room - or self.research.diagnosis.current == room then + if self.research.cure.current == room or self.research.diagnosis.current == room then progress = progress + self.research.diagnosis.points end research.research_progress[object].discovered = true @@ -453,9 +488,8 @@ if not cure or not diagnosis then for name, _ in pairs(room.objects_needed) do local object = TheApp.objects[name] - if config[object.thob] and (config[object.thob].AvailableForLevel == 1) - and object.research_category - and not research.research_progress[object].discovered then + if cfg_objects[object.thob] and cfg_objects[object.thob].AvailableForLevel == 1 and + object.research_category and not research.research_progress[object].discovered then if object.research_category == "cure" then cure = object elseif object.research_category == "diagnosis" then @@ -513,12 +547,12 @@ } self.world.map.level_config.rooms = rooms end - for i, room in ipairs(TheApp.rooms) do + for _, room in ipairs(TheApp.rooms) do -- Sum up the build cost of the room local build_cost = rooms[room.level_config_id].Cost for name, no in pairs(room.objects_needed) do -- Add cost for this object. - build_cost = build_cost + config[TheApp.objects[name].thob].StartCost * no + build_cost = build_cost + cfg_objects[TheApp.objects[name].thob].StartCost * no end -- Now define the total build cost for the room. room.build_cost = build_cost @@ -530,14 +564,14 @@ end if old < 35 then -- Define build costs for rooms once again. - local config = self.world.map.level_config.objects - local rooms = self.world.map.level_config.rooms - for i, room in ipairs(TheApp.rooms) do + local cfg_objects = self.world.map.level_config.objects + local cfg_rooms = self.world.map.level_config.rooms + for _, room in ipairs(TheApp.rooms) do -- Sum up the build cost of the room - local build_cost = rooms[room.level_config_id].Cost + local build_cost = cfg_rooms[room.level_config_id].Cost for name, no in pairs(room.objects_needed) do -- Add cost for this object. - build_cost = build_cost + config[TheApp.objects[name].thob].StartCost * no + build_cost = build_cost + cfg_objects[TheApp.objects[name].thob].StartCost * no end -- Now define the total build cost for the room. self.research.research_progress[room] = { @@ -567,20 +601,11 @@ end if old < 50 then - self.num_vips_ty = 0 - self.pleased_vips_ty = 0 + self.num_vips_ty = 0 + self.pleased_vips_ty = 0 self.num_cured_ty = 0 self.not_cured_ty = 0 self.num_visitors_ty = 0 - - self.reception_desks = {} - for _, obj_list in pairs(self.world.objects) do - for _, obj in ipairs(obj_list) do - if obj.object_type.id == "reception_desk" then - self.reception_desks[obj] = true - end - end - end end if old < 52 then @@ -606,14 +631,48 @@ if old < 76 then self.msg_counter = 0 end + if old < 84 then + self.vip_declined = 0 + end + + if old < 88 then + self.future_epidemics_pool = {} + self.concurrent_epidemic_limit = self.world.map.level_config.gbv.EpidemicConcurrentLimit or 1 + end + + if old < 107 then + self.reception_desks = nil + end + + if old < 109 then + -- price distortion + self.under_priced_threshold = -0.4 + self.over_priced_threshold = 0.3 + end + + if old < 111 then + self.initial_grace = nil + end + + if old < 114 then + self.ratholes = {} + end + + -- Update other objects in the hospital (added in version 106). + if self.epidemic then self.epidemic.afterLoad(old, new) end + for _, future_epidemic in ipairs(self.future_epidemics_pool) do + future_epidemic.afterLoad(old, new) + end + self.research.afterLoad(old, new) end +--! Update the Hospital.patientcount variable. function Hospital:countPatients() -- I have taken the patient count out of town map, from memory it does not work the other way round. -- i.e. calling it from town map to use here -- so Town map now takes this information from here. (If I am wrong, put it back) self.patientcount = 0 - for _, patient in pairs(self.patients) do + for _, patient in ipairs(self.patients) do -- only count patients that are in the hospital local tx, ty = patient.tile_x, patient.tile_y if tx and ty and self:isInHospital(tx, ty) then @@ -622,126 +681,112 @@ end end +--! Count number of sitting and standing patients in the hospital. +--!return (integer, integer) Number of sitting and number of standing patient in the hospital. +function Hospital:countSittingStanding() + local numberSitting = 0 + local numberStanding = 0 + for _, patient in ipairs(self.patients) do + local pat_action = patient:getCurrentAction() + if pat_action.name == "idle" then + numberStanding = numberStanding + 1 + elseif pat_action.name == "use_object" and pat_action.object.object_type.id == "bench" then + numberSitting = numberSitting + 1 + end + end + return numberSitting, numberStanding +end + + -- A range of checks to help a new player. These are set days apart and will show no more than once a month function Hospital:checkFacilities() - if self.hospital and self:isPlayerHospital() then + local current_date = self.world:date() + local day = current_date:dayOfMonth() + -- All messages are shown after first 4 months if respective conditions are met + if self:isPlayerHospital() and current_date >= Date(1,5) then -- If there is no staff room, remind player of the need to build one - if self.world.day == 3 and not self:hasRoomOfType("staff_room") then - if self.world.month > 4 and not self.staff_room_msg then - self:noStaffroom_msg() - elseif self.world.year > 1 then - self:noStaffroom_msg() - end + if not self.staff_room_msg and day == 3 and not self:hasRoomOfType("staff_room") then + self:noStaffroom_msg() end -- If there is no toilet, remind player of the need to build one - if self.world.day == 8 and not self:hasRoomOfType("toilets") then - if self.world.month > 4 and not self.toilet_msg then - self:noToilet_msg() - elseif self.world.year > 1 then - self:noToilet_msg() - end - end - -- How are we for seating, if there are plenty then praise is due, if not the player is warned - -- We don't want to see praise messages about seating every month, so randomise the chances of it being shown - -- check the seating : standing ratio of waiting patients - -- find all the patients who are currently waiting around - local show_msg = math.random(1, 4) - local numberSitting = 0 - local numberStanding = 0 - for _, patient in ipairs(self.patients) do - if (patient.action_queue[1].name == "idle") then - numberStanding = numberStanding + 1 - elseif (patient.action_queue[1].name == "use_object" - and patient.action_queue[1].object.object_type.id == "bench") then - numberSitting = numberSitting + 1 - end - end - -- If there are patients standing then maybe the seating is in the wrong place! - -- set to 5% (standing:seated) if there are more than 50 patients or 20% if there are less than 50. - -- If this happens for 10 days in any month you are warned about seating unless you have already been warned that month - -- So there are now two checks about having enough seating, if either are called then you won't receive praise. (may need balancing) - if self.patientcount < 50 then - if numberStanding > math.min(numberSitting / 5) then + if not self.toilet_msg and day == 8 and not self:hasRoomOfType("toilets") then + self:noToilet_msg() + end + + if not self.bench_msg then + -- How are we for seating, if there are plenty then praise is due, if not the player is warned + -- check the seating : standing ratio of waiting patients + -- find all the patients who are currently waiting around + local numberSitting, numberStanding = self:countSittingStanding() + + -- If there are patients standing then maybe the seating is in the wrong place! + -- set to 5% (standing:seated) if there are more than 50 patients or 20% if there are less than 50. + -- If this happens for 10 days in any month you are warned about seating unless you have already been warned that month + -- So there are now two checks about having enough seating, if either are called then you won't receive praise. (may need balancing) + local number_standing_threshold = numberSitting / (self.patientcount < 50 and 5 or 20) + if numberStanding > number_standing_threshold then self.seating_warning = self.seating_warning + 1 + if self.seating_warning >= 10 then + self:warningBench() + end end - elseif self.patientcount >= 50 then - if numberStanding > math.min(numberSitting / 20) then - self.seating_warning = self.seating_warning + 1 + + if day == 12 then + -- If there are less patients standing than sitting (1:20) and there are more benches than patients in the hospital + -- you have plenty of seating. If you have not been warned of standing patients in the last month, you could be praised. + + -- We don't want to see praise messages about seating every month, so randomise the chances of it being shown + local show_praise = math.random(1, 4) == 4 + if self.world.object_counts.bench > self.patientcount and show_praise then + self:praiseBench() + -- Are there enough benches for the volume of patients in your hospital? + elseif self.world.object_counts.bench < self.patientcount then + self:warningBench() + end end - if self.seating_warning >= 10 and not self.bench_msg then - self:warningBench() - self.seating_warning = 0 - end - elseif self.world.year == 1 and self.world.month > 4 - and self.world.day == 12 and show_msg == 4 and not self.bench_msg then - -- If there are less patients standing than sitting (1:20) and there are more benches than patients in the hospital - -- you have plenty of seating. If you have not been warned of standing patients in the last month, you could be praised. - if self.world.object_counts.bench > self.patientcount then - self:praiseBench() - -- Are there enough benches for the volume of patients in your hospital? - elseif self.world.object_counts.bench < self.patientcount then - self:warningBench() - end - elseif self.world.year > 1 and self.world.day == 12 - and show_msg == 4 and not self.bench_msg then - if self.world.object_counts.bench > self.patientcount then - self:praiseBench() - elseif self.world.object_counts.bench < self.patientcount then - self:warningBench() - end - end - -- Make players more aware of the need for radiators and how hot or cold the patients and staff are - -- If there are no radiators remind the player from May onwards - if self.world.object_counts.radiator == 0 and self.world.month > 4 and self.world.day == 15 then + end + + -- Make players more aware of the need for radiators + if self.world.object_counts.radiator == 0 then self.world.ui.adviser:say(_A.information.initial_general_advice.place_radiators) end - -- Now to check how warm or cold patients and staff are. So that we are not bombarded with warmth + + -- Now to check how warm or cold patients and staff are. So that we are not bombarded with warmth -- messages if we are told about patients then we won't be told about staff as well in the same month -- And unlike TH we don't want to be told that anyone is too hot or cold when the boiler is broken do we! - if not self.heating_broke then - if not self.warmth_msg and self.world.day == 15 then - local warmth = self:getAveragePatientAttribute("warmth") - if (self.world.year > 1 or self.world.month > 4) and warmth < 0.22 then + if not self.warmth_msg and not self.heating_broke then + if day == 15 then + local warmth = self:getAveragePatientAttribute("warmth", 0.3) -- Default value does not result in a message. + if warmth < 0.22 then self:warningTooCold() - elseif self.world.month > 4 and warmth >= 0.36 then + elseif warmth >= 0.36 then self:warningTooHot() end end -- Are the staff warm enough? - if not self.warmth_msg and self.world.day == 20 then - local warmth = 0 - local no = 0 - for _, staff in ipairs(self.staff) do - warmth = warmth + staff.attributes["warmth"] - no = no + 1 - end - if (self.world.year > 1 or self.world.month > 4) and warmth / no < 0.22 then + if day == 20 then + local avgWarmth = self:getAverageStaffAttribute("warmth", 0.25) -- Default value does not result in a message. + if avgWarmth < 0.22 then self.world.ui.adviser:say(_A.warnings.staff_very_cold) - elseif self.world.month > 4 and warmth / no >= 0.36 then + elseif avgWarmth >= 0.36 then self.world.ui.adviser:say(_A.warnings.staff_too_hot) end end end + -- Are the patients in need of a drink - if not self.thirst_msg and self.world.day == 24 then - local thirst = self:getAveragePatientAttribute("thirst") - if self.world.year == 1 and self.world.month > 4 then - if thirst > 0.8 then - self.world.ui.adviser:say(_A.warnings.patients_very_thirsty) - elseif thirst > 0.6 then - self:warningThirst() - end - end - if self.world.year > 1 then - if thirst > 0.9 then - self.world.ui.adviser:say(_A.warnings.patients_very_thirsty) - elseif thirst > 0.6 then - self:warningThirst() - end + if not self.thirst_msg and day == 24 then + local thirst = self:getAveragePatientAttribute("thirst", 0) -- Default value does not result in a message. + local thirst_threshold = current_date:year() == 1 and 0.8 or 0.9 + if thirst > thirst_threshold then + self.world.ui.adviser:say(_A.warnings.patients_very_thirsty) + elseif thirst > 0.6 then + self:warningThirst() end end + -- reset all the messages on 28th of each month - if self.world.day == 28 then + if day == 28 then self.staff_room_msg = false self.toilet_msg = false self.bench_msg = false @@ -754,7 +799,7 @@ end --! Called each tick, also called 'hours'. Check hours_per_day in ---! world.lua to see how many times per day this is. +--! date.lua to see how many times per day this is. function Hospital:tick() -- add some random background sounds, ringing phones, coughing, belching etc self:countPatients() @@ -774,6 +819,7 @@ end end end + self:manageEpidemics() end function Hospital:purchasePlot(plot_number) @@ -806,9 +852,9 @@ function Hospital:getHeliportPosition() local x, y = self.world.map.th:getHeliportTile(self:getPlayerIndex()) -- NB: Level 2 has a heliport tile set, but no heliport, so we ensure that - -- the specified tile is suitable by checking the adjacent spawn tile for + -- the specified tile is suitable by checking the spawn tile for -- passability. - if y > 1 and self.world.map:getCellFlag(x, y - 1, "passable") then + if y > 0 and self.world.map:getCellFlag(x, y, "passable") then return x, y end end @@ -822,13 +868,13 @@ end end ---[[ Test if a given map tile is part of the hospital. +--[[ Test if a given map tile is part of this hospital. !param x (integer) The 1-based X co-ordinate of the tile to test. !param y (integer) The 1-based Y co-ordinate of the tile to test. ]] function Hospital:isInHospital(x, y) - -- TODO: Fix to work when there are multiple hospitals. - return self.world.map.th:getCellFlags(x, y).hospital + local flags = self.world.map.th:getCellFlags(x, y) + return flags.hospital and flags.owner == self:getPlayerIndex() end function Hospital:coldWarning() local announcements = { @@ -876,6 +922,49 @@ end end +--! Daily update of the ratholes. +--!param self (Hospital) hospital being updated. +local function dailyUpdateRatholes(self) + local map = self.world.map + local th = map.th + + local wanted_holes = math.round(th:getLitterFraction(self:getPlayerIndex()) * 200) + if #self.ratholes < wanted_holes then -- Not enough holes, find a new spot + -- Try to find a wall in a corridor, and add it if possible. + -- Each iteration does a few probes at a random position, most tries will + -- fail on not being on a free (non-built) tile in a corridor with a wall + -- in the right hospital. + -- Doing more iterations speeds up finding a suitable location, less + -- iterations is reduces needed processor time. + -- "6 + 2 * difference" is an arbitrary value that seems to work nicely, 12 + -- is an arbitrary upper limit on the number of tries. + for _ = 1, math.min(12, 6 + 2 * (wanted_holes - #self.ratholes)) do + local x = math.random(1, map.width) + local y = math.random(1, map.height) + local flags = th:getCellFlags(x, y) + if self:isInHospital(x, y) and flags.roomId == 0 and flags.buildable then + local walls = self:getWallsAround(x, y) + if #walls > 0 then + -- Found a wall, check it for not being used. + local wall = walls[math.random(1, #walls)] + local found = false + for _, hole in ipairs(self.ratholes) do + if hole.x == x and hole.y == y and hole.wall == wall.wall then + found = true + break + end + end + + if not found then + self:addRathole(x, y, wall.wall, wall.parcel) + break + end + end + end + end + end +end + -- Called at the end of each day. function Hospital:onEndDay() local pay_this = self.loan*self.interest_rate/365 -- No leap years @@ -895,36 +984,16 @@ end local hosp = self.world.hospitals[1] hosp.receptionist_count = 0 - for i, staff in ipairs(self.staff) do + for _, staff in ipairs(self.staff) do if staff.humanoid_class == "Receptionist" then hosp.receptionist_count = hosp.receptionist_count + 1 end end - -- if there's currently an earthquake going on, possibly give the machines some damage - if (self.world.active_earthquake) then - for _, room in pairs(self.world.rooms) do - -- Only damage this hospital's objects. - if room.hospital == self then -- TODO: For multiplayer? - for object, value in pairs(room.objects) do - if object.strength then - -- The or clause is for backwards compatibility. Then the machine takes one damage each day. - if (object.quake_points and object.quake_points > 0) - or object.quake_points == nil then - object:machineUsed(room) - end - if object.quake_points then - object.quake_points = object.quake_points - 1 - end - end - end - end - end - end - -- check if we still have to anounce VIP visit + -- check if we still have to announce VIP visit if self.announce_vip > 0 then -- check if the VIP is in the building yet - for i, e in ipairs(self.world.entities) do + for _, e in ipairs(self.world.entities) do if e.humanoid_class == "VIP" and e.announced == false then if self:isInHospital(e.tile_x, e.tile_y) and self:isPlayerHospital() then -- play VIP arrival sound and show tooltips @@ -946,10 +1015,10 @@ -- Is the boiler working today? local breakdown = math.random(1, 240) - if breakdown == 1 and not self.heating_broke and self.boiler_can_break - and self.world.object_counts.radiator > 0 then + if breakdown == 1 and not self.heating_broke and self.boiler_can_break and + self.world.object_counts.radiator > 0 then if tonumber(self.world.map.level_number) then - if self.world.map.level_number == 1 and (self.world.month > 5 or self.world.year > 1) then + if self.world.map.level_number == 1 and (self.world:date() >= Date(1,6)) then self:boilerBreakdown() elseif self.world.map.level_number > 1 then self:boilerBreakdown() @@ -960,30 +1029,19 @@ end -- Calculate heating cost daily. Divide the monthly cost by the number of days in that month - local month_length = { - 31, -- Jan - 28, -- Feb - 31, -- Mar - 30, -- Apr - 31, -- May - 30, -- Jun - 31, -- Jul - 31, -- Aug - 30, -- Sep - 31, -- Oct - 30, -- Nov - 31, -- Dec - } local radiators = self.world.object_counts.radiator - local heating_costs = (((self.radiator_heat * 10) * radiators) * 7.50) / month_length[self.world.month] + local heating_costs = (((self.radiator_heat * 10) * radiators) * 7.50) / self.world:date():lastDayOfMonth() self.acc_heating = self.acc_heating + heating_costs + + if self:isPlayerHospital() then dailyUpdateRatholes(self) end end -- Called at the end of each month. function Hospital:onEndMonth() -- Spend wages local wages = 0 - for i, staff in ipairs(self.staff) do + local current_month = self.world:date():monthOfYear() + for _, staff in ipairs(self.staff) do wages = wages + staff.profile.wage end if wages ~= 0 then @@ -998,8 +1056,7 @@ if self:isPlayerHospital() then if self.balance < 1000 and not self.cash_msg then self:cashLow() - elseif self.balance > 6000 - and self.loan > 0 and not self.cash_ms then + elseif self.balance > 6000 and self.loan > 0 and not self.cash_ms then self.world.ui.adviser:say(_A.warnings.pay_back_loan) end self.cash_msg = true @@ -1022,23 +1079,21 @@ -- add to score each month -- rate varies on some performance factors i.e. reputation above 500 increases the score -- and the number of deaths will reduce the score. - local sal_inc = self.salary_incr /10 - local sal_mult = ((self.reputation)-500)/((self.num_deaths)+1) -- added 1 so that you don't multipy by 0 + local sal_inc = self.salary_incr / 10 + local sal_mult = (self.reputation - 500) / (self.num_deaths + 1) -- added 1 so that you don't divide by 0 local month_incr = sal_inc + sal_mult - -- To ensure that you can't recieve less than 50 or + -- To ensure that you can't receive less than 50 or -- more than 300 per month if month_incr < self.sal_min then month_incr = self.sal_min elseif month_incr > self.salary_incr then month_incr = self.salary_incr - else - month_incr = month_incr end self.player_salary = self.player_salary + math.ceil(month_incr) -- TODO: do you get interest on the balance owed? for i, company in ipairs(self.insurance_balance) do - -- Get the amount that is about to be payed to the player + -- Get the amount that is about to be paid to the player local payout_amount = company[3] if payout_amount > 0 then local str = _S.transactions.insurance_colon .. " " .. self.insurance[i] @@ -1050,10 +1105,10 @@ end -- Check for equipment getting available - self.research:checkAutomaticDiscovery(self.world.month + 12 * (self.world.year - 1)) + self.research:checkAutomaticDiscovery(self.world:date():monthOfGame()) -- Add some interesting statistics. - self.statistics[self.world.month + 1 + 12 * (self.world.year - 1)] = { + self.statistics[self.world:date():monthOfGame() + 1] = { money_in = self.money_in, money_out = self.money_out, wages = wages, @@ -1067,18 +1122,18 @@ self.money_out = 0 -- make players aware of the need for a receptionist and desk. - if (self:isPlayerHospital() and not self:hasStaffedDesk()) and self.world.year == 1 then - if self.receptionist_count ~= 0 and self.world.month > 2 and not self.receptionist_msg then + if (self:isPlayerHospital() and not self:hasStaffedDesk()) and self.world:date():year() == 1 then + if self.receptionist_count ~= 0 and current_month > 2 and not self.receptionist_msg then self.world.ui.adviser:say(_A.warnings.no_desk_6) self.receptionist_msg = true - elseif self.receptionist_count == 0 and self.world.month > 2 and self.world.object_counts["reception_desk"] ~= 0 then + elseif self.receptionist_count == 0 and current_month > 2 and self.world.object_counts["reception_desk"] ~= 0 then self.world.ui.adviser:say(_A.warnings.no_desk_7) -- self.receptionist_msg = true - elseif self.world.month == 3 then + elseif current_month == 3 then self.world.ui.adviser:say(_A.warnings.no_desk, true) - elseif self.world.month == 8 then + elseif current_month == 8 then self.world.ui.adviser:say(_A.warnings.no_desk_1, true) - elseif self.world.month == 11 then + elseif current_month == 11 then if self.visitors == 0 then self.world.ui.adviser:say(_A.warnings.no_desk_2, true) else @@ -1093,8 +1148,27 @@ return self == self.world:getLocalPlayerHospital() end +--! Does the hospital have a working reception? +--!return (bool) Whether there is a working reception in the hospital. function Hospital:hasStaffedDesk() - return (self.world.object_counts["reception_desk"] ~= 0 and self:hasStaffOfCategory("Receptionist")) + for _, desk in ipairs(self:findReceptionDesks()) do + if desk.receptionist or desk.reserved_for then return true end + end + return false +end + +--! Collect the reception desks in the hospital. +--!return (list) The reception desks in the hospital. +function Hospital:findReceptionDesks() + local reception_desks = {} + for _, obj_list in pairs(self.world.objects) do + for _, obj in ipairs(obj_list) do + if obj.object_type.id == "reception_desk" then + reception_desks[#reception_desks + 1] = obj + end + end + end + return reception_desks end --! Called at the end of each year @@ -1102,13 +1176,13 @@ self.sodas_sold = 0 self.num_vips_ty = 0 self.num_deaths_this_year = 0 - self.reputation_above_threshold = self.win_awards - and self.world.map.level_config.awards_trophies.Reputation < self.reputation or false + self:checkReputation() + -- On third year of level 3 there is the large increase to salary -- this will replicate that. I have still to check other levels above 5 to -- see if there are other large increases. -- TODO Hall of fame and shame - if self.world.year == 3 and self.world.map.level_number == 3 then + if self.world:date():year() == 3 and self.world.map.level_number == 3 then -- adds the extra to salary in level 3 year 3 self.player_salary = self.player_salary + math.random(8000,20000) end @@ -1187,8 +1261,8 @@ function Hospital:resolveEmergency() local emer = self.emergency local rescued_patients = emer.cured_emergency_patients - for i, patient in ipairs(self.emergency_patients) do - if patient and patient.hospital and not patient:getRoom() then + for _, patient in ipairs(self.emergency_patients) do + if patient and not patient.cured and not patient.dead and not patient:getRoom() then patient:die() end end @@ -1216,7 +1290,7 @@ end --check if there's a VIP in the building, and if there is then let him know the outcome - for i, e in ipairs(self.world.entities) do + for _, e in ipairs(self.world.entities) do if class.is(e, Vip) then e:evaluateEmergency(emergency_success) end @@ -1225,18 +1299,169 @@ self.world:nextEmergency() end --- Creates VIP +--! Determine if all of the patients in the emergency have been cured or killed. +--! If they have end the emergency timer. +function Hospital:checkEmergencyOver() + local killed = self.emergency.killed_emergency_patients + local cured = self.emergency.cured_emergency_patients + if killed + cured >= self.emergency.victims then + local window = self.world.ui:getWindow(UIWatch) + if window then + window:onCountdownEnd() + end + end +end + +-- Creates VIP and sends a FAX to query the user. function Hospital:createVip() local vipName = _S.vip_names[math.random(1,10)] local message = { {text = _S.fax.vip_visit_query.vip_name:format(vipName)}, choices = {{text = _S.fax.vip_visit_query.choices.invite, choice = "accept_vip", additionalInfo = {name=vipName}}, - {text = _S.fax.vip_visit_query.choices.refuse, choice = "refuse_vip"}} + {text = _S.fax.vip_visit_query.choices.refuse, choice = "refuse_vip", additionalInfo = {name=vipName}}} } -- auto-refuse after 20 days self.world.ui.bottom_panel:queueMessage("personality", message, nil, 24*20, 2) end +--[[ Creates a new epidemic by creating a new contagious patient with + a random disease - this is NOT typically how epidemics are started (mainly for cheat use) + see @Hospital:determineIfContagious() to see how epidemics are typically started]] +function Hospital:spawnContagiousPatient() + --[[ Gets the available non-visual disease in the current world + @return non_visuals (table) table of available non-visual diseases]] + local function get_avaliable_contagious_diseases() + local contagious = {} + for _, disease in ipairs(self.world.available_diseases) do + if disease.contagious then + contagious[#contagious + 1] = disease + end + end + return contagious + end + + if self:hasStaffedDesk() then + local patient = self.world:newEntity("Patient", 2) + local contagious_diseases = get_avaliable_contagious_diseases() + if #contagious_diseases > 0 then + local disease = contagious_diseases[math.random(1,#contagious_diseases)] + patient:setDisease(disease) + --Move the first patient closer (FOR TESTING ONLY) + local x,y = self:getHeliportSpawnPosition() + patient:setTile(x,y) + patient:setHospital(self) + self:addToEpidemic(patient) + else + print("Cannot create epidemic - no contagious diseases available") + end + else + print("Cannot create epidemic - no staffed reception desk") + end +end + +function Hospital:countEpidemics() + -- Count the current epidemic if it exists + local epidemic_count = self.epidemic and 1 or 0 + epidemic_count = epidemic_count + #self.future_epidemics_pool + return epidemic_count +end + +--[[ Make the active epidemic (if exists) and any future epidemics tick. If there +is no current epidemic determines if any epidemic in the pool of future +epidemics can become the active one. Also removes any epidemics from the +future pool which have no infected patients and thus, will have no effect on +the hospital. ]] +function Hospital:manageEpidemics() + --[[ Can the future epidemic be revealed to the player + @param future_epidemic (Epidemic) the epidemic to attempt to reveal + @return true if can be revealed false otherwise (boolean) ]] + local function can_be_revealed(epidemic) + return not self.world.ui:getWindow(UIWatch) and + not self.epidemic and epidemic.ready_to_reveal + end + + local current_epidemic = self.epidemic + if(current_epidemic) then + current_epidemic:tick() + end + + if self.future_epidemics_pool then + for i, future_epidemic in ipairs(self.future_epidemics_pool) do + if future_epidemic:hasNoInfectedPatients() then + table.remove(self.future_epidemics_pool,i) + elseif can_be_revealed(future_epidemic) then + self.epidemic = future_epidemic + self.epidemic:revealEpidemic() + table.remove(self.future_epidemics_pool,i) + else + future_epidemic:tick() + end + end + end +end + +--[[ Determines if a patient is contagious and then attempts to add them the + appropriate epidemic if so. + @param patient (Patient) patient to determine if contagious]] +function Hospital:determineIfContagious(patient) + if patient.is_emergency or not patient.disease.contagious then + return false + end + -- ContRate treated like a percentage with ContRate% of patients with + -- a disease having the contagious strain + local level_config = self.world.map.level_config + local disease = patient.disease + local contRate = level_config.expertise[disease.expertise_id].ContRate or 0 + + -- The patient is potentially contagious as we do not yet know if there + -- is a suitable epidemic which they can belong to + local potentially_contagious = contRate > 0 and (math.random(1,contRate) == contRate) + -- The patient isn't contagious if these conditions aren't passed + local reduce_months = level_config.ReduceContMonths or 14 + local reduce_people = level_config.ReduceContPeepCount or 20 + local date_in_months = self.world:date():monthOfGame() + + if potentially_contagious and date_in_months > reduce_months and + self.num_visitors > reduce_people then + self:addToEpidemic(patient) + end +end + +--[[ Determines if there is a suitable epidemic the contagious patient can + belong to and adds them to it if possible. N.B. a patient isn't actually + contagious until they belong to an epidemic. So if it isn't possible to add a + patient to an epidemic they are just treated as a normal patient. + @param patient (Patient) patient to attempt to add to an epidemic ]] +function Hospital:addToEpidemic(patient) + local epidemic = self.epidemic + -- Don't add a new contagious patient if the player is trying to cover up + -- an existing epidemic - not really fair + if epidemic and not epidemic.coverup_in_progress and + (patient.disease == epidemic.disease) then + epidemic:addContagiousPatient(patient) + elseif self.future_epidemics_pool and + not (epidemic and epidemic.coverup_in_progress) then + local added = false + for _, future_epidemic in ipairs(self.future_epidemics_pool) do + if future_epidemic.disease == patient.disease then + future_epidemic:addContagiousPatient(patient) + added = true + break + end + end + + if not added then + -- Make a new epidemic as one doesn't exist with this disease, but only if + -- we haven't reach the concurrent epidemic limit + if self:countEpidemics() < self.concurrent_epidemic_limit then + local new_epidemic = Epidemic(self, patient) + self.future_epidemics_pool[#self.future_epidemics_pool + 1] = new_epidemic + end + end + end +end + + function Hospital:spawnPatient() self.world:spawnPatient(self) end @@ -1266,18 +1491,19 @@ !param name (string) The name (id) of the object to investigate. ]] function Hospital:getObjectBuildCost(name) - -- Some helpers + -- Everything is free in free build mode. + if self.world.free_build_mode then return 0 end + local progress = self.research.research_progress - local config = self.world.map.level_config.objects + local cfg_objects = self.world.map.level_config.objects local obj_def = TheApp.objects[name] -- Get how much this item costs at the start of the level. - local obj_cost = config[obj_def.thob].StartCost + local obj_cost = cfg_objects[obj_def.thob].StartCost -- Some objects might have got their cost reduced by research. if progress[obj_def] then obj_cost = progress[obj_def].cost end - -- Everything is free in free build mode. - return not self.world.free_build_mode and obj_cost or 0 + return obj_cost end --[[ Lowers the player's money by the given amount and logs the transaction. @@ -1290,7 +1516,7 @@ function Hospital:spendMoney(amount, reason, changeValue) if not self.world.free_build_mode then self.balance = self.balance - amount - self:logTransaction{spend = amount, desc = reason} + self:logTransaction({spend = amount, desc = reason}) self.money_out = self.money_out + amount if changeValue then self.value = self.value + changeValue @@ -1308,7 +1534,7 @@ function Hospital:receiveMoney(amount, reason, changeValue) if not self.world.free_build_mode then self.balance = self.balance + amount - self:logTransaction{receive = amount, desc = reason} + self:logTransaction({receive = amount, desc = reason}) self.money_in = self.money_in + amount if changeValue then self.value = self.value - changeValue @@ -1322,37 +1548,38 @@ ]] function Hospital:receiveMoneyForTreatment(patient) if not self.world.free_build_mode then - local disease_id + local disease_id = patient:getTreatmentDiseaseId() + if disease_id == nil then return end + local casebook = self.disease_casebook[disease_id] local reason - if not self.world.free_build_mode then - if patient.diagnosed then - disease_id = patient.disease.id - reason = _S.transactions.cure_colon .. " " .. patient.disease.name - else - local room_info = patient:getRoom() - if not room_info then - print("Warning: Trying to receieve money for treated patient who is ".. - "not in a room") - return - end - room_info = room_info.room_info - disease_id = "diag_" .. room_info.id - reason = _S.transactions.treat_colon .. " " .. room_info.name - end - local casebook = self.disease_casebook[disease_id] - local amount = self:getTreatmentPrice(disease_id) - casebook.money_earned = casebook.money_earned + amount - patient.world:newFloatingDollarSign(patient, amount) - -- 25% of the payments now go through insurance - if patient.insurance_company then - self:addInsuranceMoney(patient.insurance_company, amount) - else - self:receiveMoney(amount, reason) - end + if casebook.pseudo then + reason = _S.transactions.treat_colon .. " " .. casebook.disease.name + else + reason = _S.transactions.cure_colon .. " " .. casebook.disease.name end + local amount = self:getTreatmentPrice(disease_id) + + -- 25% of the payments now go through insurance + if patient.insurance_company then + self:addInsuranceMoney(patient.insurance_company, amount) + else + -- patient is paying normally (but still, he could feel like it's + -- under- or over-priced and it could impact happiness and reputation) + self:computePriceLevelImpact(patient, casebook) + self:receiveMoney(amount, reason) + end + casebook.money_earned = casebook.money_earned + amount + patient.world:newFloatingDollarSign(patient, amount) end end +--! Sell a soda to a patient. +--!param patient (patient) The patient buying the soda. +function Hospital:sellSodaToPatient(patient) + self:receiveMoneyForProduct(patient, 20, _S.transactions.drinks) + self.sodas_sold = self.sodas_sold + 1 +end + --! Function to determine the price for a treatment, modified by reputation and percentage -- Treatment charge should never be less than the starting price if reputation falls below 500 function Hospital:getTreatmentPrice(disease) @@ -1376,20 +1603,84 @@ self:receiveMoney(amount, reason) end +--! Pay drug if drug has been purchased to treat a patient. +--!param disease_id Disease that was treated. +function Hospital:paySupplierForDrug(disease_id) + local drug_amount = self.disease_casebook[disease_id].drug_cost or 0 + if drug_amount ~= 0 then + local str = _S.drug_companies[math.random(1, 5)] + self:spendMoney(drug_amount, _S.transactions.drug_cost .. ": " .. str) + end +end + --[[ Add a transaction to the hospital's transaction log. !param transaction (table) A table containing a string field called `desc`, and at least one of the following integer fields: `spend`, `receive`. ]] function Hospital:logTransaction(transaction) transaction.balance = self.balance - transaction.day = self.world.day - transaction.month = self.world.month + transaction.day = self.world:date():dayOfMonth() + transaction.month = self.world:date():monthOfYear() while #self.transactions > 20 do self.transactions[#self.transactions] = nil end table.insert(self.transactions, 1, transaction) end +--! Initialize hospital staff from the level config. +function Hospital:initStaff() + local level_config = self.world.map.level_config + if level_config.start_staff then + for _, conf in ipairs(level_config.start_staff) do + local profile + local skill = 0 + local added_staff = true + if conf.Skill then + skill = conf.Skill / 100 + end + + if conf.Nurse == 1 then + profile = StaffProfile(self.world, "Nurse", _S.staff_class["nurse"]) + profile:init(skill) + elseif conf.Receptionist == 1 then + profile = StaffProfile(self.world, "Receptionist", _S.staff_class["receptionist"]) + profile:init(skill) + elseif conf.Handyman == 1 then + profile = StaffProfile(self.world, "Handyman", _S.staff_class["handyman"]) + profile:init(skill) + elseif conf.Doctor == 1 then + profile = StaffProfile(self.world, "Doctor", _S.staff_class["doctor"]) + + local shrink = 0 + local rsch = 0 + local surg = 0 + local jr, cons + + if conf.Shrink == 1 then shrink = 1 end + if conf.Surgeon == 1 then surg = 1 end + if conf.Researcher == 1 then rsch = 1 end + + if conf.Junior == 1 then jr = 1 + elseif conf.Consultant == 1 then cons = 1 + end + profile:initDoctor(shrink,surg,rsch,jr,cons,skill) + else + added_staff = false + end + if added_staff then + local staff = self.world:newEntity("Staff", 2) + staff:setProfile(profile) + -- TODO: Make a somewhat "nicer" placing algorithm. + staff:setTile(self.world.map.th:getCameraTile(1)) + staff:onPlaceInCorridor() + self.staff[#self.staff + 1] = staff + staff:setHospital(self) + end + end + end +end + + function Hospital:addStaff(staff) self.staff[#self.staff + 1] = staff -- Cost of hiring staff: @@ -1401,6 +1692,9 @@ -- Add to the hospital's visitor count self.num_visitors = self.num_visitors + 1 self.num_visitors_ty = self.num_visitors_ty + 1 + + -- Decide if the patient belongs in an epidemic + self:determineIfContagious(patient) end function Hospital:humanoidDeath(humanoid) @@ -1418,7 +1712,7 @@ --! returns false if none, else number of that type employed function Hospital:hasStaffOfCategory(category) local result = false - for i, staff in ipairs(self.staff) do + for _, staff in ipairs(self.staff) do if staff.humanoid_class == category then result = (result or 0) + 1 elseif staff.humanoid_class == "Doctor" then @@ -1447,6 +1741,11 @@ return result end +--! Remove the first entry with a given value from a table. +--! Only works reliably for lists. +--!param t Table to search for the value, and update. +--!param value Value to search and remove. +--!return Whether the value was removed. local function RemoveByValue(t, value) for i, v in ipairs(t) do if v == value then @@ -1457,10 +1756,14 @@ return false end +--! Remove a staff member from the hospital staff. +--!param staff (Staff) Staff member to remove. function Hospital:removeStaff(staff) RemoveByValue(self.staff, staff) end +--! Remove a patient from the hospital. +--!param patient (Patient) Patient to remove. function Hospital:removePatient(patient) RemoveByValue(self.patients, patient) end @@ -1472,6 +1775,8 @@ ["kicked"] = -3, -- firing a staff member OR sending a patient home ["emergency_success"] = 15, ["emergency_failed"] = -20, + ["over_priced"] = -2, + ["under_priced"] = 1, } --! Normally reputation is changed based on a reason, and the affected @@ -1483,14 +1788,16 @@ function Hospital:changeReputation(reason, disease, valueChange) local amount if reason == "autopsy_discovered" then - local config = self.world.map.level_config.gbv.AutopsyRepHitPercent - amount = config and math.floor(-self.reputation*config/100) or -70 + local rep_hit_perc = self.world.map.level_config.gbv.AutopsyRepHitPercent + amount = rep_hit_perc and math.floor(-self.reputation * rep_hit_perc / 100) or -70 elseif valueChange then amount = valueChange else amount = reputation_changes[reason] end - self.reputation = self.reputation + amount + if self:isReputationChangeAllowed(amount) then + self.reputation = self.reputation + amount + end if disease then local casebook = self.disease_casebook[disease.id] casebook.reputation = casebook.reputation + amount @@ -1501,8 +1808,92 @@ self.reputation = self.reputation_max end -- Check if criteria for trophy is still met - if self.reputation_above_threshold then - self.reputation_above_threshold = self.world.map.level_config.awards_trophies.Reputation < self.reputation + if self.reputation_above_threshold then self:checkReputation() end +end + +--! Check whether the reputation is still above the treshold. +function Hospital:checkReputation() + local level_config = self.world.map.level_config + if level_config.awards_trophies then + local min_repuration = level_config.awards_trophies.Reputation + self.reputation_above_threshold = min_repuration < self.reputation + return + end + self.reputation_above_threshold = false +end + +--! Decide whether a reputation change is effective or not. As we approach 1000, +--! a gain is less likely. As we approach 0, a loss is less likely. +--! Under 500, a gain is always effective. Over 500, a loss is always effective. +--!param amount (int): The amount of reputation change. +function Hospital:isReputationChangeAllowed(amount) + if (amount > 0 and self.reputation <= 500) or (amount < 0 and self.reputation >= 500) or (amount == 0) then + return true + else + return math.random() <= self:getReputationChangeLikelihood() + end +end + +--! Compute the likelihood for a reputation change to be effective. +--! Likelihood gets smaller as hospital reputation gets closer to extreme values. +--!return (float) Likelihood of a reputation change. +function Hospital:getReputationChangeLikelihood() + -- The result follows a quadratic function, for a curved and smooth evolution. + -- If reputation == 500, the result is 100%. + -- Between [380-720], the result is still over 80%. + -- At 100 or 900, it's under 40%. + -- At 0 or 1000, it's 0%. + -- + -- The a, b and c coefficients have been computed to include points + -- (x=0, y=1), (x=500, y=0) and (x=1000, y=1) where x is the current + -- reputation and y the likelihood of the reputation change to be + -- refused, based a discriminant (aka "delta") == 0 + local a = 0.000004008 + local b = 0.004008 + local c = 1 + + local x = self.reputation + + -- The result is "reversed" for more readability + return 1 - (a * x * x - b * x + c) +end + +--! Update the 'cured' counts of the hospital. +--!param patient Patient that was cured. +function Hospital:updateCuredCounts(patient) + if not patient.is_debug then + self:changeReputation("cured", patient.disease) + end + + if self.num_cured < 1 then + self.world.ui.adviser:say(_A.information.first_cure) + end + self.num_cured = self.num_cured + 1 + self.num_cured_ty = self.num_cured_ty + 1 + + local casebook = self.disease_casebook[patient.disease.id] + casebook.recoveries = casebook.recoveries + 1 + + if patient.is_emergency then + self.emergency.cured_emergency_patients = self.emergency.cured_emergency_patients + 1 + end +end + +--! Update the 'not cured' counts of the hospital. +--!param patient Patient that was not cured. +--!param reason (string) the reason why the patient is not cured. +--! -"kicked": Patient goes home early (manually sent, no treatment room, etc). +--! -"over_priced": Patient considers the price too high. +function Hospital:updateNotCuredCounts(patient, reason) + if patient.is_debug then return end + + self:changeReputation(reason, patient.disease) + self.not_cured = self.not_cured + 1 + self.not_cured_ty = self.not_cured_ty + 1 + + if reason == "kicked" then + local casebook = self.disease_casebook[patient.disease.id] + casebook.turned_away = casebook.turned_away + 1 end end @@ -1513,17 +1904,45 @@ self.percentage_cured = math.round(cured) end -function Hospital:getAveragePatientAttribute(attribute) - -- Some patients (i.e. Alien) may not have the attribute in question, so check for that +--! Compute average of an attribute for all patients in the hospital. +--!param attribute (str) Name of the attribute. +--!param default_value Value to return if there are no patients. +--!return Average value of the attribute for all hospital patients, or the default value. +function Hospital:getAveragePatientAttribute(attribute, default_value) local sum = 0 local count = 0 for _, patient in ipairs(self.patients) do - sum = sum + (patient.attributes[attribute] or 0) + -- Some patients (i.e. Alien) may not have the attribute in question, so check for that if patient.attributes[attribute] then + sum = sum + patient.attributes[attribute] count = count + 1 end end - return sum / count + + if count == 0 then + return default_value + else + return sum / count + end +end + +--! Compute average of an attribute for all staff in the hospital. +--!param attribute (str) Name of the attribute. +--!param default_value Value to return if there is no staff. +--!return Average value of the attribute for all staff, or the default value. +function Hospital:getAverageStaffAttribute(attribute, default_value) + local sum = 0 + local count = 0 + for _, staff in ipairs(self.staff) do + sum = sum + staff.attributes[attribute] + count = count + 1 + end + + if count == 0 then + return default_value + else + return sum / count + end end --! Checks if the requirements for the given disease are met in the hospital and returns the ones missing. @@ -1538,7 +1957,7 @@ local rooms = {} local staff = {} local any = false - for i, room_id in ipairs(self.world.available_diseases[disease].treatment_rooms) do + for _, room_id in ipairs(self.world.available_diseases[disease].treatment_rooms) do local found = self:hasRoomOfType(room_id) if not found then rooms[#rooms + 1] = room_id @@ -1559,8 +1978,129 @@ return any and {rooms = rooms, staff = staff} end +--! Get the set of walls around a tile position. +--!param x (int) X position of the queried tile. +--!param y (int) Y position of the queried tile. +--!return (table {wall, parcel}) The walls around the given position. +function Hospital:getWallsAround(x, y) + local map = self.world.map + local th = map.th + + local _, nw, ww + local walls = {} -- List of {wall="north"/"west"/"south"/"east", parcel} + local flags = th:getCellFlags(x, y) + + _, nw, ww = th:getCell(x, y) -- floor, north wall, west wall + if ww ~= 0 then + walls[#walls + 1] = {wall = "west", parcel = flags.parcelId} + end + if nw ~= 0 then + walls[#walls + 1] = {wall = "north", parcel = flags.parcelId} + end + + if x ~= map.width then + _, _, ww = th:getCell(x + 1, y) + if ww ~= 0 then + walls[#walls + 1] = {wall = "east", parcel = flags.parcelId} + end + end + + if y ~= map.height then + _, nw, _ = th:getCell(x, y + 1) + if nw ~= 0 then + walls[#walls + 1] = {wall = "south", parcel = flags.parcelId} + end + end + + return walls +end + +--! Test for the given position to be inside the given rectangle. +--!param x (int) X position to test. +--!param y (int) Y position to test. +--!param rect (table x, y, width, height) Rectangle to check against. +--!return (bool) Whether the position is inside the rectangle. +local function isInside(x, y, rect) + return x >= rect.x and x < rect.x + rect.width and y >= rect.y and y < rect.y + rect.height +end + +--! Find all ratholes that match the `to_match` criteria. +--!param holes (list ratholes) Currently existing holes. +--!param to_match (table) For each direction a rectangle with matching tile positions. +--!return (list) Matching ratholes. +local function findMatchingRatholes(holes, to_match) + local matched = {} + for _, hole in ipairs(holes) do + if isInside(hole.x, hole.y, to_match[hole.wall]) then table.insert(matched, hole) end + end + return matched +end + +--! Remove the ratholes that use the walls of the provided room. +--!param room (Room) Room being de-activated. +function Hospital:removeRatholesAroundRoom(room) + local above_rect = {x = room.x, width = room.width, y = room.y - 1, height = 1} + local below_rect = {x = room.x, width = room.width, y = room.y +room.height, height = 1} + local left_rect = {x = room.x - 1, width = 1, y = room.y, height = room.height} + local right_rect = {x = room.x + room.width, width = 1, y = room.y, height = room.height} + + local to_delete = {east = left_rect, west = right_rect, south = above_rect, north = below_rect} + + local remove_holes = findMatchingRatholes(self.ratholes, to_delete) + for _, hole in ipairs(remove_holes) do self:removeRathole(hole) end +end + +-- Add a rathole to the room. +--!param x (int) X position of the tile containing the rathole. +--!param y (int) Y position of the tile containing the rathole. +--!param wall (string) Wall containing the hole (north, west, south, east) +--!param parcel (int) Parcel number of the xy position. +function Hospital:addRathole(x, y, wall, parcel) + for _, rathole in ipairs(self.ratholes) do + if rathole.x == x and rathole.y == y and rathole.wall == wall then return end + end + + local hole = {x = x, y = y, wall = wall, parcel = parcel} + if wall == "north" or wall == "west" then + -- Only add a rat-hole graphics object for the visible holes. + hole["object"] = self.world:newObject("rathole", hole.x, hole.y, hole.wall) + end + table.insert(self.ratholes, hole) +end + +--! Remove the provided rathole. +--!param hole (table{x, y, wall, optional object}) Hole to remove. +function Hospital:removeRathole(hole) + for i, rathole in ipairs(self.ratholes) do + if rathole.x == hole.x and rathole.y == hole.y and rathole.wall == hole.wall then + table.remove(self.ratholes, i) + if rathole.object then + self.world:destroyEntity(rathole.object) + end + + break + end + end +end + +--! Remove any rathole from the given position. +--!param x X position of the tile that should not have ratholes. +--!param y Y position of the tile that should not have ratholes. +function Hospital:removeRatholeXY(x, y) + for i = #self.ratholes, 1, -1 do + local rathole = self.ratholes[i] + if rathole.x == x and rathole.y == y then + table.remove(self.ratholes, i) + if rathole.object then self.world:destroyEntity(rathole.object) end + end + end +end + class "AIHospital" (Hospital) +---@type AIHospital +local AIHospital = _G["AIHospital"] + function AIHospital:AIHospital(competitor, ...) self:Hospital(...) if _S.competitor_names[competitor] then @@ -1580,16 +2120,15 @@ end function Hospital:addHandymanTask(object, taskType, priority, x, y, call) - local parcelId = self.world.map.th:getCellFlags(x, y).parcelId local subTable = self:findHandymanTaskSubtable(taskType) - table.insert(subTable, {["object"] = object, ["priority"] = priority, ["tile_x"] = x, ["tile_y"] = y, ["parcelId"] = parcelId, ["call"] = call}); + table.insert(subTable, {["object"] = object, ["priority"] = priority, ["tile_x"] = x, ["tile_y"] = y, ["parcelId"] = parcelId, ["call"] = call}) end function Hospital:modifyHandymanTaskPriority(taskIndex, newPriority, taskType) if taskIndex ~= -1 then local subTable = self:findHandymanTaskSubtable(taskType) - self:findHandymanTaskSubtable(taskType)[taskIndex].priority = newPriority; + subTable[taskIndex].priority = newPriority end end @@ -1607,7 +2146,7 @@ end function Hospital:findHandymanTaskSubtable(taskType) - for i,v in ipairs(self.handymanTasks) do + for i = 1, #self.handymanTasks do if self.handymanTasks[i].taskType == taskType then return self.handymanTasks[i].subTable end @@ -1624,10 +2163,10 @@ if taskIndex ~= -1 then local subTable = self:findHandymanTaskSubtable(taskType) if not subTable[taskIndex].assignedHandyman then - subTable[taskIndex].assignedHandyman = handyman + subTable[taskIndex].assignedHandyman = handyman else local formerHandyman = subTable[taskIndex].assignedHandyman - subTable[taskIndex].assignedHandyman = handyman + subTable[taskIndex].assignedHandyman = handyman formerHandyman:interruptHandymanTask() end end @@ -1666,6 +2205,12 @@ if v.assignedHandyman then if v.assignedHandyman.fired then v.assignedHandyman = nil + elseif not v.assignedHandyman.hospital then + -- This should normally never be the case. If the handyman doesn't belong to a hsopital + -- then they should not have any tasks assigned to them however it was previously possible + -- We need to tidy up to make sure the task can be reassigned. + print("Warning: Orphaned handyman is still assigned a task. Removing.") + v.assignedHandyman = nil else local assignedDistance = self.world:getPathDistance(v.tile_x, v.tile_y, v.assignedHandyman.tile_x, v.assignedHandyman.tile_y) if assignedDistance ~= false then @@ -1701,24 +2246,30 @@ return index end - -function Hospital:getIndexOfTask(x, y, taskType) +--! Find a handyman task by task type, position, and possibly the used object. +--!param x (int) The X coordinate of the position. +--!param y (int) The Y coordinate of the position. +--!param taskType Type of the task. +--!param obj (Object) If specified, the object used for doing the task. +--! Since multiple litter objects may exist at the same tile, the object must be given when cleaning. +function Hospital:getIndexOfTask(x, y, taskType, obj) local subTable = self:findHandymanTaskSubtable(taskType) for i, v in ipairs(subTable) do - if v.tile_x == x and v.tile_y == y then + if v.tile_x == x and v.tile_y == y and (obj == nil or v.object == obj) then return i end end return -1 end +--! Afterload function to initialize the owned plots. function Hospital:initOwnedPlots() self.ownedPlots = {} - for i, v in ipairs(self.world.entities) do + for _, v in ipairs(self.world.entities) do if v.tile_x and v.tile_y then - local parcel = self.world.map.th:getCellFlags(v.tile_x, v.tile_y).parcelId; + local parcel = self.world.map.th:getCellFlags(v.tile_x, v.tile_y).parcelId local isAlreadyContained = false - for i2, v2 in ipairs(self.ownedPlots) do + for _, v2 in ipairs(self.ownedPlots) do if parcel == v2 then isAlreadyContained = true break @@ -1737,7 +2288,7 @@ function Hospital:roomNotYetResearched(disease) local req = self:checkDiseaseRequirements(disease) if type(req) == "table" and #req.rooms > 0 then - for i, room_id in ipairs(req.rooms) do + for _, room_id in ipairs(req.rooms) do if not self.discovered_rooms[self.world.available_rooms[room_id]] then return true end @@ -1777,3 +2328,30 @@ end return false end + +--! Change patient happiness and hospital reputation based on price distortion. +--! The patient happiness is adjusted proportionally. The hospital reputation +--! can only be affected when the distortion level reaches some threshold. +--!param patient (patient) The patient paying the bill. His/her happiness level +--! is adjusted. +--!param casebook (object) Disease casebook entry. It's used to display the +--! localised disease name when Adviser tells the warning message. +function Hospital:computePriceLevelImpact(patient, casebook) + local price_distortion = patient:getPriceDistortion(casebook) + patient:changeAttribute("happiness", -(price_distortion / 2)) + + if price_distortion < self.under_priced_threshold then + if math.random(1, 100) == 1 then + self.world.ui.adviser:say(_A.warnings.low_prices:format(casebook.disease.name)) + self:changeReputation("under_priced") + end + elseif price_distortion > self.over_priced_threshold then + if math.random(1, 100) == 1 then + self.world.ui.adviser:say(_A.warnings.high_prices:format(casebook.disease.name)) + self:changeReputation("over_priced") + end + elseif math.abs(price_distortion) <= 0.15 and math.random(1, 200) == 1 then + -- When prices are well adjusted (i.e. abs(price distortion) <= 0.15) + self.world.ui.adviser:say(_A.warnings.fair_prices:format(casebook.disease.name)) + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_action.lua corsix-th-0.62/CorsixTH/Lua/humanoid_action.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_action.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_action.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,113 @@ +--[[ Copyright (c) 2016 Albert "Alberth" Hofkamp + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +--! Humanoid action base class. +class "HumanoidAction" + +---@type HumanoidAction +local HumanoidAction = _G["HumanoidAction"] + +--! Construct a humanoid action (base class constructor). +--!param name (str) Name of the action. +function HumanoidAction:HumanoidAction(name) + assert(type(name) == "string", "Invalid value for parameter 'name'") + + self.name = name + self.count = nil -- 'nil' means 'forever' (until finished), else the number to perform. + self.must_happen = false -- If true, action cannot be skipped. + self.loop_callback = nil -- Periodic callback to check for termination conditions. + self.after_use = nil -- Callback for performing updates afterwards. + self.is_leaving = false -- Whether the humanoid is leaving. + self.no_truncate = false -- If set, disable shortening the action. +end + +--! Set the number of times the action should happen. +--!param count (int or nil) Set to 'nil' if 'forever', else integer count. +--!return (action) Returning self, for daisy-chaining. +function HumanoidAction:setCount(count) + assert(count == nil or type(count) == "number", "Invalid value for parameter 'count'") + + self.count = count + return self +end + +--! Set the 'must happen' flag (that is, action cannot be skipped). +--!param must_happen (bool) Whether or not the action must happen. +--!return (action) Returning self, for daisy-chaining. +function HumanoidAction:setMustHappen(must_happen) + assert(type(must_happen) == "boolean", "Invalid value for parameters 'must_happen'") + + self.must_happen = must_happen + return self +end + +--! Set the callback for checking termination conditions. +--!param loop_callback (func) Callback function that is called each iteration to check for +--! termination conditions. +--!return (action) Returning self, for daisy-chaining. +function HumanoidAction:setLoopCallback(loop_callback) + assert(loop_callback == nil or type(loop_callback) == "function", + "Invalid value for parameter 'loop_callback'") + + self.loop_callback = loop_callback + return self +end + +--! Set the callback for performing updates afterwards. +--!param after_use (func) Callback function that is called after the action ends. +--!return (action) Returning self, for daisy-chaining. +function HumanoidAction:setAfterUse(after_use) + assert(after_use == nil or type(after_use) == "function", + "Invalid value for parameter 'after_use'") + + self.after_use = after_use + return self +end + +--! Set whether the humanoid is leaving. +--!param is_leaving (bool) Whether or not the humanoid is leaving. If not specified, value is true. +--!return (action) Returning self, for daisy-chaining. +function HumanoidAction:setIsLeaving(is_leaving) + assert(type(is_leaving) == "boolean", "Invalid value for parameter 'is_leaving'") + + self.is_leaving = is_leaving + return self +end + +--! Do not allow truncating the action. +--!return (action) Returning self, for daisy-chaining. +function HumanoidAction:disableTruncate() + self.no_truncate = true + return self +end + +function HumanoidAction:afterLoad(old, new) + if old < 112 then + self.is_leaving = not not self.is_leaving + self.must_happen = not not self.must_happen + self.no_truncate = not not self.no_truncate + self.saved_must_happen = not not self.saved_must_happen + self.idle_must_happen = not not self.idle_must_happen + + if self.name == "walk" then + self.is_entering = not not self.is_entering + end + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/answer_call.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/answer_call.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/answer_call.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/answer_call.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "AnswerCallAction" (HumanoidAction) + +---@type AnswerCallAction +local AnswerCallAction = _G["AnswerCallAction"] + +function AnswerCallAction:AnswerCallAction() + self:HumanoidAction("answer_call") +end + local function action_answer_call_start(action, humanoid) action.must_happen = true CallsDispatcher.onCheckpointCompleted(action, humanoid) @@ -26,7 +35,7 @@ if room then humanoid:queueAction(room:createLeaveAction()) end - humanoid:queueAction({name = "meander"}) + humanoid:queueAction(MeanderAction()) end humanoid:finishAction(action) end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/call_checkpoint.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/call_checkpoint.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/call_checkpoint.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/call_checkpoint.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,22 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "CallCheckPointAction" (HumanoidAction) + +---@type CallCheckPointAction +local CallCheckPointAction = _G["CallCheckPointAction"] + +function CallCheckPointAction:CallCheckPointAction(call, on_remove) + assert(call == nil or + (type(call) == "table" and type(call.key) == "string"), + "Invalid value for parameter 'call'") + assert(type(on_remove) == "function", "Invalid value for parameter 'on_remove'") + + self:HumanoidAction("call_checkpoint") + self.call = call -- The call the humanoid is on (humanoid.on_call) or nil + self.on_remove = on_remove -- Interrupt handler to use. +end + local function action_call_checkpoint_start(action, humanoid) action.must_happen = true CallsDispatcher.onCheckpointCompleted(action.call) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/check_watch.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/check_watch.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/check_watch.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/check_watch.lua 2018-07-21 11:13:17.000000000 +0000 @@ -17,6 +17,17 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] + +class "CheckWatchAction" (HumanoidAction) + +---@type CheckWatchAction +local CheckWatchAction = _G["CheckWatchAction"] + +function CheckWatchAction:CheckWatchAction() + self:HumanoidAction("check_watch") + self:setMustHappen(true) +end + local action_check_watch_end = permanent"action_check_watch_end"( function(humanoid) humanoid:finishAction() end) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/die.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/die.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/die.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/die.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,8 +18,17 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "DieAction" (HumanoidAction) + +---@type DieAction +local DieAction = _G["DieAction"] + +function DieAction:DieAction() + self:HumanoidAction("die") +end + local action_die_tick; action_die_tick = permanent"action_die_tick"( function(humanoid) - local action = humanoid.action_queue[1] + local action = humanoid:getCurrentAction() local phase = action.phase local mirror = humanoid.last_move_direction == "east" and 0 or 1 if phase == 0 then @@ -54,19 +63,197 @@ humanoid:setAnimation(humanoid.die_anims.fly_east, mirror) humanoid:setTilePositionSpeed(humanoid.tile_x, humanoid.tile_y, nil, nil, 0, -4) else - humanoid:setHospital(nil) + humanoid:despawn() humanoid.world:destroyEntity(humanoid) end end) +local action_die_tick_reaper; action_die_tick_reaper = permanent"action_die_tick_reaper"( function(humanoid) + local action = humanoid:getCurrentAction() + local mirror = humanoid.last_move_direction == "east" and 0 or 1 + local phase = action.phase + + if phase == 0 then + action.phase = 1 + + if humanoid.die_anims.extra_east ~= nil then + humanoid:setTimer(humanoid.world:getAnimLength(humanoid.die_anims.extra_east), action_die_tick_reaper) + humanoid:setAnimation(humanoid.die_anims.extra_east, mirror) + else + action_die_tick_reaper(humanoid) + end + + --1: The patient stays on the ground until phase 5: + elseif phase == 1 then + action.phase = 2 + if humanoid.humanoid_class ~= "Standard Male Patient" then + humanoid:setType("Standard Male Patient") + end + humanoid:setAnimation(humanoid.on_ground_anim, mirror) + action_die_tick_reaper(humanoid) + + --2: Spawn the grim reaper and the lava hole, if no suitable spawn points are found a heaven death will be started: + elseif phase == 2 then + local holes_orientation + local hole_x, hole_y + local grim_x, grim_y + local grim_use_tile_x, grim_use_tile_y + local grim_spawn_idle_direction + local mirror_grim = 0 + + local spawn_scenarios = { + {"south", humanoid.tile_x, humanoid.tile_y + 4, 0, 1, "north", 0, -1, {{after_spawn_idle_direction = "east", hole_x_offset = -5, hole_y_offset = 2}, {hole_x_offset = 0, hole_y_offset = 3}} }, + {"east", humanoid.tile_x + 4, humanoid.tile_y, 1, 0, "west", -1, 0, {{hole_x_offset = 3, hole_y_offset = 0}} } + } + + --- + -- @param spawn_scenario {holes_orientation, find_hole_spawn_x, find_hole_spawn_y, g_use_x_offset, g_use_y_offset, grim_face_hole_dir, mirror_grim, p_use_x_offset, p_use_y_offset, find_grim_spawn_attempts} + --- + local function tryToUseHellDeathSpawnScenario(spawn_scenario) + holes_orientation = spawn_scenario[1] + hole_x, hole_y = humanoid.world.pathfinder:findIdleTile(spawn_scenario[2], spawn_scenario[3], 0) + + if hole_x and humanoid.world:canNonSideObjectBeSpawnedAt(hole_x, hole_y, "gates_to_hell", holes_orientation, 0, 0) then + if holes_orientation == "east" then + mirror_grim = 1 + end + grim_use_tile_x = hole_x + spawn_scenario[4] + grim_use_tile_y = hole_y + spawn_scenario[5] + humanoid.hole_use_tile_x = hole_x + spawn_scenario[7] + humanoid.hole_use_tile_y = hole_y + spawn_scenario[8] + --Ensure that the lava hole is passable on at least one of its sides to prevent it from blocking 1 tile wide corridors: + humanoid.world.map:setCellFlags(hole_x, hole_y, {passable = false}) + local hole_has_passable_side = humanoid.world:getPathDistance(grim_use_tile_x, grim_use_tile_y, humanoid.hole_use_tile_x, humanoid.hole_use_tile_y) == 4 + humanoid.world.map:setCellFlags(hole_x, hole_y, {passable = true}) + if not hole_has_passable_side then + return false + end + --Try to find grim a spawn point which will allow him to walk to his lava hole use tile: + local grim_cant_walk_to_use_tile = true + for _, find_grim_spawn_attempt in ipairs(spawn_scenario[9]) do + grim_spawn_idle_direction = find_grim_spawn_attempt.after_spawn_idle_direction or spawn_scenario[6] + grim_x, grim_y = humanoid.world.pathfinder:findIdleTile(hole_x + find_grim_spawn_attempt.hole_x_offset, hole_y + find_grim_spawn_attempt.hole_y_offset, 0) + if grim_x and not humanoid.world:getRoom(grim_x, grim_y) then + grim_cant_walk_to_use_tile = false + break + end + end + -- Else spawn him on it: + if grim_cant_walk_to_use_tile then + grim_spawn_idle_direction = spawn_scenario[6] + grim_x = grim_use_tile_x + grim_y = grim_use_tile_y + end + return true + end + return false + end + + local usable_scenario_found = false + for _, spawn_scenario in ipairs(spawn_scenarios) do + if not usable_scenario_found then + usable_scenario_found = tryToUseHellDeathSpawnScenario(spawn_scenario) + end + end + if not usable_scenario_found then + action_die_tick(humanoid) + return + end + + --Spawn the grim reaper and the lava hole: + local lava_hole = humanoid.world:newObject("gates_to_hell", hole_x, hole_y, holes_orientation) + local grim_reaper = humanoid.world:newEntity("GrimReaper", 1660) + + local point_dir = {x = grim_x, y = grim_y, direction = grim_spawn_idle_direction} + grim_reaper:setNextAction(IdleSpawnAction(1660, point_dir):setCount(40)) + + --Initialise the grim reaper: + grim_reaper:setHospital(humanoid.world:getLocalPlayerHospital()) + grim_reaper.lava_hole = lava_hole + grim_reaper.lava_hole.orientation = holes_orientation + grim_reaper.use_tile_x = grim_use_tile_x + grim_reaper.use_tile_y = grim_use_tile_y + grim_reaper.mirror = mirror_grim + grim_reaper.patient = humanoid + humanoid.grim_reaper = grim_reaper + + action.phase = 3 + action_die_tick_reaper(humanoid) + + --3: The grim reaper walks to his lava hole use tile and then stands idle waiting for phase 6: + elseif phase == 3 then + action.phase = 4 + local grim = humanoid.grim_reaper + if grim.tile_x ~= grim.use_tile_x or grim.tile_y ~= grim.use_tile_y then + grim:queueAction(WalkAction(grim.use_tile_x, grim.use_tile_y):disableTruncate()) + end + + local loop_callback_wait = --[[persistable:reaper_wait]]function() + grim:setAnimation(1002, grim.mirror) + action_die_tick_reaper(humanoid) + end + grim:queueAction(IdleAction():setLoopCallback(loop_callback_wait)) + + --4: There will be a brief pause before the patient stands up: + elseif phase == 4 then + action.phase = 5 + humanoid:setTimer(20, action_die_tick_reaper) + + -- 5: The dead patient will now stand up: + elseif phase == 5 then + action.phase = 6 + humanoid:setTimer(humanoid.world:getAnimLength(humanoid.die_anims.rise_hell_east), action_die_tick_reaper) + humanoid:setAnimation(humanoid.die_anims.rise_hell_east, mirror) + + --6: The dead patient will now walk in to the lava hole, falling in as the grim reaper does his "sending patient to hell" animation: + elseif phase == 6 then + local grim = humanoid.grim_reaper + local lava_hole = grim.lava_hole + --The grim reaper's final actions: + local loop_callback_swipe =--[[persistable:reaper_swipe]]function() + grim:setAnimation(1670, grim.mirror) + end + grim:queueAction(IdleAction():setCount(grim.world:getAnimLength(1670)):setLoopCallback(loop_callback_swipe)) + + local loop_callback_leave =--[[persistable:reaper_leave]]function() + grim:setAnimation(1678, grim.mirror) + end + grim:queueAction(IdleAction():setCount(grim.world:getAnimLength(1678)):setLoopCallback(loop_callback_leave)) + + local lava_destroy = --[[persistable:lava_destroy]]function() + humanoid.world:destroyEntity(lava_hole) + end + local loop_callback_destroy =--[[persistable:reaper_destroy]]function() + lava_hole.playing_sounds_in_random_sequence = false + lava_hole:setTimer(lava_hole.world:getAnimLength(2552), lava_destroy) + lava_hole:setAnimation(2552) + grim.world:destroyEntity(grim) + end + grim:queueAction(IdleAction():setLoopCallback(loop_callback_destroy)) + + --The patient's final actions: + humanoid:walkTo(humanoid.hole_use_tile_x, humanoid.hole_use_tile_y, true) + + local post_walk_into = --[[persistable:walk_into_lava]]function() + grim:finishAction() + end + + local use_action = UseObjectAction(lava_hole) + use_action.destroy_user_after_use = true + use_action.after_walk_in = post_walk_into + humanoid:queueAction(use_action) + humanoid:finishAction() + end +end) + local function action_die_start(action, humanoid) humanoid:setMoodInfo() -- clear all mood icons + local preferred_fall_direction if math.random(0, 1) == 1 then - humanoid.last_move_direction = "east" + preferred_fall_direction = "east" else - humanoid.last_move_direction = "south" + preferred_fall_direction = "south" end - local direction = humanoid.last_move_direction local anims = humanoid.die_anims assert(anims, "Error: no death animation for humanoid ".. humanoid.humanoid_class) action.must_happen = true @@ -77,13 +264,31 @@ --If this isn't done their bald head will become bloated instead of suddenly having hair: if humanoid.disease.id == "baldness" then humanoid:setLayer(0,2) end - if direction == "east" then - humanoid:setAnimation(anims.fall_east, 0) - elseif direction == "south" then - humanoid:setAnimation(anims.fall_east, 1) - end + local mirror_fall = preferred_fall_direction == "east" and 0 or 1 + humanoid.last_move_direction = preferred_fall_direction + + humanoid:setAnimation(anims.fall_east, mirror_fall) + action.phase = 0 - humanoid:setTimer(humanoid.world:getAnimLength(fall), action_die_tick) + + local fall_anim_duration = humanoid.world:getAnimLength(fall) + if humanoid.humanoid_class == "Chewbacca Patient" then + --After 21 ticks the first frame of the buggy falling part of this animation is reached + --so this animation is ended early, action_die_tick will then use the standard male fall animation: + fall_anim_duration = 21 + end + -- Bloaty head patients can't go to hell because they don't have a + -- "transform to standard male"/"fall into lava hole" animation. + if humanoid:isMalePatient() and humanoid.disease.id ~= "bloaty_head" then + if math.random(1, 100) <= 65 then + humanoid:setTimer(fall_anim_duration, action_die_tick_reaper) + else + humanoid:setTimer(fall_anim_duration, action_die_tick) + end + else + humanoid:setTimer(fall_anim_duration, action_die_tick) + end + humanoid.dead = true end return action_die_start diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/falling.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/falling.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/falling.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/falling.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "FallingAction" (HumanoidAction) + +---@type FallingAction +local FallingAction = _G["FallingAction"] + +function FallingAction:FallingAction() + self:HumanoidAction("falling") + self.setMustHappen(true) +end + local action_falling_end = permanent"action_falling_end"( function(humanoid) humanoid:finishAction() end) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/get_up.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/get_up.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/get_up.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/get_up.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "GetUpAction" (HumanoidAction) + +---@type GetUpAction +local GetUpAction = _G["GetUpAction"] + +function GetUpAction:GetUpAction() + self:HumanoidAction("get_up") +end + local action_get_up_end = permanent"action_get_up_end"( function(humanoid) humanoid:finishAction() end) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/idle.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/idle.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/idle.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/idle.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,12 +18,47 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "IdleAction" (HumanoidAction) + +---@type IdleAction +local IdleAction = _G["IdleAction"] + +function IdleAction:IdleAction() + self:HumanoidAction("idle") + self.direction = nil -- Direction of standing idle. + self.on_interrupt = nil -- Function to call at an interrupt. +end + +--! Set the direction of facing while standing idle. +--!param direction (string) Direction of facing. +--!return (action) Self, for daisy-chaining. +function IdleAction:setDirection(direction) + assert(direction == nil or + direction == "north" or direction == "south" or + direction == "east" or direction == "west", + "Invalid value for parameter 'direction'") + + self.direction = direction + return self +end + +--! Set the function to call on interrupt. +--!param on_interrupt (function) Function to call on interrupt. +--!return (action) Self, for daisy-chaining. +function IdleAction:setOnInterrupt(on_interrupt) + assert(on_interrupt == nil or type(on_interrupt) == "function", + "Invalid value for parameter 'on_interrupt'") + + self.on_interrupt = on_interrupt + return self +end + local action_idle_interrupt = permanent"action_idle_interrupt"( function(action, humanoid) humanoid:setTimer(1, humanoid.finishAction) end) local action_timer = permanent"action_idle_timer"( function(humanoid) - local action = humanoid.action_queue[1] + local action = humanoid:getCurrentAction() if action.after_use then action.after_use() action.must_happen = true @@ -49,7 +84,8 @@ humanoid:setTimer(action.count, action_timer) action.must_happen = true end - if action.must_happen then + -- If an interrupt is already specified for the idle action don't replace it + if action.must_happen and not action.on_interrupt then action.on_interrupt = action_idle_interrupt end if action.loop_callback then diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/idle_spawn.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/idle_spawn.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/idle_spawn.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/idle_spawn.lua 2018-07-21 11:13:17.000000000 +0000 @@ -17,6 +17,25 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] + +class "IdleSpawnAction" (HumanoidAction) + +---@type IdleSpawnAction +local IdleSpawnAction = _G["IdleSpawnAction"] + +function IdleSpawnAction:IdleSpawnAction(anim, point_dir) + assert(type(anim) == "number", "Invalid value for parameter 'anim'") + assert(type(point_dir) == "table" and + type(point_dir.x) == "number" and type(point_dir.y) == "number" and + point_dir.direction == "north" or point_dir.direction == "south" or + point_dir.direction == "east" or point_dir.direction == "west", + "Invalid value for parameter 'point_dir'") + + self:HumanoidAction("idle_spawn") + self.spawn_animation = anim + self.point = point_dir -- x, y, direction of the spawn animation +end + local function action_idle_spawn_start(action, humanoid) action.must_happen = true @@ -24,17 +43,19 @@ humanoid:setTilePositionSpeed(action.point.x,action.point.y) if action.spawn_animation then - humanoid:queueAction({name="idle",count = humanoid.world:getAnimLength(action.spawn_animation), - loop_callback=--[[persistable:idle_spawn_animation]] - function() - if action.spawn_sound then humanoid:playSound(action.spawn_sound) end - humanoid:setAnimation(action.spawn_animation) - end}) + local loop_callback_spawn =--[[persistable:idle_spawn_animation]] function() + if action.spawn_sound then humanoid:playSound(action.spawn_sound) end + humanoid:setAnimation(action.spawn_animation) + end + + humanoid:queueAction(IdleAction():setCount(humanoid.world:getAnimLength(action.spawn_animation)) + :setLoopCallback(loop_callback_spawn)) + elseif action.spawn_sound then humanoid:playSound(action.spawn_sound) end - humanoid:queueAction({name="idle",count = action.count,loop_callback = action.loop_callback}) + humanoid:queueAction(IdleAction():setCount(action.count):setLoopCallback(action.loop_callback)) humanoid:finishAction() end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/knock_door.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/knock_door.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/knock_door.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/knock_door.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,25 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "KnockDoorAction" (HumanoidAction) + +---@type KnockDoorAction +local KnockDoorAction = _G["KnockDoorAction"] + +--! Constructor for knocking on the door action. +--!param door (Object) Door to knock on. +--!param direction (string) Direction of facing. +function KnockDoorAction:KnockDoorAction(door, direction) + assert(class.is(door, Door), "Invalid value for parameter 'door'") + assert(direction == "north" or direction == "south" or + direction == "east" or direction == "west", + "Invalid value for parameter 'direction'") + + self:HumanoidAction("knock_door") + self.door = door -- Door to knock on. + self.direction = direction -- Direction of facing. +end + local action_knock_door_tick = permanent"action_knock_door_tick"( function(humanoid) local door = humanoid.user_of door:removeUser(humanoid) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/meander.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/meander.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/meander.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/meander.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "MeanderAction" (HumanoidAction) + +---@type MeanderAction +local MeanderAction = _G["MeanderAction"] + +function MeanderAction:MeanderAction() + self:HumanoidAction("meander") +end + local function meander_action_start(action, humanoid) local room = humanoid:getRoom() -- Answering call queue @@ -31,18 +40,18 @@ -- staff room visit elseif humanoid.world.dispatcher:answerCall(humanoid) then if action.must_happen then - humanoid:finishAction() - end - return + humanoid:finishAction() + end + return else -- Nowhere to go, start going to the old room if it's still in -- need of staff. - local room = humanoid.last_room - if room and room.is_active - and room:testStaffCriteria(room:getMaximumStaffCriteria(), humanoid) then - humanoid:queueAction(room:createEnterAction(humanoid)) + local last_room = humanoid.last_room + if last_room and last_room.is_active and + last_room:testStaffCriteria(last_room:getMaximumStaffCriteria(), humanoid) then + humanoid:queueAction(last_room:createEnterAction(humanoid)) humanoid:setDynamicInfoText(_S.dynamic_info.staff.actions.heading_for - :format(room.room_info.name)) + :format(last_room.room_info.name)) humanoid:finishAction() return end @@ -57,11 +66,12 @@ end end local x, y = humanoid.world.pathfinder:findIdleTile(humanoid.tile_x, - humanoid.tile_y, math.random(1, 24)) + humanoid.tile_y, math.random(1, 24)) + if x == humanoid.tile_x and y == humanoid.tile_y then -- Nowhere to walk to - go idle instead, or go onto the next action if #humanoid.action_queue == 1 then - humanoid:queueAction{name = "idle"} + humanoid:queueAction(IdleAction()) end humanoid:finishAction() return @@ -79,18 +89,19 @@ end elseif action.loop_callback then action.loop_callback() - if action ~= humanoid.action_queue[1] then + if action ~= humanoid:getCurrentAction() then return end end + local procrastination - if action.can_idle and math.random(1, 3) == 1 then - procrastination = {name = "idle", count = math.random(25, 40)} + if action.can_idle then + action.can_idle = false + procrastination = IdleAction():setCount(math.random(5, 40)):setMustHappen(action.must_happen) else action.can_idle = true - procrastination = {name = "walk", x = x, y = y} + procrastination = WalkAction(x, y):setMustHappen(action.must_happen) end - procrastination.must_happen = action.must_happen humanoid:queueAction(procrastination, 0) end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/multi_use_object.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/multi_use_object.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/multi_use_object.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/multi_use_object.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,7 +18,59 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +class "MultiUseObjectAction" (HumanoidAction) + +---@type MultiUseObjectAction +local MultiUseObjectAction = _G["MultiUseObjectAction"] + +--! Construct a multi-use object action. +--!param object (Object) Object being used. +--!param use_with (Humanoid) Fellow user of the object. +function MultiUseObjectAction:MultiUseObjectAction(object, use_with) + assert(class.is(object, Object), "Invalid value for parameter 'object'") + assert(class.is(use_with, Humanoid), "Invalid value for parameter 'use_with'") + + self:HumanoidAction("multi_use_object") + self.object = object + self.use_with = use_with + self.prolonged_usage = nil -- If true, the usage is prolonged. + self.layer3 = nil +end + +--! Set the invisibility span. +--!param span (array) Span of invisibility, {from, to} +--!return (action) self, for daisy-chaining. +function MultiUseObjectAction:setInvisiblePhaseSpan(span) + assert(type(span) == "table" and type(span[1]) == "number" and + type(span[2] == "number") and span[1] <= span[2], + "Invalid value for parameter 'span'") + + self.invisible_phase_span = span + return self +end + +--! Set prolonged usage of the object. +--!param prolonged (bool) If set, enable prolonged usage of the object. +--!return (action) self, for daisy-chaining. +function MultiUseObjectAction:setProlongedUsage(prolonged) + assert(type(prolonged), "boolean", "Invalid value for parameter 'prolonged'") + + self.prolonged_usage = prolonged + return self +end + +-- Set animation layer3 to the given value. +--!param layer3 (int) Value to set for animation layer 3. +--!return (action) self, for daisy-chaining. +function MultiUseObjectAction:setLayer3(layer3) + assert(type(layer3) == "number", "Invalid value for parameter 'layer3'") + + self.layer3 = layer3 + return self +end + +local TH = require("TH") + local orient_mirror = { north = "west", west = "north", @@ -194,7 +246,7 @@ end action_multi_use_object_tick = permanent"action_multi_use_object_tick"( function(humanoid) - local action = humanoid.action_queue[1] + local action = humanoid:getCurrentAction() local use_with = action.use_with local object = action.object local phase = action.phase @@ -248,8 +300,8 @@ end use_with.th:makeVisible() - use_with.action_queue[1].on_interrupt = action.idle_interrupt - use_with.action_queue[1].must_happen = action.idle_must_happen + use_with:getCurrentAction().on_interrupt = action.idle_interrupt + use_with:getCurrentAction().must_happen = action.idle_must_happen local spec = object.object_type.orientations[object.direction] local pos = spec.finish_use_position or spec.use_position humanoid:setTilePositionSpeed(object.tile_x + pos[1], object.tile_y + pos[2]) @@ -287,19 +339,19 @@ return end end - if use_with.action_queue[1].name ~= "idle" then - humanoid:queueAction({name = "idle", count = 2}, 0) + if use_with:getCurrentAction().name ~= "idle" then + humanoid:queueAction(IdleAction():setCount(2), 0) return else - action.idle_interrupt = use_with.action_queue[1].on_interrupt - action.idle_must_happen = use_with.action_queue[1].must_happen - use_with.action_queue[1].on_interrupt = nil - use_with.action_queue[1].must_happen = true + action.idle_interrupt = use_with:getCurrentAction().on_interrupt + action.idle_must_happen = use_with:getCurrentAction().must_happen + use_with:getCurrentAction().on_interrupt = nil + use_with:getCurrentAction().must_happen = true end action.must_happen = true if action.prolonged_usage then action.on_interrupt = action_multi_use_object_interrupt - use_with.action_queue[1].on_interrupt = --[[persistable:action_multi_use_object_use_with_interrupt]] function() + use_with:getCurrentAction().on_interrupt = --[[persistable:action_multi_use_object_use_with_interrupt]] function() if action.on_interrupt then action:on_interrupt() action.on_interrupt = nil diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/on_ground.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/on_ground.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/on_ground.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/on_ground.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "OnGroundAction" (HumanoidAction) + +---@type OnGroundAction +local OnGroundAction = _G["OnGroundAction"] + +function OnGroundAction:OnGroundAction() + self:HumanoidAction("on_ground") +end + local action_on_ground_end = permanent"action_on_ground_end"( function(humanoid) humanoid:finishAction() end) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/pee.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/pee.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/pee.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/pee.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "PeeAction" (HumanoidAction) + +---@type PeeAction +local PeeAction = _G["PeeAction"] + +function PeeAction:PeeAction() + self:HumanoidAction("pee") + self:setMustHappen(true) +end + local action_pee_end = permanent"action_pee_end"( function(humanoid) local litter = humanoid.world:newObject("litter", humanoid.tile_x, humanoid.tile_y) litter:setLitterType("pee", humanoid.last_move_direction == "south" and 0 or 1) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/pickup.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/pickup.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/pickup.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/pickup.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,29 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "PickupAction" (HumanoidAction) + +---@type PickupAction +local PickupAction = _G["PickupAction"] + +-- Construct a pick-up action +--!param ui User interface +function PickupAction:PickupAction(ui) + assert(class.is(ui, UI), "Invalid value for parameter 'ui'") + + self:HumanoidAction("pickup") + self.ui = ui + self.todo_close = nil + self:setMustHappen(true) +end + +function PickupAction:setTodoClose(dialog) + assert(class.is(dialog, Window), "Invalid value for parameter 'dialog'") + + self.todo_close = dialog + return self +end + local action_pickup_interrupt = permanent"action_pickup_interrupt"( function(action, humanoid) if action.window then action.window:close() @@ -72,7 +95,7 @@ local ui = action.ui action.window = UIPlaceStaff(ui, humanoid, ui.cursor_x, ui.cursor_y) ui:addWindow(action.window) - ui:playSound "pickup.wav" + ui:playSound("pickup.wav") ui:setDefaultCursor(ui.grab_cursor) end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/queue.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/queue.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/queue.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/queue.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,52 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "QueueAction" (HumanoidAction) + +---@type QueueAction +local QueueAction = _G["QueueAction"] + +--! Queue for something (door or reception desk). +--!param x X position of the queue. +--!param y Y position of the queue. +--!param queue (Queue) Queue to join +function QueueAction:QueueAction(x, y, queue) + assert(type(x) == "number", "Invalid value for parameter 'x'") + assert(type(y) == "number", "Invalid value for parameter 'y'") + assert(class.is(queue, Queue), "Invalid value for parameter 'queue'") + + self:HumanoidAction("queue") + self.x = x -- Position of the queue(?) + self.y = y + self.face_x = nil -- Tile to turn the face to. + self.face_y = nil + self.queue = queue + self.reserve_when_done = nil -- Object to reserve when leaving the queue. +end + +--! Set the object to reserve when queueing is done. +--!param door (object) Object to reserve when leaving the queue. +--!return (action) self, for daisy-chaining. +function QueueAction:setReserveWhenDone(door) + assert(class.is(door, Door), "Invalid value for parameter 'door'") + + self.reserve_when_done = door + return self +end + +--! Set the tile to face. +--!param face_x (int) X coordinate of the tile to face. +--!param face_y (int) Y coordinate of the tile to face. +--!return (action) self, for daisy-chaining. +function QueueAction:setFaceDirection(face_x, face_y) + assert(type(face_x) == "number", "Invalid value for parameter 'face_x'") + assert(type(face_y) == "number", "Invalid value for parameter 'face_y'") + + self.face_x = face_x + self.face_y = face_y + return self +end + local function get_direction(x, y, facing_x, facing_y) if facing_y < y then return "north" @@ -68,10 +114,9 @@ end end if found_any then - error "Proper idle not in action_queue" - else - return -1 + print("Warning: Proper idle not in action_queue") end + return -1 end local function action_queue_find_drink_action(action, humanoid) @@ -85,7 +130,7 @@ end end if found_any then - error "Proper drink action not in action_queue" + error("Proper drink action not in action_queue") else return -1 end @@ -100,24 +145,24 @@ if index == -1 then -- Attempt to recover by assuming the person is sitting down. print("Warning: Idle not in action_queue") - if humanoid.action_queue[1].name == "use_object" then + if humanoid:getCurrentAction().name == "use_object" then -- It is likely that the person is sitting down. return action_queue_leave_bench(action, humanoid) else - error "This person seems to neither be standing nor sitting?!" + error("This person seems to neither be standing nor sitting?!") end end end interrupt_head(humanoid, index) index = index + 1 - while true do + while index >= 1 do local current_action = humanoid.action_queue[index] if current_action == action then return index - 1 end index = index - 1 end - error "Queue action not in action_queue" + error("Queue action not in action_queue") end local function action_queue_leave_bench(action, humanoid) @@ -141,19 +186,25 @@ end end index = index + 1 - while true do + while index >= 1 do local current_action = humanoid.action_queue[index] if current_action == action then return index - 1 end index = index - 1 end - error "Queue action not in action_queue" + error("Queue action not in action_queue") end local action_queue_on_change_position = permanent"action_queue_on_change_position"( function(action, humanoid) - -- Find out if we have to be standing up - local must_stand = class.is(humanoid, Staff) or class.is(humanoid, Vip) or (humanoid.disease and humanoid.disease.must_stand) + -- Only proceed with this handler if the patient is still in the queue + if not action.is_in_queue then + return + end + + -- Find out if we have to be standing up - considering humanoid_class covers both health inspector and VIP + local must_stand = class.is(humanoid, Staff) or humanoid.humanoid_class == "Inspector" or + humanoid.humanoid_class == "VIP" or (humanoid.disease and humanoid.disease.must_stand) local queue = action.queue if not must_stand then for i = 1, queue.bench_threshold do @@ -181,17 +232,8 @@ num_actions_prior = action_queue_leave_bench(action, humanoid) end action.current_bench_distance = dist - humanoid:queueAction({ - name = "walk", - x = bx, - y = by, - must_happen = true, - }, num_actions_prior) - humanoid:queueAction({ - name = "use_object", - object = bench, - must_happen = true, - }, num_actions_prior + 1) + humanoid:queueAction(WalkAction(bx, by):setMustHappen(true), num_actions_prior) + humanoid:queueAction(UseObjectAction(bench):setMustHappen(true), num_actions_prior + 1) bench.reserved_for = humanoid return elseif not action:isStanding() then @@ -203,7 +245,7 @@ -- Stand up in the correct position in the queue local standing_index = 0 local our_room = humanoid:getRoom() - for i, person in ipairs(queue) do + for _, person in ipairs(queue) do if person == humanoid then break end @@ -229,30 +271,17 @@ -- Going to get a drink. Do nothing since it will be fixed after getting the drink. return else - error "Could not find an idle or drink action when trying to stand in line." + error("Could not find an idle or drink action when trying to stand in line.") end end humanoid.action_queue[idle_index].direction = idle_direction - humanoid:queueAction({ - name = "walk", - x = ix, - y = iy, - must_happen = true, - }, idle_index - 1) + humanoid:queueAction(WalkAction(ix, iy):setMustHappen(true), idle_index - 1) else action.current_bench_distance = nil local num_actions_prior = action_queue_leave_bench(action, humanoid) - humanoid:queueAction({ - name = "walk", - x = ix, - y = iy, - must_happen = true, - }, num_actions_prior) - humanoid:queueAction({ - name = "idle", - direction = idle_direction, - must_happen = true, - }, num_actions_prior + 1) + humanoid:queueAction(WalkAction(ix, iy):setMustHappen(true), num_actions_prior) + humanoid:queueAction(IdleAction():setDirection(idle_direction):setMustHappen(true), + num_actions_prior + 1) end end) @@ -271,7 +300,7 @@ return end end - error "Queue action not in action_queue" + error("Queue action not in action_queue") end) -- While queueing one could get thirsty. @@ -287,31 +316,22 @@ -- Callback function used after the drinks machine has been used. local --[[persistable:action_queue_get_soda_after_use]] function after_use() fun_after_use() -- Defined in patient:tickDay - -- Insert an idle action so that change_position can do its work. + -- If the patient is still in the queue, insert an idle action so that + -- change_position can do its work. -- Note that it is inserted after the currently executing use_object action. - humanoid:queueAction({ - name = "idle", - --direction = machine, - must_happen = true, - }, 1) - action_queue_on_change_position(action, humanoid) + if action.is_in_queue then + humanoid:queueAction(IdleAction():setMustHappen(true), 1) + action_queue_on_change_position(action, humanoid) + end end -- Walk to the machine and then use it. - humanoid:queueAction({ - name = "walk", - x = mx, - y = my, - must_happen = true, - }, num_actions_prior) - humanoid:queueAction({ - name = "use_object", - object = machine, - after_use = after_use, - must_happen = true, - }, num_actions_prior + 1) + humanoid:queueAction(WalkAction(mx, my):setMustHappen(true), num_actions_prior) + humanoid:queueAction(UseObjectAction(machine):setAfterUse(after_use) + :setMustHappen(true), num_actions_prior + 1) machine:addReservedUser(humanoid) - -- Make sure noone thinks we're sitting down anymore. + + -- Make sure no one thinks we're sitting down anymore. action.current_bench_distance = nil end) @@ -355,10 +375,7 @@ humanoid:updateDynamicInfo(_S.dynamic_info.patient.actions.queueing_for:format(door.room.room_info.name)) end end - humanoid:queueAction({ - name = "idle", - must_happen = true, - }, 0) + humanoid:queueAction(IdleAction():setMustHappen(true):setIsLeaving(humanoid:isLeaving()), 0) action:onChangeQueuePosition(humanoid) if queue.same_room_priority then diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/seek_reception.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/seek_reception.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/seek_reception.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/seek_reception.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,20 +18,31 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local flag_cache = {} -local function can_join_queue_at(humanoid, x, y, use_x, use_y) - return humanoid.world.map.th:getCellFlags(x, y, flag_cache).hospital - and (not flag_cache.room) +class "SeekReceptionAction" (HumanoidAction) + +---@type SeekReceptionAction +local SeekReceptionAction = _G["SeekReceptionAction"] + +function SeekReceptionAction:SeekReceptionAction() + self:HumanoidAction("seek_reception") +end + +local function can_join_queue_at(humanoid, x, y) + local flag_cache = humanoid.world.map.th:getCellFlags(x, y) + return flag_cache.hospital and not flag_cache.room and + humanoid.hospital and + flag_cache.owner == humanoid.hospital:getPlayerIndex() end local function action_seek_reception_start(action, humanoid) local world = humanoid.world - local best_desk local score + assert(humanoid.hospital, "humanoid must be associated with a hospital to seek reception") + -- Go through all receptions desks. - for desk, _ in pairs(humanoid.hospital.reception_desks) do + for _, desk in ipairs(humanoid.hospital:findReceptionDesks()) do if (not desk.receptionist and not desk.reserved_for) then -- Not an allowed reception desk to go to. else @@ -64,24 +75,17 @@ -- We don't want patients which have just spawned to be joining the queue -- immediately, so walk them closer to the desk before joining the queue - if can_join_queue_at(humanoid, humanoid.tile_x, humanoid.tile_y, x, y) then + if can_join_queue_at(humanoid, humanoid.tile_x, humanoid.tile_y) then local face_x, face_y = best_desk:getSecondaryUsageTile() - humanoid:setNextAction{ - name = "queue", - x = x, - y = y, - queue = best_desk.queue, - face_x = face_x, - face_y = face_y, - must_happen = action.must_happen, - } + humanoid:setNextAction(QueueAction(x, y, best_desk.queue):setMustHappen(action.must_happen) + :setFaceDirection(face_x, face_y)) else - local walk = {name = "walk", x = x, y = y, must_happen = action.must_happen} + local walk = WalkAction(x, y):setMustHappen(action.must_happen) humanoid:queueAction(walk, 0) -- Trim the walk to finish once it is possible to join the queue for i = #walk.path_x, 2, -1 do - if can_join_queue_at(humanoid, walk.path_x[i], walk.path_y[i], x, y) then + if can_join_queue_at(humanoid, walk.path_x[i], walk.path_y[i]) then walk.path_x[i + 1] = nil walk.path_y[i + 1] = nil else @@ -93,17 +97,16 @@ -- No reception desk found. One will probably be built soon, somewhere in -- the hospital, so either walk to the hospital, or walk around the hospital. local procrastination - if world.map.th:getCellFlags(humanoid.tile_x, humanoid.tile_y).hospital then - procrastination = {name = "meander", count = 1} + if humanoid.hospital:isInHospital(humanoid.tile_x, humanoid.tile_y) then + procrastination = MeanderAction():setCount(1):setMustHappen(action.must_happen) if not humanoid.waiting then -- Eventually people are going to get bored and leave. humanoid.waiting = 5 end else local _, hosp_x, hosp_y = world.pathfinder:isReachableFromHospital(humanoid.tile_x, humanoid.tile_y) - procrastination = {name = "walk", x = hosp_x, y = hosp_y} + procrastination = WalkAction(hosp_x, hosp_y):setMustHappen(action.must_happen) end - procrastination.must_happen = action.must_happen humanoid:queueAction(procrastination, 0) end end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/seek_room.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/seek_room.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/seek_room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/seek_room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "SeekRoomAction" (HumanoidAction) + +---@type SeekRoomAction +local SeekRoomAction = _G["SeekRoomAction"] + +--! Find another room (and go to it). +--!param room_type Type of the new room. +function SeekRoomAction:SeekRoomAction(room_type) + assert(type(room_type) == "string", "Invalid value for parameter 'room_type'") + + self:HumanoidAction("seek_room") + self.room_type = room_type + self.treatment_room = nil -- Whether the next room is a treatment room. + self.diagnosis_room = nil +end + +--! Denote that the room being looked for is a treatment room. +--!return (action) self, for daisy-chaining. +function SeekRoomAction:enableTreatmentRoom() + self.treatment_room = true + return self +end + +function SeekRoomAction:setDiagnosisRoom(room) + assert(type(room) == "number", "Invalid value for parameter 'room'") + + self.diagnosis_room = room + return self +end + local function action_seek_room_find_room(action, humanoid) local room_type = action.room_type if action.diagnosis_room then @@ -142,10 +172,10 @@ -- Otherwise, depending on hospital policy three things can happen: if humanoid.diagnosis_progress < humanoid.hospital.policies["send_home"] then -- Send home automatically - humanoid:goHome() + humanoid:goHome("kicked") humanoid:updateDynamicInfo(_S.dynamic_info.patient.actions.no_diagnoses_available) - elseif humanoid.diagnosis_progress < humanoid.hospital.policies["guess_cure"] - or not humanoid.hospital.disease_casebook[humanoid.disease.id].discovered then + elseif humanoid.diagnosis_progress < humanoid.hospital.policies["guess_cure"] or + not humanoid.hospital.disease_casebook[humanoid.disease.id].discovered then -- If the disease hasn't been discovered yet it cannot be guessed, go here instead. -- Ask the player -- Wait two months before going home anyway. @@ -174,12 +204,18 @@ -- Guess "type of disease" automatically. -- A patient with an undiscovered disease should never get here. assert(humanoid.hospital.disease_casebook[humanoid.disease.id].discovered) - humanoid:setDiagnosed(true) - humanoid:queueAction({ - name = "seek_room", - room_type = humanoid.disease.treatment_rooms[1], - treatment_room = true, - }, 1) + humanoid:setDiagnosed() + humanoid:unregisterRoomBuildCallback(action.build_callback) + humanoid:unregisterRoomRemoveCallback(action.remove_callback) + if humanoid:agreesToPay(humanoid.disease.id) then + humanoid:queueAction({ + name = "seek_room", + room_type = humanoid.disease.treatment_rooms[1], + treatment_room = true, + }, 1) + else + humanoid:goHome("over_priced", humanoid.disease.id) + end humanoid:finishAction() end end @@ -205,7 +241,7 @@ end -- Seeking for toilets is a special case with its own action. if action.room_type == "toilets" then - humanoid:queueAction({name = "seek_toilets"}, 1) + humanoid:queueAction(SeekToiletsAction(), 1) humanoid:finishAction() return end @@ -219,8 +255,8 @@ action.done_init = true action.must_happen = true - local remove_callback = --[[persistable:action_seek_room_remove_callback]] function(room) - if room.room_info.id == "research" then + local remove_callback = --[[persistable:action_seek_room_remove_callback]] function(rm) + if rm.room_info.id == "research" then humanoid:updateMessage("research") end end -- End of remove_callback function @@ -228,16 +264,16 @@ humanoid:registerRoomRemoveCallback(remove_callback) local build_callback - build_callback = --[[persistable:action_seek_room_build_callback]] function(room) + build_callback = --[[persistable:action_seek_room_build_callback]] function(rm) -- if research room was built, message may need to be updated - if room.room_info.id == "research" then + if rm.room_info.id == "research" then humanoid:updateMessage("research") end local found = false - if room.room_info.id == action.room_type then + if rm.room_info.id == action.room_type then found = true - elseif room.room_info.id == action.room_type_needed then + elseif rm.room_info.id == action.room_type_needed then -- So the room that we're going to is not actually the room we waited for to be built. -- Example: Will go to ward, but is waiting for the operating theatre. -- Clean up and start over to find the room we actually want to go to. @@ -250,14 +286,21 @@ -- Waiting for a diagnosis room, we need to go through the list - unless it is gp if action.room_type ~= "gp" then for i = 1, #humanoid.available_diagnosis_rooms do - if humanoid.available_diagnosis_rooms[i].id == room.room_info.id then + if humanoid.available_diagnosis_rooms[i].id == rm.room_info.id then found = true end end end end if found then - action_seek_room_goto_room(room, humanoid, action.diagnosis_room) + -- Don't add a "go to room" action to the patient's queue if the + -- autopsy machine is about to kill them: + local current_room = humanoid:getRoom() + if not current_room or not (current_room.room_info.id == "research" and + current_room:getStaffMember() and + current_room:getStaffMember():getCurrentAction().name == "multi_use_object") then + action_seek_room_goto_room(rm, humanoid, action.diagnosis_room) + end TheApp.ui.bottom_panel:removeMessage(humanoid) humanoid:unregisterRoomBuildCallback(build_callback) humanoid:unregisterRoomRemoveCallback(remove_callback) @@ -295,7 +338,7 @@ end if action_still_valid then action.done_walk = true - humanoid:queueAction({name = "meander", count = 1, must_happen = true}, 0) + humanoid:queueAction(MeanderAction():setCount(1):setMustHappen(true), 0) end else -- Make sure the patient stands in a correct way as he/she is waiting. diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/seek_staffroom.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/seek_staffroom.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/seek_staffroom.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/seek_staffroom.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "SeekStaffRoomAction" (HumanoidAction) + +---@type SeekStaffRoomAction +local SeekStaffRoomAction = _G["SeekStaffRoomAction"] + +function SeekStaffRoomAction:SeekStaffRoomAction() + self:HumanoidAction("seek_staffroom") + self:setMustHappen(true) +end + local function seek_staffroom_action_start(action, humanoid) -- Mechanism for clearing the going_to_staffroom flag when this action is -- interrupted (due to entering the staff room, being picked up, etc.) @@ -30,16 +40,14 @@ -- Go to the nearest staff room, if any is found. local room = humanoid.world:findRoomNear(humanoid, "staff_room") if room then - local task = room:createEnterAction(humanoid) - task.must_happen = true - task.is_leaving = true + local task = room:createEnterAction(humanoid):setMustHappen(true):setIsLeaving(true) humanoid:queueAction(task, 0) humanoid:setDynamicInfoText(_S.dynamic_info.staff.actions.heading_for:format(room.room_info.name)) else -- This should happen only in rare cases, e.g. if the target staff room was removed while heading there and none other exists print("No staff room found in seek_staffroom action") humanoid.going_to_staffroom = nil - humanoid:queueAction({name = "meander"}) + humanoid:queueAction(MeanderAction()) humanoid:finishAction() end end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/seek_toilets.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/seek_toilets.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/seek_toilets.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/seek_toilets.lua 2018-07-21 11:13:17.000000000 +0000 @@ -19,12 +19,21 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "SeekToiletsAction" (HumanoidAction) + +---@type SeekToiletsAction +local SeekToiletsAction = _G["SeekToiletsAction"] + +function SeekToiletsAction:SeekToiletsAction() + self:HumanoidAction("seek_toilets") +end + local function seek_toilets_action_start(action, humanoid) -- Mechanism for clearing the going_to_toilets flag when this action is -- interrupted. if action.todo_interrupt then - humanoid.going_to_toilet = nil + humanoid.going_to_toilet = "no" humanoid:finishAction() return end @@ -33,9 +42,7 @@ -- Go to the nearest toilet, if any is found. local room = humanoid.world:findRoomNear(humanoid, "toilets", nil, "advanced") if room then - local task = room:createEnterAction(humanoid) - task.must_happen = true - humanoid:setNextAction(task) + humanoid:setNextAction(room:createEnterAction(humanoid):setMustHappen(true)) -- Unexpect the patient from a possible destination room. if humanoid.next_room_to_visit then local queue = humanoid.next_room_to_visit.door.queue @@ -50,11 +57,11 @@ -- removed while heading there and none other exists. In that case, go back -- to the previous room or go to the reception. if humanoid.next_room_to_visit then - humanoid:setNextAction{name = "seek_room", room_type = humanoid.next_room_to_visit.room_info.id} + humanoid:setNextAction(SeekRoomAction(humanoid.next_room_to_visit.room_info.id)) else - humanoid:queueAction{name = "seek_reception"} + humanoid:queueAction(SeekReceptionAction()) end - humanoid.going_to_toilet = nil + humanoid.going_to_toilet = "no" humanoid:finishAction() end end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/shake_fist.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/shake_fist.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/shake_fist.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/shake_fist.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "ShakeFistAction" (HumanoidAction) + +---@type ShakeFistAction +local ShakeFistAction = _G["ShakeFistAction"] + +function ShakeFistAction:ShakeFistAction() + self:HumanoidAction("shake_fist") + self:setMustHappen(true) +end + local action_shake_fist_end = permanent"action_shake_fist_end"( function(humanoid) humanoid:finishAction() end) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/spawn.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/spawn.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/spawn.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/spawn.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,45 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "SpawnAction" (HumanoidAction) + +---@type SpawnAction +local SpawnAction = _G["SpawnAction"] + +--! Spawn an entity. +--!param mode (str) Mode of spawning: "spawn" or "despawn" +--!param point (table x, y, optional direction) Position and optional face direction of spawning or despawning. +function SpawnAction:SpawnAction(mode, point) + assert(mode == "spawn" or mode == "despawn", "Invalid value for parameter 'mode'") + assert(type(point) == "table" and + type(point.x) == "number" and type(point.y) == "number", + "Invalid value for parameter 'point'") + + self:HumanoidAction("spawn") + self.mode = mode -- mode of spawning: "spawn" or "despawn" + self.point = point + self.offset = nil -- Offset in position?? +end + +--! Set the offset of spawning. +--! +--! These two values specifies how many tiles away the humanoid should start +--! walking before actually spawning in the destination tile. Default is x and +--! y values are 2, and should not be set less than or equal to 0. Only one of +--! x or y offsets are used depending on the initial walk direction of the +--! newly spawned humanoid. +--!param offset (table x, y) Position offset. +--!return (action) Return self for daisy chaining. +function SpawnAction:setOffset(offset) + assert(type(offset) == "table" and + (offset.x == nil or (type(offset.x) == "number" and offset.x > 0)) and + (offset.y == nil or (type(offset.y) == "number" and offset.y > 0)), + "Invalid value for parameter 'offset'") + + self.offset = offset + return self +end + local orient_opposite = { north = "south", west = "east", @@ -27,21 +66,16 @@ local action_spawn_despawn = permanent"action_spawn_despawn"( function(humanoid) if humanoid.hospital then - humanoid:setHospital(nil) + humanoid:despawn() end humanoid.world:destroyEntity(humanoid) end) local function action_spawn_start(action, humanoid) assert(action.mode == "spawn" or action.mode == "despawn", "spawn action given invalid mode: " .. action.mode) - local x, y = action.point.x, action.point.y + local x, y = action.point.x, action.point.y if action.mode == "despawn" and (humanoid.tile_x ~= x or humanoid.tile_y ~= y) then - humanoid:queueAction({ - name = "walk", - x = action.point.x, - y = action.point.y, - must_happen = action.must_happen, - }, 0) + humanoid:queueAction(WalkAction(action.point.x, action.point.y):setMustHappen(action.must_happen), 0) return end action.must_happen = true @@ -51,8 +85,6 @@ if action.mode == "spawn" then walk_dir = orient_opposite[walk_dir] end - -- These two values specifies how many tiles away the patient should start walking before actually - -- spawning in the destination tile. Default is 2, and it should not be set to 0. local offset_x = 2 local offset_y = 2 if action.offset then diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/staff_reception.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/staff_reception.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/staff_reception.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/staff_reception.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,21 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "StaffReceptionAction" (HumanoidAction) + +---@type StaffReceptionAction +local StaffReceptionAction = _G["StaffReceptionAction"] + +-- Action class for the "staff reception desk" action. +--!param desk (object) Desk to staff. +function StaffReceptionAction:StaffReceptionAction(desk) + assert(class.is(desk, ReceptionDesk), "Invalid value for parameter 'desk'") + + self:HumanoidAction("staff_reception") + self.object = desk -- Reception desk object. + self:setMustHappen(true) +end + local action_staff_reception_interrupt = permanent"action_staff_reception_interrupt"( function(action, humanoid, high_priority) local object = action.object object.receptionist = nil @@ -38,7 +53,7 @@ end) local action_staff_reception_idle_phase = permanent"action_staff_reception_idle_phase"( function(humanoid) - local action = humanoid.action_queue[1] + local action = humanoid:getCurrentAction() local direction = humanoid.last_move_direction local anims = humanoid.walk_anims local object = action.object diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/sweep_floor.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/sweep_floor.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/sweep_floor.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/sweep_floor.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,18 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "SweepFloorAction" (HumanoidAction) + +---@type SweepFloorAction +local SweepFloorAction = _G["SweepFloorAction"] + +function SweepFloorAction:SweepFloorAction(litter) + assert(class.is(litter, Litter), "Invalid value for parameter 'litter'") + + self:HumanoidAction("sweep_floor") + self.litter = litter +end + -- Set markers for all animations involved. local animation_numbers = { 1874, @@ -30,17 +42,10 @@ end) local remove_litter = permanent"action_sweep_floor_remove_litter"( function(humanoid) - humanoid.world:removeObjectFromTile(humanoid.user_of, humanoid.tile_x, humanoid.tile_y) - humanoid.world:destroyEntity(humanoid.user_of) - humanoid.world.map.th:setCellFlags(humanoid.tile_x, humanoid.tile_y, {buildable = true}) + humanoid.user_of:remove() humanoid.user_of:setTile(nil) humanoid.user_of = nil humanoid:setTimer(humanoid.world:getAnimLength(animation_numbers[2]) * 2, finish) - local hospital = humanoid.world.hospitals[1] - local taskIndex = hospital:getIndexOfTask(humanoid.tile_x, humanoid.tile_y, "cleaning") - if taskIndex ~= -1 then - hospital:removeHandymanTask(taskIndex, "cleaning") - end end) local sweep = permanent"action_sweep_floor_sweep"( function(humanoid) @@ -52,6 +57,11 @@ local function action_sweep_floor_start(action, humanoid) action.must_happen = true humanoid.user_of = action.litter + -- remove handyman task as soon as action starts - we should be committed to completing this task + local litter = action.litter + local hospital = litter.world:getHospital(litter.tile_x, litter.tile_y) + local taskIndex = hospital:getIndexOfTask(litter.tile_x, litter.tile_y, "cleaning", litter) + hospital:removeHandymanTask(taskIndex, "cleaning") local anim = animation_numbers[1] humanoid:setAnimation(anim) humanoid:setTimer(humanoid.world:getAnimLength(anim), sweep) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/tap_foot.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/tap_foot.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/tap_foot.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/tap_foot.lua 2018-07-21 11:13:17.000000000 +0000 @@ -17,11 +17,21 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] + +class "TapFootAction" (HumanoidAction) + +---@type TapFootAction +local TapFootAction = _G["TapFootAction"] + +function TapFootAction:TapFootAction() + self:HumanoidAction("tap_foot") + self:setMustHappen(true) +end + local action_tap_foot_end = permanent"action_tap_foot_end"( function(humanoid) humanoid:finishAction() end) - local function action_tap_foot_start(action, humanoid) if math.random(0, 1) == 1 then humanoid.last_move_direction = "east" diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/use_object.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/use_object.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/use_object.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/use_object.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,7 +18,42 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") + + +class "UseObjectAction" (HumanoidAction) + +---@type UseObjectAction +local UseObjectAction = _G["UseObjectAction"] + +--! Construct a 'use object' action. +--!param object (Object) Object to use. +function UseObjectAction:UseObjectAction(object) + assert(class.is(object, Object), "Invalid value for parameter 'object'") + + self:HumanoidAction("use_object") + self.object = object + self.watering_plant = false -- Whether the action is watering the plant. + self.prolonged_usage = nil -- If true, the usage is prolonged. +end + +--! Set the 'watering plant' flag. +--!return (action) self, for daisy chaining. +function UseObjectAction:enableWateringPlant() + self.watering_plant = true + return self +end + +--! Set prolonged usage of the object. +--!param prolonged (bool or nil) If set, enable prolonged usage of the object. +--!return (action) self, for daisy-chaining. +function UseObjectAction:setProlongedUsage(prolonged) + assert(prolonged == nil or type(prolonged) == "boolean", + "Invalid value for parameter 'prolonged'") + + self.prolonged_usage = prolonged + return self +end local orient_mirror = { north = "west", @@ -68,7 +103,7 @@ if phase == 5 and not action.anims.finish_use_5 then phase = phase + 1 end - if phase == 6 and not action.do_walk then + if phase == 6 and not action.do_walk or phase == 6 and action.destroy_user_after_use then phase = phase + 1 end if phase > 6 then @@ -234,8 +269,8 @@ -- Even it out so that an integer number of animation sequences are done. length = action.min_length + action.min_length % length end - if phase == 0 and (not is_list) and length == 1 and action.prolonged_usage - and action.on_interrupt and not action.loop_callback then + if phase == 0 and (not is_list) and length == 1 and action.prolonged_usage and + action.on_interrupt and not action.loop_callback then -- a timer would be redundant, so do not set one else humanoid:setTimer(length, action_use_object_tick) @@ -271,7 +306,7 @@ end action_use_object_tick = permanent"action_use_object_tick"( function(humanoid) - local action = humanoid.action_queue[1] + local action = humanoid:getCurrentAction() local object = action.object local phase = action.phase local oldphase = phase @@ -279,6 +314,9 @@ object:setUser(humanoid) humanoid.user_of = object init_split_anims(object, humanoid) + if action.after_walk_in then + action:after_walk_in() + end end if phase ~= 0 or not action.prolonged_usage or not action.on_interrupt then phase = action_use_next_phase(action, phase) @@ -314,7 +352,13 @@ if action.after_use then action.after_use() end - humanoid:finishAction(action) + + if action.destroy_user_after_use then + humanoid:despawn() + humanoid.world:destroyEntity(humanoid) + else + humanoid:finishAction(action) + end end else action_use_phase(action, humanoid, phase) @@ -335,6 +379,10 @@ elseif not humanoid.timer_function then humanoid:setTimer(1, action_use_object_tick) end + -- Only patients can be vaccination candidates so no need to check + if humanoid.vaccination_candidate then + humanoid:removeVaccinationCandidateStatus() + end end) local function action_use_object_start(action, humanoid) diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/use_screen.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/use_screen.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/use_screen.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/use_screen.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,13 +18,30 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "UseScreenAction" (HumanoidAction) + +---@type UseScreenAction +local UseScreenAction = _G["UseScreenAction"] + +--! Action to use the screen. +--!param screen (object) Screen to use. +function UseScreenAction:UseScreenAction(screen) + assert(class.is(screen, Object) and ( + screen.object_type.id == "screen" or + screen.object_type.id == "surgeon_screen"), + "Invalid value for parameter 'screen'") + + self:HumanoidAction("use_screen") + self.object = screen +end + local finish = permanent"action_use_screen_finish"( function(humanoid) local screen = humanoid.user_of humanoid.user_of = nil screen:removeUser(humanoid) local offset = screen.object_type.orientations[screen.direction].use_position humanoid:setTile(screen.tile_x + offset[1], screen.tile_y + offset[2]) - local after_use = humanoid.action_queue[1].after_use + local after_use = humanoid:getCurrentAction().after_use if after_use then after_use() end diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/use_staffroom.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/use_staffroom.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/use_staffroom.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/use_staffroom.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "UseStaffRoomAction" (HumanoidAction) + +---@type UseStaffRoomAction +local UseStaffRoomAction = _G["UseStaffRoomAction"] + +function UseStaffRoomAction:UseStaffRoomAction() + self:HumanoidAction("use_staffroom") +end + -- decide on the next source of relaxation the humanoid will go to -- returns target_obj, ox, oy, new_type -- the function will always return a value for new_type, depending on what type was chosen, @@ -81,65 +90,71 @@ action.target_obj.reserved_for = humanoid end else - action.target_obj, action.ox, action.oy, action.target_type = action.next_target_obj, action.next_ox, action.next_oy, action.next_target_type - action.next_target_obj, action.next_ox, action.next_oy, action.next_target_type = nil + action.target_obj = action.next_target_obj + action.ox = action.next_ox + action.oy = action.next_oy + action.target_type = action.next_target_type + + action.next_target_obj = nil + action.next_ox = nil + action.next_oy = nil + action.next_target_type = nil end -- If no target was found, then walk around for a bit and try again later if not action.target_obj then - humanoid:queueAction({name = "meander", count = 2}, 0) + humanoid:queueAction(MeanderAction():setCount(2), 0) return end -- Otherwise, walk to and use the object: -- Note: force prolonged_usage, because video_game wouldn't get it by default (because it has no begin and end animation) - local object_action local obj_use_time = generate_use_time(action.target_type) - object_action = { - name = "use_object", - prolonged_usage = true, - object = action.target_obj, - loop_callback = --[[persistable:use_staffroom_action_loop_callback]] function() - humanoid:wake(relaxation[action.target_type]) - -- if staff is no longer fatigued, make them leave the staff room - if humanoid.attributes["fatigue"] == 0 then - humanoid:setNextAction(humanoid:getRoom():createLeaveAction()) - local room = humanoid.last_room - -- Send back to the last room if that room is still empty. - -- (applies to training and research only) - -- Make sure that the room is still there though. - -- If not, just answer the call - if room and room.is_active and - (room.room_info.id == "research" or room.room_info.id == "training") - and room:testStaffCriteria(room:getMaximumStaffCriteria(), humanoid) then - humanoid:queueAction(room:createEnterAction(humanoid)) - humanoid:setDynamicInfoText(_S.dynamic_info.staff.actions.heading_for:format(room.room_info.name)) - else - -- Send the staff out of the room - humanoid:queueAction{name = "meander"} - end - else - obj_use_time = obj_use_time - 1 - -- if staff is done using object - if obj_use_time == 0 then - -- Decide on the next target. If it happens to be of the same type as the current, just continue using the current. - -- also check x,y co-ords to see if the object actually exists in the room - action.next_target_obj, action.next_ox, action.next_oy, action.next_target_type = decide_next_target(action, humanoid) - if (not action.next_ox and not action.next_oy) or action.next_target_type == action.target_type then - obj_use_time = generate_use_time(action.target_type) - else - if action.next_target_obj then - action.next_target_obj.reserved_for = humanoid - end - object_action.prolonged_usage = false + local loop_callback_use = --[[persistable:use_staffroom_action_loop_callback]] function(obj_action) + humanoid:wake(relaxation[action.target_type]) + -- if staff is no longer fatigued, make them leave the staff room + if humanoid.attributes["fatigue"] == 0 then + humanoid:setNextAction(humanoid:getRoom():createLeaveAction()) + + local room = humanoid.last_room + -- Send back to the last room if that room is still empty. + -- (applies to training and research only) + -- Make sure that the room is still there though. + -- If not, just answer the call + if room and room.is_active and + (room.room_info.id == "research" or room.room_info.id == "training") and + room:testStaffCriteria(room:getMaximumStaffCriteria(), humanoid) then + humanoid:queueAction(room:createEnterAction(humanoid)) + humanoid:setDynamicInfoText(_S.dynamic_info.staff.actions.heading_for:format(room.room_info.name)) + else + -- Send the staff out of the room + humanoid:queueAction(MeanderAction()) + end + else + obj_use_time = obj_use_time - 1 + -- if staff is done using object + if obj_use_time == 0 then + -- Decide on the next target. If it happens to be of the same type as the current, just continue using the current. + -- also check x,y co-ords to see if the object actually exists in the room + action.next_target_obj, action.next_ox, action.next_oy, action.next_target_type = decide_next_target(action, humanoid) + if (not action.next_ox and not action.next_oy) or action.next_target_type == action.target_type then + obj_use_time = generate_use_time(action.target_type) + else + if action.next_target_obj then + action.next_target_obj.reserved_for = humanoid end + obj_action.prolonged_usage = false end end end - } - humanoid:queueAction({name = "walk", x = action.ox, y = action.oy}, 0) - humanoid:queueAction(object_action, 1) + end + + local obj_action = UseObjectAction(action.target_obj):setProlongedUsage(true) + :setLoopCallback(loop_callback_use) + + humanoid:queueAction(WalkAction(action.ox, action.oy), 0) + humanoid:queueAction(obj_action, 1) end return use_staffroom_action_start diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/vaccinate.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/vaccinate.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/vaccinate.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/vaccinate.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,127 @@ +--[[ Copyright (c) 2013 William "sadger" Gatens + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +class "VaccinateAction" (HumanoidAction) + +---@type VaccinateAction +local VaccinateAction = _G["VaccinateAction"] + +-- Vaccinate action constructor for a nurse. +--!param patient (Patient) Patient to vaccinate. +--!param fee Amount of money to pay. +function VaccinateAction:VaccinateAction(patient, fee) + assert(class.is(patient, Patient), "Invalid value for parameter 'patient'") + assert(type(fee) == "number", "Invalid value for parameter 'fee'") + + self:HumanoidAction("vaccinate") + self.patient = patient -- Patient to vaccinate. + self.vaccination_fee = fee -- Money to get from the patient. + self:setMustHappen(true) +end + +local is_in_adjacent_square = permanent"vacc_adjacent_square"( +function (patient,nurse) + local x1, y1 = patient.tile_x, patient.tile_y + local x2, y2 = nurse.tile_x, nurse.tile_y + + if not x1 or not x2 or not y1 or not y2 then + return false + end + + -- Determine if they are in an adjacent square + local x_diff = math.abs(x1-x2) + local y_diff = math.abs(y1-y2) + if (x_diff + y_diff == 1) then + -- And neither of them are in a room so must be outside + return (not patient:getRoom() and not nurse:getRoom()) + end +end) + +local find_face_direction = permanent"vacc_find_face_direction"( +function(nurse, patient) + local nx, ny = nurse.tile_x, nurse.tile_y + local px, py = patient.tile_x, patient.tile_y + + local x_diff = px - nx + local y_diff = py - ny + + if x_diff == 1 then + return "east" + elseif x_diff == -1 then + return "west" + elseif y_diff == -1 then + return "north" + elseif y_diff == 1 then + return "south" + end +end) + + +local interrupt_vaccination = permanent"action_interrupt_vaccination"( +function(action, humanoid) + local epidemic = humanoid.hospital.epidemic + epidemic:interruptVaccinationActions(humanoid) + humanoid:setTimer(1, humanoid.finishAction) +end) + + +local function vaccinate(action, nurse) + assert(nurse.humanoid_class == "Nurse") + + local patient = action.patient + + local perform_vaccination = --[[persistable:action_perform_vaccination]] function(humanoid) + -- Check if they STILL are in an adjacent square + if is_in_adjacent_square(nurse, patient) then + CallsDispatcher.queueCallCheckpointAction(nurse) + nurse:queueAction(AnswerCallAction()) + -- Disable either vaccination icon that may be present (edge case) + patient:setMood("epidemy2", "deactivate") + patient:setMood("epidemy3", "deactivate") + patient:setMood("epidemy1", "activate") + patient.vaccinated = true + patient.hospital:spendMoney(action.vaccination_fee, _S.transactions.vaccination) + patient:updateDynamicInfo() + else + patient:setMood("epidemy3", "deactivate") + patient:setMood("epidemy2", "activate") + -- Drop it they may not even be the vacc candidate anymore + CallsDispatcher.queueCallCheckpointAction(nurse) + nurse:queueAction(AnswerCallAction()) + patient.reserved_for = nil + end + end + + if is_in_adjacent_square(nurse,patient) then + local face_direction = find_face_direction(nurse,patient) + nurse:queueAction(IdleAction():setDirection(face_direction):setCount(5) + :setAfterUse(perform_vaccination):setOnInterrupt(interrupt_vaccination):setMustHappen(true)) + + else + patient:removeVaccinationCandidateStatus() + nurse:setCallCompleted() + patient.reserved_for = nil + nurse:queueAction(MeanderAction()) + end + nurse:finishAction() +end + +return vaccinate + diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/vip_go_to_next_room.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/vip_go_to_next_room.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/vip_go_to_next_room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/vip_go_to_next_room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -17,10 +17,17 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local action_vip_go_to_next_room_end = permanent"action_next_room_end"( function(humanoid) - humanoid:finishAction() -end) +class "VipGoToNextRoomAction" (HumanoidAction) + +---@type VipGoToNextRoomAction +local VipGoToNextRoomAction = _G["VipGoToNextRoomAction"] + +function VipGoToNextRoomAction:VipGoToNextRoomAction() + self:HumanoidAction("vip_go_to_next_room") +end + +local action_vip_go_to_next_room_end = permanent"action_next_room_end"( function(humanoid) end) local function action_vip_go_to_next_room_start(action, humanoid) if humanoid.next_room_no == nil then @@ -30,10 +37,10 @@ -- Walk to the entrance of the room and stay there for a while. local x, y = humanoid.next_room:getEntranceXY() local callback = --[[persistable:vip_next_room_enroute_cancel]] function() - humanoid:setNextAction({name = "idle"}) - humanoid.waiting = 1; + humanoid:setNextAction(IdleAction()) + humanoid.waiting = 1 end - humanoid:queueAction{name = "walk", x = x, y = y} + humanoid:queueAction(WalkAction(x, y)) -- What happens if the room disappears: humanoid.next_room.humanoids_enroute[humanoid] = {callback = callback} @@ -57,11 +64,7 @@ dir = "east" end end - humanoid:queueAction{ - name = "idle", - loop_callback = evaluate, - direction = dir, - } + humanoid:queueAction(IdleAction():setLoopCallback(evaluate):setDirection(dir)) -- Finish this action and start the above sequence. humanoid:finishAction() diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/vomit.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/vomit.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/vomit.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/vomit.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "VomitAction" (HumanoidAction) + +---@type VomitAction +local VomitAction = _G["VomitAction"] + +function VomitAction:VomitAction() + self:HumanoidAction("vomit") + self:setMustHappen(true) +end + local action_vomit_end = permanent"action_vomit_end"( function(humanoid) local litter = humanoid.world:newObject("litter", humanoid.tile_x, humanoid.tile_y) litter:setLitterType("puke", humanoid.last_move_direction == "south" and 0 or 1) --For some reason the vomit is inverted. diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/walk.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/walk.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/walk.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/walk.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,6 +18,48 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] +class "WalkAction" (HumanoidAction) + +---@type WalkAction +local WalkAction = _G["WalkAction"] + +--! Action to walk to a given position. +--!param x (int) X coordinate of the destination tile. +--!param y (int) Y coordinate of the destination tile. +function WalkAction:WalkAction(x, y) + assert(type(x) == "number", "Invalid value for parameter 'x'") + assert(type(y) == "number", "Invalid value for parameter 'y'") + + self:HumanoidAction("walk") + self.x = x + self.y = y + self.truncate_only_on_high_priority = false + self.walking_to_vaccinate = false -- Nurse walking with the intention to vaccinate + self.is_entering = false -- Whether the walk enters a room. +end + +function WalkAction:truncateOnHighPriority() + self.truncate_only_on_high_priority = true + return self +end + +--! Nurse is walking with the intention to vaccinate. +--!return (action) self, for daisy-chaining. +function WalkAction:enableWalkingToVaccinate() + self.walking_to_vaccinate = true + return self +end + +--! Set a flag whether the walk enters a room. +--!param entering (bool) If set or nil, set the flag of entering the room. +--!return (action) self, for daisy-chaining. +function WalkAction:setIsEntering(entering) + assert(type(entering) == "boolean", "Invalid value for parameter 'entering'") + + self.is_entering = entering + return self +end + local action_walk_interrupt action_walk_interrupt = permanent"action_walk_interrupt"( function(action, humanoid, high_priority) if action.truncate_only_on_high_priority and not high_priority then @@ -59,10 +101,17 @@ humanoid:setTimer(nil) timer_function(humanoid) end + + if action.walking_to_vaccinate then + local hospital = humanoid.hospital or humanoid.last_hospital + local epidemic = hospital.epidemic + if epidemic then + epidemic:interruptVaccinationActions(humanoid) + end + end end) local flag_list_bottom = 2048 -local flag_early_list = 1024 local flag_flip_h = 1 local navigateDoor @@ -127,7 +176,7 @@ local flags_here, flags_there = {}, {} local action_walk_tick; action_walk_tick = permanent"action_walk_tick"( function(humanoid) - local action = humanoid.action_queue[1] + local action = humanoid:getCurrentAction() local path_x = action.path_x local path_y = action.path_y local path_index = action.path_index @@ -156,9 +205,10 @@ if not recalc_route and flags_here.roomId ~= flags_there.roomId then local door = TheApp.objects.door.thob local door2 = TheApp.objects.swing_door_right.thob - if ((flags_here.thob ~= door and flags_here.thob ~= door2) and (flags_there.thob ~= door - and flags_there.thob ~= door2)) and (not flags_there.room - or map:getCellFlags(path_x[#path_x], path_y[#path_y]).roomId ~= flags_there.roomId) then + if flags_here.thob ~= door and flags_here.thob ~= door2 and + flags_there.thob ~= door and flags_there.thob ~= door2 and + (not flags_there.room or + map:getCellFlags(path_x[#path_x], path_y[#path_y]).roomId ~= flags_there.roomId) then recalc_route = true end end @@ -199,7 +249,7 @@ end) navigateDoor = function(humanoid, x1, y1, dir) - local action = humanoid.action_queue[1] + local action = humanoid:getCurrentAction() local duration = 12 local dx = x1 local dy = y1 @@ -221,21 +271,20 @@ local room = door:getRoom() local is_entering_room = room and humanoid:getRoom() ~= room - if class.is(humanoid, Staff) and is_entering_room - and humanoid.humanoid_class ~= "Handyman" then + if class.is(humanoid, Staff) and is_entering_room and + humanoid.humanoid_class ~= "Handyman" then -- A member of staff is entering, but is maybe no longer needed -- in this room? if not room.is_active or not room:staffFitsInRoom(humanoid) then - humanoid:queueAction({name = "idle"},0) + humanoid:queueAction(IdleAction(), 0) humanoid:setTilePositionSpeed(x1, y1) - humanoid:setNextAction({name = "idle", count = 10},0) - humanoid:queueAction{name = "meander"} + humanoid:setNextAction(IdleAction():setCount(10), 0) + humanoid:queueAction(MeanderAction()) return end end - if (door.user) - or (door.reserved_for and door.reserved_for ~= humanoid) - or (is_entering_room and not room:canHumanoidEnter(humanoid)) then + if door.user or (door.reserved_for and door.reserved_for ~= humanoid) or + (is_entering_room and not room:canHumanoidEnter(humanoid)) then --queueing patients are no longer enroute room.humanoids_enroute[humanoid] = nil local queue = door.queue @@ -248,23 +297,14 @@ end humanoid:setTilePositionSpeed(x1, y1) local action_index = 0 - if is_entering_room and queue:size() == 0 and not room:getPatient() - and not door.user and not door.reserved_for and humanoid.should_knock_on_doors - and room.room_info.required_staff and not swinging then - humanoid:queueAction({ - name = "knock_door", - door = door, - direction = dir, - }, action_index) + if is_entering_room and queue:size() == 0 and not room:getPatient() and + not door.user and not door.reserved_for and humanoid.should_knock_on_doors and + room.room_info.required_staff and not swinging then + humanoid:queueAction(KnockDoorAction(door, dir), action_index) action_index = action_index + 1 end - humanoid:queueAction({ - name = "queue", - x = x1, - y = y1, - queue = queue, - reserve_when_done = door, - }, action_index) + humanoid:queueAction(QueueAction(x1, y1, queue):setIsLeaving(humanoid:isLeaving()) + :setReserveWhenDone(door), action_index) action.must_happen = action.saved_must_happen action.reserve_on_resume = door return @@ -272,14 +312,10 @@ if action.reserve_on_resume then assert(action.reserve_on_resume == door) action.reserve_on_resume = nil - elseif is_entering_room and not action.done_knock and humanoid.should_knock_on_doors - and room.room_info.required_staff and not swinging then + elseif is_entering_room and not action.done_knock and humanoid.should_knock_on_doors and + room.room_info.required_staff and not swinging then humanoid:setTilePositionSpeed(x1, y1) - humanoid:queueAction({ - name = "knock_door", - door = door, - direction = dir, - }, 0) + humanoid:queueAction(KnockDoorAction(door, dir), 0) action.reserve_on_resume = door action.done_knock = true return @@ -338,13 +374,13 @@ if action.on_next_tile_set == on_next_tile_set then action.on_next_tile_set = nil end - local room = humanoid.world:getRoom(x1, y1) - if room then - room:onHumanoidLeave(humanoid) - end - room = humanoid.world:getRoom(to_x, to_y) - if room then - room:onHumanoidEnter(humanoid) + local rm = humanoid.world:getRoom(x1, y1) + if rm then + rm:onHumanoidLeave(humanoid) + end + rm = humanoid.world:getRoom(to_x, to_y) + if rm then + rm:onHumanoidEnter(humanoid) end end action.on_next_tile_set = on_next_tile_set diff -Nru corsix-th-0.30/CorsixTH/Lua/humanoid_actions/yawn.lua corsix-th-0.62/CorsixTH/Lua/humanoid_actions/yawn.lua --- corsix-th-0.30/CorsixTH/Lua/humanoid_actions/yawn.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/humanoid_actions/yawn.lua 2018-07-21 11:13:17.000000000 +0000 @@ -17,11 +17,21 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] + +class "YawnAction" (HumanoidAction) + +---@type YawnAction +local YawnAction = _G["YawnAction"] + +function YawnAction:YawnAction() + self:HumanoidAction("yawn") + self:setMustHappen(true) +end + local action_yawn_end = permanent"action_yawn_end"( function(humanoid) humanoid:finishAction() end) - local function action_yawn_start(action, humanoid) assert(humanoid.yawn_anim, "Error: yawning animation for humanoid " .. humanoid.humanoid_class) diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/brazilian_portuguese.lua corsix-th-0.62/CorsixTH/Lua/languages/brazilian_portuguese.lua --- corsix-th-0.30/CorsixTH/Lua/languages/brazilian_portuguese.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/brazilian_portuguese.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,5 +1,7 @@ --[[ Copyright (c) 2010 Manuel "Roujin" Wolf Copyright (c) 2012 Henrique Poyatos +Copyright (c) 2014 Leonardo Malaman (LeonardoGamer) +Copyright (c) 2018 Altieres Lima da Silva Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -17,1747 +19,2650 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -Language(utf8 "Português do Brasil", "Brazilian Portuguese", "pt_br", "br") - --]] +SOFTWARE. --]] -Language("Português do Brasil", "Brazilian Portuguese", "pt_br", "br") +Language("Português Brasileiro", "Brazilian Portuguese", "pt_br", "br") Inherit("English") Encoding(utf8) +------------------------------- OVERRIDE ---------------------------------- +adviser.warnings.money_low = "Você está ficando sem dinheiro!" -- Funny. Exists in German translation, but not existent in english? +-- TODO: tooltip.graphs.reputation -- this tooltip talks about hospital value. Actually it should say reputation. +-- TODO: tooltip.status.close -- it's called status window, not overview window. ---[[ -1. Menus e Janelas de Sistema -2. Menu Superior - ---]] - --- 1. Menus e Janelas de Sistema - -main_menu = { - new_game = "Novo Jogo", - custom_level = "Fase Personalizada", - load_game = "Carregar Jogo", - options = "Opções", - savegame_version = "versão de jogo salvo: ", - version = "Versão: ", - exit = "Sair", -} - -tooltip.main_menu = { - new_game = "Iniciar na primeira fase do jogo", - custom_level = "Construir seu hospital para uma única fase", - load_game = "Carregar um jogo salvo anteriormente", - options = "Modifique várias configurações", - exit = "Não se vá!", -} - -new_game_window = { - easy = "Júnior (Fácil)", - medium = "Pleno (Médio)", - hard = "Sênior (Difícil)", - tutorial = "Tutorial", - cancel = "Cancelar", -} - -tooltip.new_game_window = { - easy = "Se você é novo em jogos de simulação esta é a opção para você", - medium = "Este é o meio do campinho se você está inseguro do que deve escolher", - hard = "Se você está acostumado com este tipo de jogo e quer mais desafios, escolha esta opção", - tutorial = "Se você precisa de ajuda para começar a jogar, escolha esta opção", - tutorial = "Tutorial", - cancel = "Ah, eu não queria começar um novo jogo !", -} - -custom_game_window = { - caption = "Jogo Customizado", - free_build = "Construção Livre", -} - -tooltip.custom_game_window = { - start_game_with_name = "Carregando fase %s", - free_build = "Escolha esta opção se você quer jogar sem dinheiro ou objetivos de jogo", -} - -load_game_window = { - caption = "Carregar Jogo", -} - -tooltip.load_game_window = { - load_game = "Carregar jogo %s", - load_game_number = "Carregar jogo %d", - load_autosave = "Carregar jogo salvo automaticamente", -} - -menu_list_window = { - name = "Nome", - save_date = "Modificado", - back = "Voltar", -} - -tooltip.menu_list_window = { - name = "Clique aqui para ordenar por nome", - save_date = "Clique aqui para ordenar por data de última modificação", - back = "Fechar esta janela", -} +-- tooltip.staff_list.next_person, prev_person is rather next/prev page (also in german, maybe more languages?) +tooltip.staff_list.next_person = "Mostrar a página seguinte" +tooltip.staff_list.prev_person = "Mostrar a página anterior" +tooltip.status.reputation = "Sua reputaçäo näo deve estar abaixo de %d. Atualmente tem %d" +tooltip.status.balance = "Näo deve ter menos que $%d no banco. Atualmente tem $%d" -options_window = { - fullscreen = "Tela cheia", - width = "Largura", - height = "Altura", - change_resolution = "Mudar resolução de tela", - browse = "Procurar", - new_th_directory = "Aqui você pode indicar outro diretório onde o jogo Theme Hospital está instalado, entretando se mudar o diretório o jogo será reiniciado.", - cancel = "Cancelar", - back = "Voltar", -} +-- The originals of these two contain one space too much +fax.emergency.cure_not_possible_build = "Você precisará construir um(a) %s" +fax.emergency.cure_not_possible_build_and_employ = "Você precisará construir um(a) %s e contratar um(a)" +fax.emergency.num_disease = "Existem %d pessoas com %s e precisam ser atendidas imediatamente." +adviser.goals.lose.kill = "Mate mais %d pacientes para perder o nível!" -tooltip.options_window = { - fullscreen_button = "Clique para mudar para tela cheia", - width = "Digite a largura desejada", - height = "Digite a altura desejada", - change_resolution = "Mude a resolução da janela para os valores inseridos à esquerda", - language = "Selecionar '%s' como linguagem", - original_path = "Diretório informado como sendo da instalação do Theme Hospital original", - browse = "Procurar outro diretório de instalação do Theme Hospital. %1%", - back = "Fechar a janela de opções", -} +-- Improve tooltips in staff window to mention hidden features +tooltip.staff_window.face = "Rosto da pessoa - clique para abrir a tela de gerenciamento." +tooltip.staff_window.center_view = "Clique esquerdo para fixar-se na pessoa, botäo direito para rodar entre os funcionários." -lua_console = { - execute_code = "Executar", - close = "Fechar", -} +-- These strings are missing in some versions of TH (unpatched?) +confirmation.restart_level = "Você tem certeza de que deseja reiniciar o nível?" +-- TODO adviser.multiplayer.objective_completed +-- TODO adviser.multiplayer.objective_failed -tooltip.lua_console = { - textbox = "Digite um código Lua para rodar aqui", - execute_code = "Run the code you have entered", - close = "Fechar o console", +-- Replace Billy Savile +-- this is only relevant to the English game so does not need adding +-- in other language files +vip_names = { + [6] = "O Presidente da Cruz Vermelha", } -save_game_window = { - caption = "Salvar Jogo", - new_save_game = "Novo Jogo Salvo", -} +-- A small error in the introduction text of level 2 +introduction_texts.level2 = "Há uma grande variedade de doenças nesta área. Prepare o seu hospital para tratar mais pacientes " .. + "e para a construçäo de um Centro de Pesquisa. Lembre-se que deve manter limpo o hospital e procurar atingir a " .. + "sua mais alta reputaçäo possível. Tratará doenças como a língua comprida, entäo necessitará de uma sala de " .. + "laringologia. Também pode construir uma cardiologia para diagnosticar novas doenças. Estas duas consultas deveräo " .. + "ser pesquisadas antes de as construir. Também pode comprar mais terreno para aumentar o seu hospital. " .. + "Para isso, utilize o mapa da cidade. Obtenha uma reputaçäo de 300 um saldo de bancário de $10,000 e 40 pessoas curadas. " -tooltip.save_game_window = { - save_game = "Sobrescrevendo jogo salvo %s", - new_save_game = "Digite o nome para este jogo salvo", +-- An override for the squits becoming the the squits see issue 1646 +adviser.research.drug_improved_1 = "Seu Centro de Pesquisa melhorou o medicamento para %s" +------------------------------- NEW STRINGS ------------------------------- +date_format = { + daymonth = "%1% %2:months%", } -totd_window = { - tips = { - "Todo hospital precisa de um balção de recepção e uma Sala de Clínica Geral para começar. Depois disso, dependará do tipo de pacientes que visitará seu hospital. Ter uma farmácia é sempre uma boa idéia, entretanto.", - "Máquina como o Inflador precisam de constante manutenção. Contrate um ou dois funcionários da Manutenção para reparos nestas máquinas, ou colocará seus funcionários e pacientes em risco.", - "Depois de um certo período de trabalho, seus funcionários ficarão cansados. Certifique-se de construir uma Sala de Relaxamento, para que posam descansar.", - "Instale radiadores o suficiente para manter seus funcionários e pacientes aquecidos, do contrário ficarão infelizes. Use o Mapa da Cidade para localizar pontos do hospital que precisem ser aquecidos.", - "O nível de habilidade de um médico reflexe na qualidade e velocidade dos diagnósticos. Coloque um médico experiente na Sala de Clínica Geral, assim não precisará de muitas salas de diagnósticos adicionais.", - "Médicos de níveis 'Junior' e 'Pleno' podem melhorar suas habilidades aprendendo com um Sênior na Sala de Treinamento. Se o Sênior possuir alguma qualificação especial (Cirurgião, Psiquiatra ou Pesquisador), ele irá passar este conhecido ao(s) seu(s) pupilo(s).", - "Você já tentou digitar o numéro europeu de emergência (112) no aparelho de fax ? Certifique-se que o seu som esteja ligado !", - "Você pode ajustar algumas configurações como a resolução de tela e linguagem na janela de opções que pode ser acessar no menu inicial e dentro do jogo.", - "Você selecionou uma linguagem que não o inglês, mas existem textos em inglês por todos os lugares? Ajude-nos a traduzir os textos restantes para sua língua !", - "A comunidade do Jogo CorsixTH está precisando de reforços em sua equipe ! Você está interessado em codificar, traduzir ou criar gráficos para o CorsixTH? Entre em contato conosco pelo nosso Fórum, Lista de Discussão ou canal de IRC (#corsix-th no freenode).", - "Se localizar um bug, por favor reporte-o em nosso bugtracker: th-issues.corsix.org", - "Cada fase possui certas metas a serem atingidas antes de passar para a próxima fase. Cheque a janela de situação para acompanhar seu progresso a fim de atingir seus objetivos.", - "Se você deseja editar ou remover um sala existente, pode fazê-lo com o botão de edição de sala na barra inferior.", - "Caso haja uma multidão de pacientes esperando, você deve descobrir rapidamente quais deles estão aguardando por uma sala em particular passando o ponteiro do mouse por cima desta sala.", - "Clique nas portas das salas para ver sua fila. Isso pode ser muito útil, já que pode reordenar a fila ou encaminhar um paciente para outra sala.", - "Funcionários infelizes irão pedir aumentos de salários com mais frequência. Certifique-se que sua equipe esteja trabalho em um ambiente de trabalho confortável para mantê-los felizes.", - "Pacientes podem ficar com sede enquanto esperam em seu hospital, ainda mais se ligar o aquecimento! Instale máquinas de venda de refrigerantes em pontos estratégicos para um ganho extra.", - "Você pode abortar o processo de diagnóstico prematuramente e presupor a cura, se você já tiver descoberto a doença. Atente-se que desta maneira aumenta-se o risco de um tratamento errado, resultando na morte do paciente.", - "Emergências podem ser uma boa fonte de grana extra, desde que você possua plena capacidade e recursos de lidar com os pacientes à tempo.", - }, - previous = "Dica anterior", - next = "Próxima Dica", -} +object.litter = "Lixo" +tooltip.objects.litter = "Lixo: Um paciente jogou porque näo encontrou um cesto de lixo." -tooltip.totd_window = { - previous = "Mostrar a dica anterior", - next = "Mostrar a próxima dica", -} +object.rathole = "Buraco de rato" +tooltip.objects.rathole = "Casa de uma família de ratos que encontrou seu hospital sujo o suficiente para morar nele." --- 2. Menu Superior +tooltip.fax.close = "Fecha esta janela sem apagar a mensagem." +tooltip.message.button = "Clique com o botäo esquerdo para abrir a mensagem" +tooltip.message.button_dismiss = "Clique com o botäo esquerdo para abrir a mensagem e botäo direto para recusá-la" +tooltip.casebook.cure_requirement.hire_staff = "Você precisa contratar empregados para realizar este tratamento." +tooltip.casebook.cure_type.unknown = "Você ainda näo sabe como tratar esta doença" +tooltip.research_policy.no_research = "Nenhuma pesquisa está sendo feita nesta categoria no momento." +tooltip.research_policy.research_progress = "Progresso para a próxima descoberta nesta categoria: %1%/%2%" -menu = { - file = " ARQUIVO ", - options = " OPÇÕES ", - display = " DISPLAY", - charts = " GRÁFICOS ", - debug = " DEBUG ", -} +menu["player_count"] = "QUANTIDADE DE JOGADORES" --- Menu File menu_file = { - load = " CARREGAR JOGO ", - save = " SALVAR JOGO ", - restart = " REINICIAR ", - quit = " SAIR ", + load = " CARREGAR (SHIFT+L) ", + save = " SALVAR (SHIFT+S) ", + restart = " REINICIAR (SHIFT+R)", + quit = " SAIR (SHIFT+Q) ", } - --- Menu Options menu_options = { - sound = " SOM ", - announcements = " ANÚNCIOS ", - music = " MÚSICA ", - sound_vol = " VOLUME DOS SONS ", - announcements_vol = " SOM DOS ANÚNCIOS ", - music_vol = " VOLUME DA MUSICA ", - autosave = " AUTOSALVAR ", - game_speed = " VELOCIDADE DO JOGO ", - jukebox = " JUKEBOX ", -} - - --- Menu Display -menu_display = { - high_res = " ALTA RESOLUÇÃO ", - mcga_lo_res = " BAIXA RESOLUÇÃO ", - shadows = " SOMBRAS ", -} - --- Menu Charts -menu_charts = { - statement = " EXTRATO BANCÁRIO ", - casebook = " PRONTUÁRIO DE DOENÇAS ", - policy = " POLÍTICAS DO HOSPITAL ", - research = " PESQUISA ", - graphs = " GRÁFICOS ", - staff_listing = " QUADRO DE FUNCIONÁRIOS ", - bank_manager = " GERENTE DO BANCO ", - status = " STATUS ", - briefing = " OBJETIVO DESTA FASE ", -} - --- Menu Options Volume -menu_options_volume = { - [10] = " 10% ", - [20] = " 20% ", - [30] = " 30% ", - [40] = " 40% ", - [50] = " 50% ", - [60] = " 60% ", - [70] = " 70% ", - [80] = " 80% ", - [90] = " 90% ", - [100] = " 100% ", -} - - menu_options = { + sound = " SOM (ALT+S) ", + announcements = " ANUNCIOS (ALT+A) ", + music = " MUSICA (ALT+M) ", + jukebox = " MAQUINA DE DISCOS (J) ", lock_windows = " TRAVAR JANELAS ", - edge_scrolling = " EDGE SCROLLING ", - settings = " CONFIGURAÇÕES ", - adviser_disabled = " NOTIFICAÇÕES ", - warmth_colors = " WARMTH COLOURS", + edge_scrolling = " ROLAR MARGEM ", + capture_mouse = " CAPTURAR MOUSE ", + adviser_disabled = " CONSELHEIRO (SHIFT+A) ", + warmth_colors = " CORES QUENTES ", + wage_increase = " EXIGENCIAS SALARIAS", + twentyfour_hour_clock = " RELOGIO DE 24 HORAS ", } menu_options_game_speed = { - pause = " (P) PAUSADO ", - slowest = " (1) MUITO LENTO ", - slower = " (2) LENTO ", - normal = " (3) NORMAL ", - max_speed = " (4) RÁPIDO ", - and_then_some_more = " (5) AINDA MAIS RÁPIDO ", + pause = " PAUSAR (P) ", + slowest = " MUITO LENTO (1) ", + slower = " LENTO (2) ", + normal = " NORMAL (3) ", + max_speed = " RAPIDO (4) ", + and_then_some_more = " MUITO RAPIDO (5) ", } menu_options_warmth_colors = { - choice_1 = " Vermelho ", - choice_2 = " Azul Verde Vermelho ", - choice_3 = " Amarelo Laranja Vermelho ", + choice_1 = " VERMELHO ", + choice_2 = " AZUL VERDE VERMELHO ", + choice_3 = " AMARELO LARANJA VERMELHO ", } --- The demo does not contain this string -menu_file.restart = " REINICIAR " +menu_options_wage_increase = { + grant = " PERMITIR ", + deny = " NEGAR ", +} + +-- Add F-keys to entries in charts menu (except briefing), also town_map was added. +menu_charts = { + bank_manager = " GERENTE DO BANCO (F1) ", + statement = " ESTADO DA CONTA (F2) ", + staff_listing = " LISTA DOS FUNCIONARIOS (F3) ", + town_map = " MAPA DA CIDADE (F4) ", + casebook = " FICHA CLINICA (F5) ", + research = " PESQUISA (F6) ", + status = " ESTADO (F7) ", + graphs = " GRAFICO (F8) ", + policy = " NORMAS (F9) ", +} menu_debug = { - jump_to_level = " IR PARA A FASE ", - transparent_walls = " (X) PAREDES TRANSPARENTES ", - limit_camera = " LIMIT CAMERA ", - disable_salary_raise = " DESABILITAR AUMENTOS DE SALÁRIO ", - make_debug_fax = " (F8) MAKE DEBUG FAX ", - make_debug_patient = " (F9) MAKE DEBUG PATIENT ", - cheats = " (F11) CHEATS ", - lua_console = " (F12) CONSOLE LUA ", - calls_dispatcher = " CALLS DISPATCHER ", - dump_strings = " DUMP STRINGS ", - dump_gamelog = " (CTRL+D) DUMP GAME LOG ", - map_overlay = " MAP OVERLAY ", - sprite_viewer = " SPRITE VIEWER ", + jump_to_level = " SALTAR PARA NIVEL ", + connect_debugger = " CONECTAR SERVIDOR LUA DBGp (CTRL + C) ", + transparent_walls = " PAREDES TRANSPARENTES (X) ", + limit_camera = " LIMITAR CAMERA ", + disable_salary_raise = " DESATIVAR AUMENTO DE SALARIO ", + make_debug_fax = " FAZER DEBUG DO FAX ", + make_debug_patient = " FAZER DEBUG DO PACIENTE ", + cheats = " TRAPAÇAS (F11) ", + lua_console = " CONSOLE LUA (F12) ", + debug_script = " RODAR SCRIPT DE DEBUG (SHIFT + D) ", + calls_dispatcher = " CHAMAR CONTROLADOR ", + dump_strings = " DUMPAR TEXTOS DO JOGO ", + dump_gamelog = " DUMPAR LOG DO JOGO (CTRL + D) ", + map_overlay = " SOBREPOR MAPA ", + sprite_viewer = " VISUALIZADOR DE SPRITE ", } menu_debug_overlay = { - none = " NENHUM ", - flags = " FLAGS ", - positions = " POSIÇÕES ", + none = " NADA ", + flags = " MARCAS ", + positions = " POSIÇOES ", heat = " TEMPERATURA ", - byte_0_1 = " BYTE 0 & 1 ", - byte_floor = " BYTE FLOOR ", - byte_n_wall = " BYTE N WALL ", - byte_w_wall = " BYTE W WALL ", + byte_0_1 = " BYTE 0 Y 1 ", + byte_floor = " BYTE SOLO ", + byte_n_wall = " BYTE PAREDE NORTE ", + byte_w_wall = " BYTE PAREDE OESTE ", byte_5 = " BYTE 5 ", byte_6 = " BYTE 6 ", byte_7 = " BYTE 7 ", - parcel = " PARCEL ", -} - -dynamic_info = { - patient = { --- emergency = "Чрезвычайная ситуация: %s", --- guessed_diagnosis = "Диагноз навскидку: %s ", - diagnosis_progress = "Diagnóstico em:", - actions = { --- sent_to_other_hospital = "Отправлен в другую больницу", --- prices_too_high = "У вас слишком дорого, - я иду домой", --- no_gp_available = "Ждет постройки кабинета терапевта", --- waiting_for_treatment_rooms = "Ждет постройки кабинета для лечения", --- dying = "Умирает!", - no_diagnoses_available = "Sem diagnóstico - Indo para a casa", --- epidemic_sent_home = "Отправлен домой инспектором", - cured = "Curado !", - waiting_for_diagnosis_rooms = "Esperando você construir novas salas de diagnóstico", --- epidemic_contagious = "Заразный", - awaiting_decision = "Esperando por sua decisão", - sent_home = "Alta - Indo para casa", --- fed_up = "Сыт по горло и уходит", - no_treatment_available = "Sem tratamento - Indo para a casa", - on_my_way_to = "À caminho do %s", - queueing_for = "Na fila de espera do(a) %s", - }, - diagnosed = "Diagnóstico: %s ", - }, --- health_inspector = "Инспектор", --- vip = "Шишка", - object = { - times_used = "Vezes que foi usado(a): %d", - queue_size = "Tamanho da fila: %d", --- strength = "Прочность: %d", - queue_expected = "Tamanho esperado da fila: %d", - }, - staff = { - actions = { - going_to_repair = "Indo reparar %s", - fired = "Demitido", - waiting_for_patient = "Esperando por um paciente", - wandering = "Andando sem rumo", - heading_for = "Indo para %s", - }, - tiredness = "Nível de Stress: ", - }, -} - --- 3. Staff? - --- Staff titles --- these are titles used e.g. in the dynamic info bar -staff_title = { - receptionist = "Recepcionista", - general = "General", -- unused? - nurse = "Enfermeira", - junior = "Júnior", - doctor = "Doutor", - surgeon = "Cirurgião", - psychiatrist = "Psiquiatra", - consultant = "Doutor Sênior", - researcher = "Pesquisador", -} - -staff_list = { - morale = "MORAL", - tiredness = "CANSAÇO", - skill = "QUALIFICAÇÕES", - total_wages = "SALÁRIO", -} - - - -bank_manager = { - current_loan = "Empréstimo atual", - balance = "Balanço", - interest_payment = "Pagamento de Juros", - hospital_value = "Valor do Hospital", - interest_rate = "Taxa de Juros", - inflation_rate = "Taxa Inflação", - insurance_owed = "Seguro Inadimplência", - statistics_page = { - balance = "Saldo", - details = "Detalhe", - date = "Data", - current_balance = "Saldo Atual", - money_in = "Entrada", - money_out = "Saída", - }, -} - - -transactions = { - severance = "Demissão", - research = "Custos de Pesquisa", --- eoy_trophy_bonus = "Bonificação VIP", // VIP cash award - buy_object = "Compra", - cure_colon = "Cura:", - wages = "Custos com Folha de Pagamento", - personal_bonus = "Pagamento de Bonificação Pessoal", - drug_cost = "Medicação", - heating = "Custos de Aquecimento", - treat_colon = "Tratamento:", - hire_staff = "Contratação", - bank_loan = "Empréstimo Bancário", - insurance_colon = "Seguro:", - sell_object = "Venda", --- loan_interest = "Выплата процента по займу", --- loan_repayment = "Возврат по займу", - buy_land = "Compra de Terreno", --- machine_replacement = "Замена машины", - build_room = "Construção", - drinks = "Receita: Máq. de Refrigerante", --- "vip_cash_award"? -} - -town_map = { - number = "Número", - not_for_sale = "Não está à venda", - price = "Preço", - for_sale = "À Venda", - owner = "Dono", - area = "Área", -} - -high_score = { - categories = { --- deaths = "Óbitos", --- total_value = "Общая стоимость", --- money = "Самый богатый", --- cures = "Пациентов вылечено", --- visitors = "Количество посетителей", --- salary = "", - }, -} - -research = { --- allocated_amount = "Распределенное количество", --- funds_allocation = "Распределение финасирования", - categories = { - improvements = "Melhorias", - drugs = "Novos Medicamentos", - diagnosis = "Equip. para Diagnóstico", - cure = "Equip. para Tratamento", - specialisation = "Especializações", - }, + parcel = " PARCELA ", } - -policy = { - header = "POLÍTICA DO HOSPITAL", - diag_termination = "Finalização de Diagnóstico", - sliders = { - guess = "Determinar Cura", - send_home = "Mandar p/ casa", - stop = "Parar", - staff_room = "Ir descansar", - }, - diag_procedure = "Procedimento de Diagnóstico", - staff_rest = "Descanso dos Funcionários", - staff_leave_rooms = "Funcionário deixar sala", -} - -casebook = { - sent_home = "enviados para casa", - deaths = "óbitos", - treatment_charge = "custo do tratamento", - reputation = "reputação", --- research = "Сосредоточить исследования", - cure = "curas", - cured = "curados", - earned_money = "valor do tratamento", -} - ---[[ -progress_report = { - quite_unhappy = "Люди вами недовольны", - header = "Отчет об успехах", - very_unhappy = "Люди вас не любят. Уделяйте им больше внимания", - more_drinks_machines = "Пациенты умирают от жажды. Поставьте автоматы с напитками", - too_cold = "У вас слишком холодно, поставьте еще батарей", - too_hot = "Настройте систему отопления, у вас слишком жарко", - percentage_pop = "Доля клиентов", - win_criteria = "Условия для победы", -} -]] -tooltip = { ---[[ - staff_list = { - = "Предыдущая страница", - next_person = "Следующая страница", - detail = "Внимание к деталям", - happiness = "Насколько ваши сотрудники довольны своей работой в целом", - tiredness = "Показывает сколько ваши сотрудники еще смогут поработать без отдыха", - ability = "Квалификация ваших сотрудников в среднем по больнице", - happiness_2 = "Моральное состояние", - ability_2 = "Профессиональные навыки", - tiredness_2 = "Запас сил", - researcher_train = "На %d%% готов к получению диплома исследователя", - surgeon_train = "На %d%% готов к получению диплома хирурга", - psychiatrist_train = "На %d%% готов к получению диплома психиатра", - researcher = "Дипломированый исследователь", - psychiatrist = "Дипломированый психиатр", - surgeon = "Дипломированый хирург", - handymen = "Показать список всех рабочих вашей больницы", - nurses = "Показать список всех медсестер вашей больницы", - doctors = "Показать список всех докторов вашей больницы", - receptionists = "Показать список всех регистраторов вашей больницы", - pay_rise = "Поднять оклад на 10%", - bonus = "Выплатить премию в размере 10% от оклада", - salary = "Текущая зарплата", - close = "Назад к игре", - sack = "Вышвырнуть на улицу", - doctor_seniority = "Авторитет доктора", - view_staff = "Наблюдать за работой", - skills = "Дополнительные умения", - total_wages = "Общая зарплата", - },]] - town_map = { - close = "Fechar", - plants = "Exibir plantas", - fire_extinguishers = "Exibir plantas", - people = "Exibir pessoas", - balance = "Saldo", - heat_dec = "Diminuir aquecimento", - heating_bill = "Preço do aquecimento", - radiators = "Exibir radiadores", - objects = "Exibir objetos", - heat_level = "Temperatura do aquecimento", - heat_inc = "Aumentar aquecimento", - }, ---[[ - policy = { - diag_termination = "Обследование пациента будет продолжаться, пока доктора не будут на столько процентов уверены в диагнозе или пока у них не закончатся средства диагностики", - close = "Закрыть окно политики", - staff_leave = "Нажмите здесь чтобы разрешить сотрудникам покидать кабинеты и идти туда где нужна их помощь", - diag_procedure = "Если доктор уверен в своем диагнозе менее, чем значение «Отправить домой», пациент будет отправлен домой. Если же шансы выше чем «Диагноз наугад», он будет отправлен на лечение. В остальных случаях потребуется ваше решение", - staff_rest = "Насколько усталым должен быть сотрудник, чтобы получить право на отдых", - staff_stay = "Нажмите здесь чтобы сотрудники оставались в тех кабинетах, где вы их поставили", - }, - bank_manager = { - graph = "График ожидаемых выплат от %s", - close = "Закрыть окно", - hospital_value = "Текущая стоимость госпиталя вместе со всем оборудованием", - graph_return = "Вернуться назад", - current_loan = "Размер текущего займа", - borrow_5000 = "Занять у банка 5000$", - balance = "Ваш баланс", - interest_payment = "Ежемесячные выплаты по займу", - inflation_rate = "Размер инфляции за год", - interest_rate = "Годовой процент по займу", - repay_5000 = "Отдать банку 5000$", - show_graph = "Показать график ожидаемых выплат от %s", - insurance_owed = "Сколько денег вам должны %s", - }, - casebook = { - sent_home = "Количество пациентов, которым было отказано в лечении", - increase = "Поднять стоимость", - decrease = "Снизить стоимость", - up = "Вверх", - down = "Вниз", - reputation = "Общая репутация этой практики", - research = "Нажмите чтобы сосредоточить бюджет специальных исследований на этой проблеме", - close = "Закрыть", - earned_money = "Всего заработано на этом", - deaths = "Количество летальных исходов", - cured = "Количество вылеченных", - treatment_charge = " Стоимость для пациентов", - cure_type = { - psychiatrist = "Это лечит психиатр", - drug_percentage = "От этого есть лекарство. Ваше эффективно на %d%", - machine = "Для лечения нужно специальное оборудование", - surgery = "Cura требует операции", - }, - cure_requirement = { - possible = "Вы можете это вылечить", - build_room = "Вам нужно построить специальный кабинет для лечения", - research_machine = "Для лечения нужно изобрести машину", - hire_staff = "Вам нужно нанять специалиста для лечения", - }, - }, - status = { - population_chart = "Показывает соотношение числа посетителей в разных больницах", - percentage_cured = "Вам нужно вылечить %d% всех посетителей. На данный момент вам удалось вылечить %d%", - num_cured = "Вам нужно вылечить %d людей. Пока вам удалось исцелить %d", - thirst = "Средний уровень жажды людей в больнице", - close = "Закрыть окно", - win_progress_own = "Показать успехи вашей больницы", - reputation = "Ваша репутация должна достигать %d. Сейчас она составляет %d", - population = "Добейтесь чтобы к вам приходили лечиться %d%% всех пациентов", - warmth = "Средняя температура по больнице", - percentage_killed = "Постарайтесь не убивать более чем %d%% посетителей. На данный момент вы угробили %d%%", - balance = "На вашем счету должно быть не менее %d$. Сейчас у вас %d$", - value = "Ваша больница должна стоить %d$. Сейчас она стоит %d$", - win_progress_other = "Показать как идут дела у %s", - happiness = "Общее состояние пациентов в вашей больнице", - }, ---]] - buy_objects_window = { - price = "Preço", - cancel = "Cancelar", - confirm = "Comprar itens", - total_value = "Total", - decrease = "Comprar menos", - increase = "Comprar mais", - }, - hire_staff_window = { - doctors = "Ver Doutores disponíveis para contratação", - nurses = "Ver Enfermeiras disponíveis para contratação", - handymen = "Ver Zeladores disponíveis para contratação", - receptionists = "Ver Recepcionistas disponíveis para contratação", - prev_person = "Próxima pessoa", - next_person = "Pessoa anterior", - hire = "Contratar", - cancel = "Cancelar", - doctor_seniority = "Experiência (Júnior, Pleno, Sênior)", - staff_ability = "Habilidade", - salary = "Salário", - qualifications = "Qualificações extras", - surgeon = "Cirurgião", - psychiatrist = "Psiquiatra", - researcher = "Pesquisador", - }, -} - --- 5. Doenças - -diseases = { - general_practice = { - name = "Prática geral", - }, - diag_ward = { - name = "Diag: Enfermaria", - }, - diag_ultrascan = { - name = "Diag: Ultrasom", - }, - diag_blood_machine = { - name = "Diag: Análise Sanguinea", - }, - diag_x_ray = { - name = "Diag: Raio-X", - }, - diag_psych = { - name = "Diag: Psiquiatria", - }, - diag_general_diag = { - name = "Diag: Diagnóstico Geral", - }, - diag_cardiogram = { - name = "Diag: Eletrocardiograma", - }, - diag_scanner = { - name = "Diag: Scanner", - }, - autopsy = { - name = "Autópsia", - }, - third_degree_sideburns = { --- cause = "Causa - непреодолимая тоска по семидесятым.", --- cure = "Cura - психиатр должен, используя самые современные методы, убедить пациента, что чрезмерная волосатость уже не в моде.", - name = "Queimaduras de Terceiro Grau", --- symptoms = "Sintomas - длинные волосы, смешные штаны, обувь на платформе и сверкающий макияж.", - }, - discrete_itching = { --- cause = "Causa - крошечные насекомые с очень острыми зубами.", --- cure = "Cura - пациент выпивает липкий фармацевтический сироп, который защищает кожу.", - name = "Coceira Discreta", --- symptoms = "Sintomas - интенсивное чесание вплоть до воспламенения.", - }, - the_squits = { - cause = "Causa - Comer um pedaço de pizza encontrada embaixo do fogão.", - cure = "Cura - Uma mistura glutinoso de químicos farmacêuticos pegajosos solidificará as entranhas do paciente.", - name = "Disenteria", - symptoms = "Sintomas - Argh, tenho certeza que você pode imaginar.", - }, - spare_ribs = { --- cause = "Causa - сидение на холодном каменном полу.", --- cure = "Cura - два хирурга должны удалить лишние ребра и завернуть их пациенту с собой.", - name = "Rim Extra", --- symptoms = "Sintomas - неприятные ощущения от массивной груди.", - }, - king_complex = { --- cause = "Causa - дух Короля, который захватил контроль над разумом пациента.", --- cure = "Cura - психиатр рассказывает пациенту как нелепо тот выглядит.", - name = "Complexo de Rei", --- symptoms = "Sintomas - слабость к цветастой замшевой обуви и чизбургерам.", - }, - fake_blood = { --- cause = "Causa - скорее всего, пациент стал жертвой розыгрыша.", --- cure = "Cura - психиатр должен помочь пациенту успокоиться.", - name = "Sangue falso", --- symptoms = "Sintomas - красная жидкость в венах, которая испаряется при контакте с одеждой.", - }, - invisibility = { --- cause = "Causa - укус радиоактивного (и, само собой, невидимого) муравья.", --- cure = "Cura - напиток насыщенного цвета, приготовленный в аптеке, восстанавливает видимость пациента.", - name = "Invisibilidade", --- symptoms = "Sintomas - пациент чувствует себя нормально и даже может использовать болезнь чтобы разыгрывать близких.", - }, - golf_stones = { --- cause = "Causa - вдыхание ядовитого газа, содержащегося в мячиках для гольфа.", --- cure = "Cura - образования удаляются хирургами в операционной.", - name = "Pedras de Golf", --- symptoms = "Sintomas - бред и чувство стыда.", - }, - infectious_laughter = { - -- cause = "Causa - просмотр классических комедий.", - -- cure = "Cura - квалифицированный психиатр должен напомнить пациенту, что не все в этой жизни смешно.", - name = "Risada contagiosa", - -- symptoms = "Sintomas - непроизвольное фырканье и повторение несмешных шуток.", - }, - baldness = { - -- cause = "Causa - вранье и придумавание небылиц с целью привлечения внимания.", - -- cure = "Cura - в ходе болезненной процедуры специальная машина плавно восстанавливает волосяной покров.", - name = "Calvíce", - -- symptoms = "Sintomas - блестящесть и смущение.", - }, - heaped_piles = { - cause = "Causa - Ficar muito perto de refrigeradores de água.", - cure = "Cura - Um agradável porém poderoso acído dissolverá as hemorróidas por dentro.", - name = "Hemorróidas", - symptoms = "Sintomas - Paciente tem a sensação de estar sentado em um saco de bolinhas de gude.", - }, - unexpected_swelling = { - -- cause = "Causa - все внезапное.", - -- cure = "Cura - возбухание может быть уменьшено хирургами при помощи автогена.", - name = "Inchaço inesperado", - -- symptoms = "Симптом - возбухание.", - }, - jellyitis = { - -- cause = "Causa - пища, богатая желатином и избыток физической активности.", - -- cure = "Cura - пациента помещают в разжелетиватель в специальном кабинете.", - name = "Gelatinite", - -- symptoms = "Sintomas - пациент чрезмерно трясется и часто падает.", - }, - hairyitis = { - -- cause = "Causa - длительные прогулки в свете луны.", - -- cure = "Cura - электролизатор удаляет волосы и запаивает поры.", - name = "Cabelulite", - -- symptoms = "Sintomas - обостренное обоняние.", - }, - alien_dna = { - -- cause = "Causa - прыгающие личинки разумных видов пришельцев.", - -- cure = "Cura - в специальной машине ДНК извлекается, очищается от фрагментов пришельцев и быстро вставляется на место.", - name = "DNA alienígena", - -- symptoms = "Sintomas - постепенное превращение в пришельца и стремление уничтожить человечество.", - }, - bloaty_head = { - cause = "Causa - Cheirar queijo e beber água de chuva não purificada.", - cure = "Cura - A cabeça inchada é estourada e reinflada no PSI correto usando uma máquina inteligente.", - name = "Cabeça inchada", - symptoms = "Sintomas - Muito desconforto para o sofredor.", - }, - gastric_ejections = { - -- cause = "Causa - острая мексиканская и индийская пища.", - -- cure = "Cura - выпивание специального связующего состава предотвращает какие бы то ни было извержения.", - name = "Vômitos", - -- symptoms = "Sintomas - полупереваренная пища извергается из пациента в случайных местах.", - }, - uncommon_cold = { - cause = "Causa - pequenas partículas de muco no ar.", - cure = "Cura - Um bom gole de um xarope incomum feito a partir de ingredientes especiais na Farmária poderá curar isso.", - name = "Frio incomum", - symptoms = "Sintomas - Barulho constante, espirros e pulmões descolorados.", - }, - corrugated_ankles = { - -- cause = "Causa - езда через асфальтовые гребни на дорогах.", - -- cure = "Cura - слегка токсичная смесь трав и специй позволяет пациенту выпрямить лодыжки.", - name = "Tornozelos tortos", - -- symptoms = "Sintomas - привычная обувь больше не подходит пациенту.", - }, - sleeping_illness = { - cause = "Causa - Superatividade da glândula de sono localizada no céu da boca.", - cure = "Cura - Uma alta dosagem de um poderoso estimulante será administrado pela Enfermeira.", - name = "Encefalite letárgica", - symptoms = "Sintomas - Vontade incontrolável de desabar e dormir em qualquer lugar.", - }, - sweaty_palms = { - -- cause = "Causa - боязнь собеседований.", - -- cure = "Cura - психиатр должен уговорить пациента избавиться от этой выдуманной болезни.", - name = "Mãos suadas", - -- symptoms = "Sintomas - рукопожатие пациента напоминает сжимание мокрой губки.", - }, - serious_radiation = { - -- cause = "Causa - жевание изотопов плутония.", - -- cure = "Cura - пациента нужно как следует промыть под обеззараживающим душем.", - name = "Radiação severa", - -- symptoms = "Sintomas - пациент себя очень, очень плохо чувствует.", - }, - gut_rot = { - cause = "Causa - Mistura de Whisky 12 anos Mrs. O'Mallley's com xarope.", - cure = "Cura - A Enfermeira pode administrar uma seleção de químicos dissolventes que podem revestir o estômago.", - name = "Intestino podre", - symptoms = "Sintomas - sem tosse mas sem parede do estômago também.", - }, - iron_lungs = { - -- cause = "Causa - городской смог и дым от шашлыков.", - -- cure = "Cura - два хирурга проводят операцию чтобы удалить затвердевшие легкие.", - name = "Pulmões de Aço", - -- symptoms = "Sintomas - способность выдыхать огонь и громко кричать под водой.", - }, - broken_wind = { - -- cause = "Causa - упражнения на беговой дорожке после еды.", - -- cure = "Cura - насыщенная особыми водянистыми атомами микстура выпивается залпом.", - name = "Vento quebrado", - -- symptoms = "Sintomas - представляют опасность для находящих позади пациента.", - }, - kidney_beans = { - -- cause = "Causa - разгрызание ледяных кубиков в напитках.", - -- cure = "Cura - два хирурга должны удалить бобы, не прикасаясь к почкам.", - name = "Pedras no rim", - -- symptoms = "Sintomas - боль и частые визиты в туалет.", - }, - transparency = { - -- cause = "Causa - слизывание йогурта с крышечек упаковок.", - -- cure = "Cura - специально охлажденная и подкрашенная в аптеке вода вылечит эту болезнь.", - name = "Transparência", - -- symptoms = "Sintomas - плоть становится прозрачной и ужасно выглядит.", - }, - broken_heart = { - -- cause = "Causa - кто-нибудь более молодой, богатый и стройный чем пациент.", - -- cure = "Cura - два хирурга вскрывают грудную клетку и, затаив дыхание, аккуратно собирают сердце.", - name = "Coração partido", - -- symptoms = "Sintomas - плач и боли в мышцах от разрывания праздничных фотографий.", - }, - slack_tongue = { - -- cause = "Causa - хроническое обсуждение мыльных опер.", - -- cure = "Cura - язык помещается в языкорезку и укорачивается быстро, точно, безжалостно.", - name = "Língua negligente", - -- symptoms = "Sintomas - язык примерно в пять раз увеличен в размерах.", - }, - tv_personalities = { - cause = "Causa - Assistar à televisão o dia todo.", - cure = "Cura - Um psiquiatra bem treinado deverá convencer o paciente à vender a TV e comprar um rádio.", - name = "Personalidade da TV", - symptoms = "Sintomas - Ilusões sobre ser capaz de apresentar um programa de variedades matinal.", - }, - ruptured_nodules = { - -- cause = "Causa - прыжки с тарзанкой в холодную погоду.", - -- cure = "Cura - хирург удаляет грыжу твердой, уверенной рукой.", - name = "Ruptura de Nódulos", - -- symptoms = "Sintomas - невозможность сидеть с комфортом.", - }, - fractured_bones = { - -- cause = "Causa - падение с большой высоты на бетонные поверхности.", - -- cure = "Cura - сперва накладывается гипс, затем он удаляется при помощи устройства с лазером.", - name = "Fratura nos ossos", - -- symptoms = "Sintomas - громкий треск и неспособность использовать поврежденные конечности.", - }, - chronic_nosehair = { - -- cause = "Causa - высокомерное фыркание в присутствии менее успешных людей.", - -- cure = "Cura - отвратительное противоволосяное зелье приготавливается в аптеке.", - name = "Pêlos no nariz crônicos", - -- symptoms = "Sintomas - нособорода, в которой можно свить гнездо.", - }, +menu_player_count = { + players_1 = " 1 JOGADOR ", + players_2 = " 2 JOGADORES ", + players_3 = " 3 JOGADORES ", + players_4 = " 4 JOGADORES ", } - - --- 6. Faxes - - --[[ - epidemic = { - cover_up_explanation_1 = "Или вы можете попытаться вылечить всех зараженных, пока про это не узнали в министерстве здравоохранения.", - cover_up_explanation_2 = "Если к приезду инспектора эпидемия все еще будет бушевать, приготовьтесь к неприятностям.", - choices = { - cover_up = "Попытаться вылечить всех зараженных пациентов пока есть время и пока он еще в больнице.", - declare = "Объявить об эпидемии. Признать свою вину и заплатить штраф.", - }, - disease_name = "Ваши доктора обнаружили особо заразный подвид %s.", - declare_explanation_fine = "Вы можете объявить об эпидемии, заплатить штраф в %d$, тогда вам немедленно окажут помощь в вакцинации. Ваша репутация несколько пострадает.", - }, - epidemic_result = { - fine_amount = "Правительство объявило чрезвычайное положение, а вас оштрафовали на %d$.", - close_text = "Ура!", - hospital_evacuated = "У комиссии не осталось другого выбора, кроме как объявить эвакуацию.", - succeeded = { - part_1_name = "До департамента здоровья дошли слухи, что в вашей больнице бушует эпидемия %s.", - part_2 = "Однако, инспектору не удалось найти им подтверждение.", - }, - compensation_amount = "Правительство решило компенсировать ущерб, который эти враки нанесли репутации вашей больницы, в сумме %d$.", - failed = { - part_1_name = "В попытке скрыть наличие заразной инфекции %s,", - part_2 = "ваши сотрудники вызвали распространение болезни по округе.", - }, - rep_loss_fine_amount = "Журналисты уже заточили карандаши. Ваша репутация серьезно пострадает. К тому же, вас оштрафовали на %d$.", - }, - --]] - -fax = { - -- VIP - vip_visit_query = { - choices = { - invite = "Enviar um convite oficial ao V.I.P.", - refuse = "Despiste o V.I.P. com desculpas.", - }, - vip_name = "%s expressou a vontade de visitar seu hospital", - }, - vip_visit_result = { - --telegram = "Телеграмма!", - remarks = { - --good = { - -- [1] = "Какая хорошая больница! Спасибо за приглашение.", - -- [2] = "Хмм... Определенно, неплохое медицинское учреждение.", - -- [3] = "Мне очень понравилась ваша милая больничка. Ну, кто со мной в ресторан?", - --}, - super = { - [1] = "É um super hospital! Eu deveria saber, já estive aqui algumas vezes.", - }, - --[[ - bad = { - [1] = "Не надо было мне приходить. Лучше бы я просидел четырехчасовую оперу!", - [2] = "Мне до сих пор не по себе. Они правда называют свое заведение больницей? Больше похоже на свинарник!", - [3] = "Я сыт по горло визитами в подобные выгребные ямы и постоянным вниманием прессы! Я подаю в отставку.", - }, - mediocre = { - [1] = "Что ж, я видал и похуже. Им есть куда расти.", - [2] = "Не знаю, стоит ли туда обращаться, если почувствуете себя неважно.", - [3] = "Что я могу сказать, больница как больница. Я ожидал большего.", - }, - very_bad = { - [1] = "Ну и свалка! Я приложу все усилия чтобы ее закрыли.", - [2] = "Никогда не видел больницы хуже. Какой позор!", - [3] = "Я потрясен. Это нельзя назвать больницей! Мне надо выпить.", - }, - - --]] - -- tem good? Recebi um 'Now that's what I call a hospital' - }, - rep_boost = "Sua reputação na comunidade acaba de aumentar.", - vip_remarked_name = "Após visitar seu hospital, %s declarou:", - cash_grant = "Você foi recompensado com uma quantia de $ %d.", - --rep_loss = "Ваша репутация пострадала.", - close_text = "Obrigado por visitar o hospital.", - - }, - -- Descoberta de Nova Doença - disease_discovered = { - discovered_name = "Sua equipe descobriu uma nova condição : %s", - }, - - disease_discovered_patient_choice = { - need_to_build = "Você precisa construir um %s para lidar com ela.", - --need_to_employ = "Наймите %s чтобы вылечить это.", - what_to_do_question = "O que deve ser feito com o paciente ?", - --guessed_percentage_name = "Мы не совсем уверены, что с этим пациентом. Существует вероятность в %d% что это %s", - choices = { - send_home = "Mandar o paciente para casa", - research = "Encaminhar o paciente ao Departamento de Pesquisas.", - wait = "Pedir ao paciente esperar um pouco no Hospital.", - }, - disease_name = "Sua equipe descobriu uma nova condição: %s", - --need_to_build_and_employ = "Можно будет попробовать, если вы построите %s и наймете %s .", - can_not_cure = "Você não pode curar esta doença.", - }, - diagnosis_failed = { - choices = { - send_home = "Enviar o Paciente para casa.", - take_chance = "Dar ao Paciente um possibilidade de cura.", - wait = "Pedir ao Paciente aguardar enquanto você construir mais salas de diagnóstico.", - }, - situation = "Nós esgotamos todas as possibilidades de diagnóstico e ainda não temos certeza do que há de errado com o paciente.", - what_to_do_question = "O que deve ser feito com o paciente ?", - partial_diagnosis_percentage_name = "Existe, entretanto, uma possibilidade de %d% de termos identificado que tipo de %s o paciente contraiu.", - }, - --[[ - emergency = { - locations = { - [1] = "Новоуренгойский химзавод", - [2] = "Фальшивый Университет", - [3] = "Центр Принудительного Озеленения", - [4] = "Институт Разработки Опасных Штук", - [5] = "Клуб Хороших Танцоров", - [6] = "Издательство «МакулатураПресс»", - [7] = "Похоронное бюро «Безенчук и нимфы»", - [8] = "Китайский ресторанчик дяди Вонга", - [9] = "ГлавХимСбытСтыдЗагранПоставка", - }, - num_disease = "У нас тут %d человек с диагнозом %s и им требуется немедленное лечение.", - cure_possible_drug_name_efficiency = "У вас есть все необходимое оборудование и специалисты. У вас есть нужное лекарство. Это %s и оно эффективно на %d%", - cure_not_possible_employ = "Вам потребуется нанять %s", - cure_not_possible = "Сейчас вы не можете это вылечить.", - cure_possible = "У вас есть все необходимое оборудование и специалисты, так что вы, наверное, справитесь.", - choices = { - accept = "Да. Я разберусь с этой ситуацией.", - refuse = "Нет. Я отказываюсь в этом участвовать.", - }, - location = "На предприятии %s чрезвычайная ситуация.", - cure_not_possible_build = "Вам надо будет построить %s", - cure_not_possible_build_and_employ = "Вам надо будет построить %s и нанять %s", - bonus = "Вознаграждение за помощь составит %d. Если вы не справитесь, ваша репутация серьезно пострадает.", - }, - --]] - emergency_result = { - earned_money = "De um bônus total de $ %d, você ganhou $ %d.", - close_text = "Clique para sair.", - saved_people = "Você salvou %d de um total de %d pacientes.", - }, -} - -------------------------------- OVERRIDE ---------------------------------- -adviser.warnings.money_low = "Você está ficando sem dinheiro!" -- Funny. Exists in German translation, but not existent in english? --- TODO: tooltip.graphs.reputation -- this tooltip talks about hospital value. Actually it should say reputation. --- TODO: tooltip.status.close -- it's called status window, not overview window. - --- tooltip.staff_list.next_person, prev_person is rather next/prev page (also in german, maybe more languages?) -tooltip.staff_list.next_person = "Próxima página" -tooltip.staff_list.prev_person = "Página anterior" -tooltip.status.reputation = "Sua reputação não deve ficar abaixo de %d. Atualmente é de %d" -tooltip.status.balance = "Seu saldo bancário não deve vicar abaixo de %d. Atualmente é de %d" - --- The originals of these two contain one space too much -fax.emergency.cure_not_possible_build = "Você precisará construir um(a) %s" -fax.emergency.cure_not_possible_build_and_employ = "Você precisará construir um(a) %s e empregar um(a) %s" -fax.emergency.num_disease = "Existem %d pessoas com %s e eles precisam urgente de sua atenção." -adviser.goals.lose.kill = "Se matar mais %d pacientes perderá esta fase!" - --- Improve tooltips in staff window to mention hidden features -tooltip.staff_window.face = "This person's face - click to open management screen" -tooltip.staff_window.center_view = "Clique com o botão esquerdo para dar um zoom no quadro de funcionários e botão direito para circular membros da equipe" - --- These strings are missing in some versions of TH (unpatched?) -confirmation.restart_level = "Tem certeza que deseja reiniciar esta fase?" --- TODO adviser.multiplayer.objective_completed --- TODO adviser.multiplayer.objective_failed - -------------------------------- NEW STRINGS ------------------------------- -date_format = { - daymonth = "%1% %2:months%", -} - -object.litter = "Lixo" -tooltip.objects.litter = "Lixo: Um paciente jogou no chão porque não achou uma lixeira próxima." - -tooltip.fax.close = "Fechar esta janela sem apagar a mensagem" -tooltip.message.button = "Clique com o botão esquerdo para abrir a mensagem" -tooltip.message.button_dismiss = "Clique com o botão esquerdo para abrir a mensagem, e com o botão direito para descartá-la" -tooltip.casebook.cure_requirement.hire_staff = "Você precisa contratar funcionários para administrar este tratamento" -tooltip.casebook.cure_type.unknown = "Você ainda não sabe como tratar esta doença" -tooltip.research_policy.no_research = "Nenhuma pesquisa desta categoria está sendo conduzida neste momento" -tooltip.research_policy.research_progress = "Progresso para uma nova descoberta nesta categoria: %1%/%2%" - - adviser = { - room_forbidden_non_reachable_parts = "Construir a sala neste local resultará em alas do hospital que não poderão ser acessadas.", + room_forbidden_non_reachable_parts = "Construir a sala neste local resultará em alas do hospital que näo poderäo ser acessadas.", warnings = { - no_desk = "Você precisa comprar um balcão de recepção e contratar uma recepcionista em algum momento!", - no_desk_1 = "Se você quer que os pacientes venham ao seu hospital, você precisa contratar uma recepcionista e comprar um balcão para recepcioná-los!", - no_desk_2 = "Excelente, isso provavelmente é um recorde mundial - quase um ano e nenhum paciente! Se você deseja continuar administrando este hospital, você precisa urgente contratar uma recepcionista e comprar um balcão para que ela possa trabalhar!", - no_desk_3 = "That's just brilliant, nearly a year and you don't have a staffed reception! How do you expect to get any patients, now get it sorted out and stop messing around!", - cannot_afford = "Seu saldo bancário é insuficiente para contratar esta pessoa!", -- I can't see anything like this in the original strings - falling_1 = "Hey! Isso não é engraçado, cuidado onde aponta este mouse; alguém pode se machucar!", + no_desk = "Você precisa comprar um balcäo de recepçäo e contratar uma recepcionista em algum momento!", + no_desk_1 = "Se você quer que os pacientes venham ao seu hospital, você precisa contratar uma recepcionista e comprar um balcäo para recepcioná-los!", + no_desk_2 = "Excelente, isso provavelmente é um recorde mundial - quase um ano e nenhum paciente! Se você deseja continuar administrando este hospital, você precisa urgente contratar uma recepcionista e comprar um balcäo para que ela possa trabalhar!", + no_desk_3 = "Brilhante, se passou quase um ano e ainda näo tem uma recepcionista! Como quer que os pacientes apareçam? Arrume uma recepcionista e deixe de perder tempo!", + no_desk_4 = "Uma recepcionista necessita de uma mesa para atender os pacientes que aparecem.", + no_desk_5 = "Já era hora! Os pacientes começaräo a chegar logo.", + no_desk_6 = "Você tem uma recepcionista, que tal se construir uma mesa de recepçäo para que possa trabalhar?", + no_desk_7 = "Você construiu a mesa da recepçäo, entäo que tal contratar um recepcionista? Você näo receberá nenhum paciente até que contrate uma.", + cannot_afford = "Seu saldo bancário é insuficiente para contratar esta pessoa!", + cannot_afford_2 = "Näo tem dinheiro para comprar isso!", + falling_1 = "Ei! Isso näo é engraçado, cuidado onde aponta este mouse; alguém pode se machucar!", falling_2 = "Gostou da queda? Pare de bagunçar!", falling_3 = "Ai, isso dói, alguém chame um médico!", - falling_4 = "Isto é um Hospital, não um parque de diversões!", - falling_5 = "Este não é o local para empurar as pessoas, elas estão doentes sabia?!", - falling_6 = "Aqui não é uma pista de boliche, pessoas doentes não deveriam ser tratadas desta forma!", - research_screen_open_1 = "Você precisa construir um Departamento de Pesquisas antes de acessar a tela de Pesquisas.", - research_screen_open_2 = "Pesquisas estão desabilitadas nesta fase.", + falling_4 = "Isto é um Hospital, näo um parque de diversöes!", + falling_5 = "Este näo é o local para empurrar as pessoas, elas estäo doentes sabia?!", + falling_6 = "Aqui näo é uma pista de boliche, pessoas doentes näo deveriam ser tratadas desta forma!", + research_screen_open_1 = "Para acessar a tela de pesquisa, tem que construir um Centro de Pesquisa.", + research_screen_open_2 = "Näo é possível realizar pesquisas nessa fase.", + researcher_needs_desk_1 = "Uma pesquisa necessita de uma mesa para trabalhar.", + researcher_needs_desk_2 = "Seu pesquisador agradece que lhe tenha dado um descanso. Se pretende ter mais pessoas pesquisando, deve dar a cada um uma mesa para trabalhar.", + researcher_needs_desk_3 = "Cada pesquisa necessita de uma mesa para trabalhar.", + nurse_needs_desk_1 = "Cada enfermeira necessita de uma mesa para trabalhar.", + nurse_needs_desk_2 = "Sua enfermeira agradece que lhe tenha dado um descanso. Se pretende ter mais pessoas trabalhando na enfermaria, tem que dar a cada uma delas uma mesa para trabalhar.", + low_prices = "Você está cobrando muito pouco pelo uso de %s. Isto trará pessoas para o seu hospital, mas você näo fará muito lucro com cada uma delas.", + high_prices = "Você está cobrando muito pelo uso de %s. Isto trará grande lucro a curto prazo, mas no final das contas você começará a afugentar as pessoas para longe do seu hospital.", + fair_prices = "O preço de %s parece justo.", + patient_not_paying = "Um paciente se foi sem pagar por %s porque é muito caro!", }, cheats = { th_cheat = "Parabéns, você habilitou os códigos de trapaça!", - crazy_on_cheat = "Oh não! Todos os médicos ficaram malucos!", - crazy_off_cheat = "Ufa… o médicos recobraram sua sanidade.", roujin_on_cheat = "Desafio Roujin ativado! Boa sorte...", roujin_off_cheat = "Desafio Roujin desativado.", - hairyitis_cheat = "Trapaça de Cabelulite ativada!", - hairyitis_off_cheat = "Trapaça de Cabelulite desativada.", - bloaty_cheat = "Bloaty Head cheat activated!", - bloaty_off_cheat = "Bloaty Head cheat deactivated.", }, } -dynamic_info.patient.actions.no_gp_available = "Waiting for you to build a GP's office" -dynamic_info.staff.actions.heading_for = "Indo para %s" -dynamic_info.staff.actions.fired = "Demitido" +dynamic_info.patient.actions.no_gp_available = "Esperando que construa um Consultório Geral" +dynamic_info.staff.actions.heading_for = "Dirigindo-se para %s" +dynamic_info.staff.actions.fired = "Despedido" +dynamic_info.patient.actions.epidemic_vaccinated = "Eu näo sou mais contagioso" -progress_report.free_build = "CONSTRUÇÃO LIVRE" +progress_report.free_build = "CONSTRUÇAO LIVRE" fax = { choices = { - return_to_main_menu = "Retornar ao menu principal", - accept_new_level = "Ir para a próxima fase", - decline_new_level = "Continuar jogando nesta fase um pouco mais", + return_to_main_menu = "Voltar para menu principal", + accept_new_level = "Ir para o próximo nível", + decline_new_level = "Continuar jogando um pouco mais", }, emergency = { - num_disease_singular = "Existe uma pessoa com %s que precisa urgente de sua atenção.", - free_build = "Se você for bem sucedido sua reputação aumentará, mas se você falhar sua reputação será bastante prejudicada.", + num_disease_singular = "Existe uma pessoa com %s que precisa urgente de sua atençäo.", + free_build = "Se você for bem sucedido sua reputaçäo aumentará, mas se você falhar sua reputaçäo será bastante prejudicada.", }, vip_visit_result = { remarks = { free_build = { - "Que hospital maravilhoso! Não é tão difícil manter tudo funcionando com dinheiro ilimitado, não é mesmo?", - "Eu não sou economista, mas acho que eu também conseguiria administrar esse hospital, se é que você me entende...", - "Um hospital em ótimo funcionamento. Mas cuidado com a recessão! Ah, me esqueci... você não teve que se preocupar com isso.", + "Seu hospital é muito bom! Näo é difícil mantê-lo sem limitaçöes econômicas, né?", + "Näo sou economista, mas até eu poderia dirigir este hospital, se é que você me entende...", + "Um hospital muito bem cuidado. Mas tome cuidado a crise financeira! Certo... você näo tem que se preocupar com isso.", } } } } letter = { - dear_player = "Prezado(a) %s", - custom_level_completed = "Parabéns! Você completou todos os objetivos desta fase customizada!", + dear_player = "Prezado(a) %s\n", + custom_level_completed = "Parabéns! Você completou todos os objetivos desta fase personalizada!", return_to_main_menu = "Deseja retornar ao menu principal ou continuar jogando?", + campaign_level_completed = "Bom trabalho! Você superou este nível, mas ainda näo acabou!\n Você se interessaria em aceitar um posto no hospital %s?", + campaign_completed = "Incrível! Você conseguiu superar todos os níveis. Já pode relaxar e desfrutar enquanto fala das suas realizaçöes nos fóruns de toda a Internet. Boa sorte!", + campaign_level_missing = "Desculpe, parece que o próximo nível desta campanha está faltando. (Nome: %s)", } install = { - title = "--------------------------------- CorsixTH Setup ---------------------------------", - th_directory = "CorsixTH precisa de uma cópia dos arquivos de dados do jogo original - Theme Hospital (ou demo) para executar. Utilize o seletor abaixo para localizar o diretório onde o jogo Theme Hospital está instalado.", + title = "----------------------- Configuraçäo do CorsixTH -----------------------", + th_directory = "O CorsixTH precisa de uma cópia dos arquivos de dados do Theme Hospital original (ou a demo) para executar. Utilize o seletor abaixo para localizar o diretório onde o jogo Theme Hospital está instalado.", + ok = "OK", exit = "Sair", + cancel = "Cancelar", } -misc.not_yet_implemented = "(não foi implementado ainda)" -misc.no_heliport = "Ou você ainda não descobriu nenhuma doença ou este hospital não possui heliporto. Você pode também necessitar construir uma recepção e contratar uma recepcionista." +misc.not_yet_implemented = "(ainda näo implementado)" +misc.no_heliport = "Uma das doença ainda näo foi descoberta, ou näo existe um heliporto neste mapa. Talvez precise comprar uma mesa de recepçäo e contratar a uma recepcionista." +main_menu = { + new_game = "Campanha", + custom_campaign = "Campanha Personalizada", + custom_level = "Cenário Personalizado", + continue = "Continuar Jogo", + load_game = "Carregar Jogo", + options = "Configuraçöes", + map_edit = "Editor de Mapa", + savegame_version = "Versäo do jogo salvo: ", + version = "Versäo: ", + exit = "Sair", +} +tooltip.main_menu = { + new_game = "Começar o primeiro nível da campanha", + custom_campaign = "Jogar uma campanha criada pela comunidade.", + custom_level = "Construir seu hospital em um cenário único", + continue = "Continuar seu último jogo salvo.", + load_game = "Carregar um jogo salvo", + options = "Ajustar várias configuraçöes", + map_edit = "Criar um mapa personalizado", + exit = "Näo, näo, por favor, näo vá", + quit = "Você deseja realmente sair do CorsixTH?", +} +load_game_window = { + caption = "Carregar Jogo (%1%)", +} +tooltip.load_game_window = { + load_game = "Carregar jogo %s", + load_game_number = "Carregar jogo %d", + load_autosave = "Carregar jogo salvo automaticamente", +} +custom_game_window = { + caption = "Jogo Personalizado", + free_build = "Construçäo Livre", + load_selected_level = "Iniciar", +} -tooltip.handyman_window = { - parcel_select = "O prédio no qual este funcionário executará suas tarefas, clique para mudar" +tooltip.custom_game_window = { + choose_game = "Clique em um nível para ver mais informaçäo sobre o mesmo.", + free_build = "Marque esta opçäo se quiser jogar sem dinheiro nem condiçöes de vitória ou derrota.", + load_selected_level = "Carregar e jogar o nível selecionado", +} + +custom_campaign_window = { + caption = "Campanha Personalizada", + start_selected_campaign = "Iniciar Campanha", +} + +tooltip.custom_campaign_window = { + choose_campaign = "Selecione uma campanha para ver mais informaçäo sobre a mesma.", + start_selected_campaign = "Carregar o primeiro nível desta campanha", +} + +save_game_window = { + caption = "Salvar Jogo (%1%)", + new_save_game = "Novo jogo salvo", +} + +tooltip.save_game_window = { + save_game = "Substituir jogo salvo %s", + new_save_game = "Digite um nome para o jogo salvo.", +} + +save_map_window = { + caption = "Salvar Mapa (%1%)", + new_map = "Novo Mapa", +} + +tooltip.save_map_window = { + map = "Substituir mapa %s", + new_map = "Digite um nome para o novo mapa salvo", +} + +menu_list_window = { + name = "Nome", + save_date = "Modificado", + back = "Voltar", +} + +tooltip.menu_list_window = { + name = "Aperte aqui para ordenar a lista por nomes", + save_date = "Aperte aqui para ordenar a lista pela última data de modificaçäo", + back = "Fechar esta janela.", +} + +options_window = { + caption = "Configuraçöes", + option_on = "Ligar", + option_off = "Desligar", + fullscreen = "Tela Cheia", + resolution = "Resoluçäo", + capture_mouse = "Capturar Mouse", + custom_resolution = "Personalizar...", + width = "Largura", + height = "Altura", + audio = "Audio Geral", + customise = "Personalizar", + folder = "Pastas", + language = "Idioma do Jogo", + apply = "Aplicar", + cancel = "Cancelar", + back = "Voltar", +} + +tooltip.options_window = { + fullscreen = "Se o jogo deve ser executado em tela cheia ou modo janela", + fullscreen_button = "Clique para mudar para tela cheia", + resolution = "A resoluçäo que o jogo deve ser executado", + select_resolution = "Selecionar uma nova resoluçäo", + capture_mouse = "Clique para alternar a captura do cursor na janela do jogo", + width = "Digite a largura desejada", + height = "Digite a altura desejada", + apply = "Aplicar a resoluçäo digitada", + cancel = "Voltar sem mudar a resoluçäo", + audio_button = "Ligar ou desligar o áudio de todo o jogo", + audio_toggle = "Alternar entre ligado e desligado", + customise_button = "Você pode alterar mais configuraçöes para personalizar sua experiência de jogo", + folder_button = "Opçöes de pasta", + language = "O idioma em que os textos do jogo apareceräo", + select_language = "Selecione o idioma do jogo", + language_dropdown_item = "Selecionar %s como idioma", + back = "Fechar a janela de Configuraçöes", +} + +customise_window = { + caption = "Config. Personalizadas", + option_on = "Ligado", + option_off = "Desligado", + back = "Voltar", + movies = "Vídeo Geral", + intro = "Vídeo de Introduçäo", + paused = "Construir em Pausa", + volume = "Tecla de Volume", + aliens = "Pacientes Alienígenas", + fractured_bones = "Ossos Fraturados", + average_contents = "Conteúdos Habituais", +} + +tooltip.customise_window = { + movies = "Controle geral de vídeos, que permitirá a você desativar todos os vídeos", + intro = "Desligar ou ligar o vídeo de introduçäo, vídeos gerais precisaräo estar ligados se você quiser o vídeo de introduçäo rode quando você carregar o CorsixTH", + paused = "No Theme Hospital o jogador só teria permissäo para utilizar o menu superior se o jogo estivesse pausado. Esta é também a configuraçäo padräo no CorsixTH, mas habilitando isso você tem permissäo para acessar tudo enquanto o jogo está pausado", + volume = "Se a tecla de baixar volume abrir também a ficha clínica, utilize esta opçäo para mudar o atalho para direto a ficha clínica para Shift + C.", + aliens = "Devido à falta de animaçöes decentes disponíveis, fizemos com que os pacientes com DNA alienígena só apareçam em uma emergência. Para permitir que os pacientes com DNA alienígena possam visitar seu hospital, desative esta opçäo.", + fractured_bones = "Devido a uma animaçäo deficiente, fizemos que näo existam pacientes com Fraturas ósseas femininas. Para permitir que as pacientes com Fraturas ósseas visitem seu hospital, desative esta opçäo.", + average_contents = "Se você quiser que o jogo lembre que objetos extras você normalmente adiciona quando constrói salas, entäo ligue esta opçäo", + back = "Fecha este menu e volta para o Menu de Configuraçöes", +} + +folders_window = { + caption = "Localizaçäo de Pastas", + data_label = "Dados do TH", + font_label = "Fonte", + music_label = "Músicas", + savegames_label = "Jogos Salvos", + screenshots_label = "Capturas de Tela", + -- next four are the captions for the browser window, which are called from the folder setting menu + new_th_location = "Aqui pode especificar uma nova pasta de instalaçäo do Theme Hospital. O jogo será reiniciado assim que selecionar a nova pasta.", + savegames_location = "Selecione a pasta que quer utilizar para seus jogos salvos.", + music_location = "Selecione a pasta que quer utilizar para sua música.", + screenshots_location = "Selecione a pasta que quer utilizar para suas capturas de tela.", + back = "Voltar", +} + +tooltip.folders_window = { + browse = "Procurar a localizaçäo da pasta", + data_location = "A pasta com a instalaçäo do Theme Hospital original, necessário para executar o CorsixTH", + font_location = "A localizaçäo de uma fonte de letra capaz de mostrar caracteres Unicode necessários para seu idioma. Se näo for indicado, näo poderá selecionar idiomas que tenham mais caracteres dos que o jogo original tem, por exemplo, russo e chinês.", + savegames_location = "A pasta de jogos salvos é localizada por padräo junto com o arquivo de configuraçäo e é utilizado para armazenar os jogos salvo. Se você näo gostar, pode selecionar outra procurando a pasta que quiser usar.", + screenshots_location = "As capturas de tela säo guardadas por padräo em uma pasta junto com o arquivo de configuraçäo. Se você näo gostar, pode selecionar outra procurando a pasta que quiser usar.", + music_location = "Selecione uma pasta com seus arquivos de música. Necessita de uma pasta já existente, entäo poderá procurá-la.", + browse_data = "Procurar outra localizaçäo com uma instalaçäo do Theme Hospital. (Localizaçäo atual: %1%)", + browse_font = "Procurar outro arquivo de fonte de letra. (Localizaçäo atual: %1%)", + browse_saves = "Procurar outra localizaçäo para sua pasta de jogos salvos. (Localizaçäo atual: %1%) ", + browse_screenshots = "Procurar outra localizaçäo para sua pasta de capturas de tela. (Localizaçäo atual: %1%) ", + browse_music = "Procurar outra localizaçäo para sua pasta de música. (Localizaçäo atual: %1%) ", + no_font_specified = "Pasta de fontes näo especificada!", + not_specified = "Pasta näo especificada!", + default = "Localizaçäo padräo", + reset_to_default = "Volta a atribuir a pasta a sua localizaçäo padräo", + -- original_path = "The currently chosen directory of the original Theme Hospital installation", -- where is this used, I have left if for the time being? + back = "Fechar este menu e voltar para o menu de Configuraçöes", +} + +font_location_window = { + caption = "Selecionar fonte (%1%)", } handyman_window = { - all_parcels = "Todos os prédios", - parcel = "Prédio" + all_parcels = "Todas as parcelas", + parcel = "Parcela" +} + +tooltip.handyman_window = { + parcel_select = "Parcela onde o faz-tudo aceita tarefas, clique para alterar o configuraçäo" } +new_game_window = { + caption = "Campanha", + player_name = "Nome", + option_on = "Ligado", + option_off = "Desligado", + difficulty = "Dificuldade", + easy = "Residente (Fácil)", + medium = "Médico (Normal)", + hard = "Consultor (Difícil)", + tutorial = "Tutorial", + start = "Iniciar", + cancel = "Cancelar", +} +tooltip.new_game_window = { + player_name = "Digite o nome que você deseja ser chamado no jogo", + difficulty = "Selecione o nível de dificuldade do jogo", + easy = "Se você näo conhecer jogos de simulaçäo, esta dificuldade é para você.", + medium = "Esta é a dificuldade intermediária, se você está inseguro do que deve escolher.", + hard = "Se você está acostumado com este tipo de jogo e quer um bom desafio, escolha esta opçäo", + tutorial = "Se você precisa de ajuda para começar a jogar, escolha esta opçäo", + start = "Iniciar o jogo com a configuraçäo selecionada", + cancel = "Ah, eu näo queria começar um novo jogo!", +} + +lua_console = { + execute_code = "Executar", + close = "Fechar", +} + +tooltip.lua_console = { + textbox = "Digite aqui o código Lua que deseja executar", + execute_code = "Executar o código Lua que digitou", + close = "Fechar o console", +} errors = { - dialog_missing_graphics = "Desculpe, os arquivos de dados da demo não contém este diálogo.", - save_prefix = "Erro ao salvar jogo: ", - load_prefix = "Erro ao carregar jogo: ", - map_file_missing = "Não foi possível encontrar o arquivo de mapa %s para esta fase!", - minimum_screen_size = "Favor digitar dimensões de tela de pelo menos 640x480.", - maximum_screen_size = "Favor digitar dimensões de tela de no máximo 3000x2000.", - unavailable_screen_size = "O tamanho da tela que você digitou não está disponível em tela cheia.", + dialog_missing_graphics = "Desculpe, os arquivos de dados da versäo de demonstraçäo näo contém este diálogo.", + save_prefix = "Erro ao salvar o jogo: ", + load_prefix = "Erro ao carregar o jogo: ", + no_games_to_contine = "Näo há jogos salvos.", + load_quick_save = "Erro, näo foi possível carregar o carregamento rápido já que ele näo existe, näo se preocupe nós criamos um agora para você!", + map_file_missing = "Näo foi possível encontrar o arquivo de mapa %s para esta fase!", + minimum_screen_size = "Por favor, digite dimensöes de tela de pelo menos 640x480.", + unavailable_screen_size = "O tamanho da tela que você digitou näo está disponível em tela cheia.", + alien_dna = "NOTA: Os pacientes alienígenas näo têm animaçöes para se sentar, abrir portas, bater nas portas, etc. portanto, assim como no Theme Hospital original, ao fazer estas coisas aparentaräo mudar para uma imagem normal e logo voltaräo para o seu estado. Os pacientes com DNA alienígena só apareceräo se o arquivo de fase o indicar", + fractured_bones = "NOTA: A animaçäo das pacientes femininas com Fraturas ósseas näo é perfeita", + could_not_load_campaign = "Falha ao carregar a campanha: %s", + could_not_find_first_campaign_level = "Näo foi possível encontrar o primeiro nível desta campanha: %s", +} + +warnings = { + levelfile_variable_is_deprecated = "Aviso: O nível '%s ' contém uma definiçäo variável obsoleta no arquivo de nível." .. + " '%LevelFile' foi renomeado para '%MapFile '. Por favor, informe ao criador do mapa para atualizar o nível.", } confirmation = { - needs_restart = "Para alterar esta configuração é necessário reiniciar o CorsixTH. Qualquer alteração não salva será perdida. Tem certeza que deseja fazer isso?", - abort_edit_room = "Você está editando uma sala. Se todos os objetos necessário estiverem colocados ela será completada, caso contrário ela será removida. Continuar?", + needs_restart = "Para alterar esta configuraçäo é necessário reiniciar o CorsixTH. Qualquer alteraçäo näo salva será perdida. Tem certeza que deseja fazer isso?", + abort_edit_room = "Você está editando uma sala. Se todos os objetos necessários estiverem colocados ela será completada, caso contrário ela será removida. Continuar?", + maximum_screen_size = "O tamanho de tela que digitou é maior que 3000 x 2000. É possível utilizar uma resoluçäo maior, mas necessitará de um computador melhor para que a velocidade de quadros por segundo seja aceitável. Tem certeza de que quer continuar?", + music_warning = "Antes de selecionar o uso de MP3 para sua música dentro do jogo, precisará ter o arquivo smpeg.dll, ou o equivalente para seu sistema operacional, ou do contrário näo terá música no jogo. Atualmente näo existe um arquivo equivalente para sistemas de 64 bits. Deseja continuar?", } information = { - custom_game = "Bem-vindo ao CorsixTH. Se divirta neste mapa personalizado!", - no_custom_game_in_demo = "Desculpe, mas a versão de demonstração não pode jogar mapas pesonalizados.", - cannot_restart = "Infelizmente este mapa personalizado foi salvo antes que a funcionalidade de reiniciação fosse implementada.", - very_old_save = "Houveram muitas mudanças no jogo desde que você começou a jogar este mapa. Para ter certeza que todas as funcionalidades estão funcionando considere recomeçar o mapa.", + custom_game = "Bem-vindo ao CorsixTH. Divirta-se com esse mapa personalizado!", + no_custom_game_in_demo = "Desculpe, mas a versäo de demonstraçäo näo pode jogar mapas personalizados.", + cannot_restart = "Infelizmente este mapa personalizado foi salvo antes que a funcionalidade de reiniciaçäo fosse implementada.", + very_old_save = "Houveram muitas mudanças no jogo desde que você começou a jogar este mapa. Para ter certeza que todas as funcionalidades estäo funcionando considere recomeçar o mapa.", level_lost = { - "Parabéns! Você perdeu a fase. Mais sorte na próxima vez!", + "Que pena! Você fracassou. Mais sorte na próxima vez!", "Você perdeu porque:", - reputation = "Sua reputação caiu abaixo de %d.", + reputation = "Sua reputaçäo caiu abaixo de %d.", balance = "Seu saldo no banco caiu abaixo de %d.", - percentage_killed = "Você matou mais de %d porcento dos pacientes.", + percentage_killed = "Você matou mais de %d por cento dos pacientes.", + cheat = "Foi escolha sua ou você se enganou de botäo? Näo sabe nem trapacear direito?", }, - cheat_not_possible = "Você não pode usar esta trapaça nesta fase. Até na hora de trapacear você falha, irônico não?", + cheat_not_possible = "Näo pode usar essa trapaça nesta fase. Näo sabe nem trapacear direito?", } tooltip.information = { - close = "Fechar a janela de informações", + close = "Fechar a janela de informaçäo", } +totd_window = { + tips = { + "Todo hospital precisa de uma Recepçäo e um Consultório Geral para começar. Depois disso, dependerá do tipo de pacientes que visitará seu hospital. Entretanto ter uma farmácia é sempre uma boa ideia.", + "Máquinas como o Inflador precisam de constante manutençäo. Contrate um ou dois Faz-tudo para reparos nestas máquinas, ou colocará seus funcionários e pacientes em risco.", + "Depois de um certo período de trabalho, seus funcionários ficaräo cansados. Certifique-se de construir uma Sala de Descanso, para que posam relaxar.", + "Instale Radiadores suficientes para manter seus funcionários e pacientes aquecidos, do contrário ficaräo infelizes. Use o Mapa da Cidade para localizar pontos do hospital que precisem ser aquecidos.", + "O nível de habilidade de um médico reflete na qualidade e velocidade dos diagnósticos. Coloque um médico experiente no Consultório Geral, assim näo precisará de muitas salas de diagnósticos adicionais.", + "Médicos de níveis 'Residente' e 'Médico' podem melhorar suas habilidades aprendendo com um Consultor na Sala de Treinamento. Se o Consultor possuir alguma especializaçäo (Cirurgiäo, Psiquiatra ou Pesquisador), ele irá passar este conhecimento aos seus alunos.", + "Você já tentou digitar o número europeu de emergência (112) no aparelho de fax? Certifique-se que o seu som esteja ligado!", + "Você pode alterar algumas configuraçöes como a resoluçäo da tela e o idioma na janela de opçöes que pode ser acessar no menu inicial e dentro do jogo.", + "Você selecionou um idioma que näo é o inglês, mas continua vendo textos em inglês por todos os lugares? Ajude-nos a traduzir os textos restantes para o seu idioma!", + "A comunidade do CorsixTH está precisando de reforços em sua equipe! Você está interessado em codificar, traduzir ou criar gráficos para o CorsixTH? Entre em contato conosco pelo nosso Fórum, Lista de Discussäo ou canal de IRC (#corsix-th no freenode).", + "Se localizar um bug, por favor reporte-o em nosso bugtracker: th-issues.corsix.org", + "Cada fase possui certas metas a serem atingidas antes de passar para a próxima fase. Cheque a janela de situaçäo para acompanhar seu progresso a fim de atingir seus objetivos.", + "Se você deseja editar ou remover uma sala existente, pode fazê-lo com o botäo de ediçäo de sala na barra inferior.", + "Caso haja uma multidäo de pacientes esperando, você deve descobrir rapidamente quais deles estäo aguardando por uma sala em particular passando o ponteiro do mouse por cima desta sala.", + "Clique nas portas das salas para ver sua fila. Isso pode ser muito útil, já que pode reordenar a fila ou encaminhar um paciente para outra sala.", + "Funcionários infelizes iräo pedir aumentos de salários com mais frequência. Certifique-se que sua equipe esteja trabalho em um ambiente de trabalho confortável para mantê-los felizes.", + "Pacientes podem ficar com sede enquanto esperam em seu hospital, ainda mais se ligar o aquecimento! Instale máquinas de venda de refrigerantes em pontos estratégicos para um ganho extra.", + "Você pode abortar o processo de diagnóstico prematuramente e pressupor a cura, se você já tiver descoberto a doença. Atente-se que desta maneira aumenta-se o risco de um tratamento errado, resultando na morte do paciente.", + "Emergências podem ser uma boa fonte de grana extra, desde que você possua plena capacidade e recursos de lidar com os pacientes à tempo.", + }, + previous = "Dica anterior", + next = "Próxima dica", +} +tooltip.totd_window = { + previous = "Mostra a dica anterior", + next = "Mostra a próxima dica", +} debug_patient_window = { caption = "Depurar Paciente", } cheats_window = { - caption = "Cheats/Trapaças", - warning = "Aviso: você não ganhará nenhum ponto bônus no final desta fase se você trapacear!", + caption = "Trapaças", + warning = "Atençäo: Você näo conseguirá quaisquer pontos de bonificaçöes no fim do nível se você trapacear!", cheated = { - no = "Trapaças usadas: Não", + no = "Trapaças usadas: Näo", yes = "Trapaças usadas: Sim", }, cheats = { - money = "Trapaça Financeira", + money = "Trapaça de Dinheiro", all_research = "Trapaça Todas as Pesquisas Realizadas", emergency = "Criar Emergência", - vip = "Criar visitante VIP", + vip = "Criar VIP", earthquake = "Criar Terremoto", + epidemic = "Gerar um paciente contagioso", + toggle_infected = "Alternar ícones de infectados", create_patient = "Criar Paciente", - end_month = "Final de Mês", - end_year = "Final de Ano", + end_month = "Fim do Mês", + end_year = "Fim do ano", lose_level = "Perder a Fase", win_level = "Ganhar a Fase", + increase_prices = "Aumentar Preços", + decrease_prices = "Reduzir Preços", }, close = "Fechar", } tooltip.cheats_window = { - close = "Fechar a janela de trapaças", + close = "Fecha a janela de trapaças", cheats = { - money = "Adicionar 10.000 no saldo bancário.", - all_research = "Completar todas as pesquisas.", - emergency = "Criar uma emergência.", - vip = "Criar um visitante VIP.", - earthquake = "Criar um terremoto.", - create_patient = "Criar um Paciente na borda do mapa.", - end_month = "Pular para o final do mês.", - end_year = "Pular para o final do ano.", - lose_level = "Perder esta fase.", - win_level = "Ganhar esta fase.", + money = "Adiciona 10.000 no saldo bancário.", + all_research = "Completa todas as pesquisas.", + emergency = "Cria uma emergência.", + vip = "Cria um visitante VIP.", + earthquake = "Cria um Terremoto.", + epidemic = "Cria um paciente contagioso", + toggle_infected = "Mostra/oculta os ícones de infecçäo", + create_patient = "Cria um Paciente no canto de mapa.", + end_month = "Pula para o final do mês.", + end_year = "Pula para o final do ano.", + lose_level = "Perde esta fase.", + win_level = "Ganha esta fase.", + increase_prices = "Aumenta todos os preços em 50% (200% máximo).", + decrease_prices = "Reduz todos os preços em 50% (50% mínimo).", } } +introduction_texts = { + demo = + "Bem-vindo ao hospital de demonstraçäo!//" .. + "Infelizmente esta versäo de demonstraçäo só possui esta fase. Entretanto, teremos aqui o suficiente para mantê-lo ocupado por enquanto! " .. + "Você encontrará várias doenças que necessitaräo de salas diferentes para cura. De tempos em tempos, emergências ocorreräo. E você precisará pesquisar por salas adicionais usando o Centro de Pesquisas. " .. + "Seu objetivo é ter um saldo bancário de $100.000,00, o valor do hospital em $ 70.000,00 e uma reputaçäo de 700, enquanto você cura pelo menos 75% de seus pacientes. " .. + "Certifique-se que sua reputaçäo näo fique abaixo de 300 e você näo mate mais de 40% dos seus pacientes, senäo você perde.//" .. + "Boa sorte!", +} + calls_dispatcher = { -- Dispatcher description message. Visible in Calls Dispatcher dialog summary = "%d chamadas; %d assinaladas", staff = "%s - %s", watering = "Regando @ %d,%d", - repair = "Consertar %s", + repair = "Reparar %s", close = "Fechar", } tooltip.calls_dispatcher = { task = "Lista de tarefas - clique na tarefa para abrir a janela do funcionário responsável e ir para o local da tarefa.", assigned = "Esta janela será marcada se alguém for designado para a tarefa correspondente.", - close = "Fechar a janela de calls dispatcher", -} - - - -staff_class = { - nurse = "Enfermeira", - doctor = "Doutor", - handyman = "Funcionário da Manutenção", - receptionist = "Recepcionista", - surgeon = "Cirurgião", + close = "Fechar a janela de chamadas de controle", } - - - --- Objects -object = { - desk = "Secretária", - cabinet = "Arquivo", - door = "Porta", - bench = "Banco", - table1 = "Mesa", -- unused object - chair = "Cadeira", - drinks_machine = "Máquina de Bebidas", - bed = "Cama", - inflator = "Inflador", - pool_table = "Mesa de Bilhar", - reception_desk = "Recepção", - table2 = "Mesa", -- unused object & duplicate - cardio = "Máquina de Eletrocardiograma", - scanner = "Scanner", - console = "Console", - screen = "Tela", - litter_bomb = "Bomba de lixo", - couch = "Sofá", - sofa = "Sofá", - crash_trolley = "Trolley", - tv = "TV", - ultrascanner = "Ultrasom", - dna_fixer = "Fixador de DNA", - cast_remover = "Removedor de Gesso", - hair_restorer = "Restaurador de Cabelo", - slicer = "Fatiador", - x_ray = "Raio-X", - radiation_shield = "Escudo de Radiação", - x_ray_viewer = "Visualizador de Raio-X", - operating_table = "Mesa de Operação", - lamp = "Lampâda", -- unused object - toilet_sink = "Pia", - op_sink1 = "Pia", - op_sink2 = "Pia", - surgeon_screen = "Tela de Operação", - lecture_chair = "Cadeira de aluno", - projector = "Projetor", - bed2 = "Cama", -- unused duplicate - pharmacy_cabinet = "Gabinete de Farmácia", - computer = "Computador", - atom_analyser = "Analisador de Átomos", - blood_machine = "Máquina de Análise Sanguínea", - fire_extinguisher = "Extintor", - radiator = "Radiador", - plant = "Planta", - electrolyser = "Electrolisador", - jelly_moulder = "Moldador gelatinoso", - gates_of_hell = "Portões do Inferno", - bed3 = "Cama", -- unused duplicate - bin = "Lixeira", - toilet = "Cabine de Toalete", - swing_door1 = "Porta", - swing_door2 = "Porta", - shower = "Chuveiro", - auto_autopsy = "Auto-Autópsia", - bookcase = "Estante de Livros", - video_game = "Fliperama", - entrance_left = "Entrada esquerda", - entrance_right = "Entrada direita", - skeleton = "Esqueleto", - comfortable_chair = "Cadeira de conforto", -} - - --- Months -months = { - "Jan", - "Fev", - "Mar", - "Abr", - "Mai", - "Jun", - "Jul", - "Ago", - "Set", - "Out", - "Nov", - "Dez", -} - --- Rooms short --- NB: includes some special "rooms" --- reception, destroyed room and "corridor objects" -rooms_short = { - reception = "Recepção", - destroyed = "Destruído", - corridor_objects = "Objetos de Corredor", - - gps_office = "Clínica Geral", - psychiatric = "Psiquiatria", - ward = "Enfermaria", - operating_theatre = "Sala de Operações", - pharmacy = "Farmácia", - cardiogram = "Máq. de Eletrocardiograma", - scanner = "Scanner", - ultrascan = "Ultrasom", - blood_machine = "Sala de Análises Sanguíneas", - x_ray = "Raio-X", - inflation = "Inflador", - dna_fixer = "Fixador de DNA", - hair_restoration = "Recuperador de Cabelo", - tongue_clinic = "Fatiador", - fracture_clinic = "Clínica de Fraturas", - training_room = "Sala de Aula", - electrolysis = "Sala de Electrolisador", - jelly_vat = "Moldador Gelatinoso", - staffroom = "Sala de Relaxamento", - -- rehabilitation = "Reabilitação", -- unused - general_diag = "Diagnóstico Geral", - research_room = "Departamento de Pesquisas", - toilets = "Toaletes", - decontamination = "Descontaminação", -} - - - --- 8. Objetivos da Fase -introduction_texts = { - demo = { - "Bem-vindo ao hospital de demonstração!", - "Infelizmente esta versão demo são possui esta fase. Entretanto, teremos aqui o suficiente para mantê-lo ocupado por enquanto !", - "Você encontrará várias doenças que necessitarão de salas diferentes para cura. De tempos em tempos, emergências ocorrerão. E você precisará pesquisar por salas adicionais usando o Departamento de Pesquisas.", - "Seu objetivo é ter um saldo bancário de $100.000,00, o valor do hospital em $ 70.000,00 e uma reputação de 700, enquanto você cura pelo menos 75% de seus pacientes.", - "Certifique-se que sua reputação não fique abaixo de 300 e você não mate mais de 40% dos seus pacientes, senão você perde.", - "Boa sorte!", - }, - level1 = { - [1] = "Bem-vindo(a) ao seu primeiro hospital !//", - [2] = "Tenha-o pronto e rodando colocando um balcão de recepção, construindo um consultório de clínica geral e contratando uma recepcionista e médico. ", - [3] = "Então espere os negócios prosperarem.", - [4] = "É uma boa idéia construir um departamento de psiquiatria e contratar um médico psiquiatra, além de uma farmácia e enfermeira que também serão essenciais para curar seus pacientes. ", - [5] = "Cuidado com os casos de 'Cabeça inchada' - Uma sala com um Inflador resolverá os casos rapidamente.", - [6] = "Seu objetivo será curar 10 pessoas e garantir que sua reputação não fique abaixo de 200.", - [7] = "", - }, - level2 = { - [1] = "Há uma grande variedade de doenças nesta área, sendo assim planeje seu hospital para lidar com mais pacientes, além de construir um Departamento de Pesquisas. ", - [2] = "Lembre-se de manter o estabelecimento limpo e procure manter sua reputação a mais alta possível - você estará lidando com doenças como Língua negligente, então precisará de um Fatiador. Adicionalmente, poderá construir uma máquina de Eletrocardiograma para ajudá-lo a diagnosticar novas doenças", - [3] = "Ambas precisarão ser pesquisadas antes de serem construídas. Agora você poderá comprar lotes de terreno extras para expandir seu hospital - use o Mapa da Cidade para fazê-lo.", - [4] = "Tenha como objetivo uma reputação de 300, um saldo bancário de $10.000,00 e 40 pessoas curadas.", - [5] = "", - [6] = "", - }, - level3 = { - [1] = "Desta vez, você irá construir seu hospital em uma área nobre da cidade.", - [2] = "O Ministro da Saúde está contando com você para manter os níveis da saúde por aqui.", - [3] = "Você precisa ganhar uma boa reputação para começar, mas uma vez que seu hospital esteja estabelecido, concentre-se em lucrar a maior quantidade de dinheiro que puder.", - [4] = "Há uma grande possibilidade de ter de lidar com Emergências - isso acontece quando um grande número de pessoas chega de uma só vez, na mesma condição clínica - Curando-as à tempo você ganhará uma boa reputação e um grande bônus.", - [5] = "Doenças como o Complexo de Rei podem ocorrer, e você deverá planejar seu orçamento para construir uma Sala de Operações com uma Enfermaria ao lado. ", - [6] = "Consiga $ 20.000,00 em dinheiro para vencer a fase.", - [7] = "", - [8] = "", - }, - level4 = { - [1] = "Mantenha seus pacientes felizes, lide com eles da forma mais eficiente que puder e mantenha o número de óbitos no mínimo.", - [2] = "Sua reputação está em jogo, portanto mantenha-a a mais alta que conseguir.", - [3] = "Não se preocupe tanto com dinheiro - ele virá a medida que sua reputação cresce.", - [4] = "Você terá a possibilidade de treinar seus médicos para ampliar suas habilidades também, pois ele poderão ter que lidar com pacientes mais opacos que a maioria.", - [5] = "Consiga uma reputação acima de 500 para vencer a fase.", - [6] = "", - }, - level5 = { - [1] = "Você administrará agora um hospital ocupado, lidando com um grande variedade de casos.", - [2] = "Seus médicos são todos calouros da escola de medicina, portanto será de vital importância construir um sala de treinamento e treiná-los até um nível aceitável.", - [3] = "Você possui apenas três médicos sêniores para ajudá-lo a ensinar sua inexperiente equipe, portanto mantenha-os felizes.", - [4] = "Note, também, que as fundações deste hospital ficam no centro da falha geológica de São Android - existe um risco eminente de terremotos. que causarão um estrago significativo em seus equipamentos, atrapalhando uma calma administração de seu hospital.", - [5] = "Sua reputação deve ultrapassar a marca de 400, e um saldo bancário de $ 50.000,00 para ter sucesso - além de curar pelo menos 200 pacientes.", - [6] = "", - [7] = "", - }, - level6 = { - [1] = "Utilize todo seu know-how para montar um hospital eficiente que gere lucro e possa lidar com qualquer coisa que o público doente colocar em suas mãos.", - [2] = "Você deve estar ciente que a atmosfera do local é propícia para alastrar germes e infecções - Mantenha a instituição espetacularmente limpa se não quiser enfrentar uma série de epidemias envolvendo os pacientes.", - [3] = "Suas metas são fazer $ 150.000,00 em dinheiro e o valor do hospital deve valer pelo menos $140.000,00", - [4] = "", - }, - level7 = { - [1] = "Você está sendo observado de perto pelo Ministro de Saúde, então certifique-se que seus números indiquem que você está ganhando muito dinheiro e reputação crescente.", - [2] = "Não se dê ao luxo de mortes desnecessárias - elas são ruins para os negócios", - [3] = "Certifique-se que seu quadro de funcionários seja hábil e que você possua todos os equipamentos que precisa.", - [4] = "Obtenha uma reputação de 600 e $ 200.000,00 de saldo bancário.", - }, - level8 = { - [1] = "Só depende de você construir o hospital mais rentável e eficiente possível.", - [2] = "As pessoas por aqui são bem afortunadas, portanto 'enfie a faca' como puder. ", - [3] = "Lembre-se, curar pessoas é uma coisa muito legal, mas do que você realmente PRECISA é da grana que elas trarão.", - [4] = "Limpe estas pessoas doentes, consiga incríveis $ 300.000,00 para vencer esta fase.", - [5] = "", - }, - level9 = { - [1] = "Tendo enchido os bolsos e custeado a nova limousine do Ministro da Saúde, finalmente você pode voltar a criar um hospital modelo em benefício dos mais necessitados. ", - [2] = "Você pode esperar muitos e diversos problemas por aqui - Treine muito bem seus funcionários, tenha boas salas para cobrir todas as possibilidades.", - [3] = "Seu hospital precisa valer $200.000,00 e precisará de $400.000,00 no balco - qualquer coisa menos do que isso você não poderá terminar esta fase.", - [4] = "", - [5] = "", - }, - level10 = { - [1] = "Assim que você cuidar de todas as doenças que surgirem por estas bandas, o Ministro solicitou que você se concentre na eficiência de seus medicamentos. ", - [2] = "Existem algumas queixas feitas no 'SemDoenças' - que faz Auditorias na área da Saúde - então para ficar bonito na foto certifique-se que seus medicamentos sejam extremamente eficientes. Portanto, o hospital precisar ficar ótimo. Mantenha os óbitos em níveis baixos.", - [3] = "Fica a dica, deixe espaço livre para o Moldador Gelatinoso.", - [4] = "Pesquise e crie todos os medicamento com pelo menos 80% de eficiência, obtenha uma reputação de 650 e um saldo bancário de $500.000,00 para vencer! ", - [5] = "", - }, - level11 = { - [1] = "Você está tendo a oportunidade de construir a última palavra em hospitais. Está em uma área extremamente privilegiada, e o ministro gostaria de ver o melhor hospital possível.", - [2] = "A expectativa é que você faça muito dinheiro, tenha uma reputação soberba e esteja preparado para qualquer eventualidade.", - [4] = "É um trabalho importante este. ", - [5] = "Você precisa ser especial para conseguir se dar bem nessa fase.", - [6] = "Existem vários relatos de OVNIs nessa área. Certifique-se que seus funcionários estejam preparados para um eventual contato imediato.", - [7] = "Seu hospital precisa valer $240,000, você precisará de $500,000 no banco e uma reputação de 700.", - }, - level12 = { - }, - level13 = { - }, - level14 = { - }, - level15 = { - }, - level16 = { - }, - level17 = { - }, - level18 = { - }, -} - -graphs = { - money_in = "Receitas", - money_out = "Despesas", - wages = "Salários", - balance = "Balanço", - visitors = "Visitantes", - cures = "Curas", - deaths = "Óbitos", - reputation = "Reputação", - - time_spans = { - S[7][12], - S[7][13], - S[7][14], +update_window = { + caption = "Atualizaçäo Disponível!", + new_version = "Nova Versäo:", + current_version = "Versäo Atual:", + download = "Ir para página de download", + ignore = "Pular e ir para o menu principal", +} + +tooltip.update_window = { + download = "Vai para a página de downloads para obter a última versäo do CorsixTH", + ignore = "Ignora esta atualizaçäo no momento. Você será notificado da próxima vez que abrir o CorsixTH", +} + +map_editor_window = { + pages = { + inside = "Interior", + outside = "Exterior", + foliage = "Folhagem", + hedgerow = "Cerca viva", + pond = "Lagoa", + road = "Estrada", + north_wall = "Parede norte", + west_wall = "Parede oeste", + helipad = "Heliporto", + delete_wall = "Excluir paredes", + parcel_0 = "Parcela 0", + parcel_1 = "Parcela 1", + parcel_2 = "Parcela 2", + parcel_3 = "Parcela 3", + parcel_4 = "Parcela 4", + parcel_5 = "Parcela 5", + parcel_6 = "Parcela 6", + parcel_7 = "Parcela 7", + parcel_8 = "Parcela 8", + parcel_9 = "Parcela 9", + camera_1 = "Câmera 1", + camera_2 = "Câmera 2", + camera_3 = "Câmera 3", + camera_4 = "Câmera 4", + heliport_1 = "Heliporto 1", + heliport_2 = "Heliporto 2", + heliport_3 = "Heliporto 3", + heliport_4 = "Heliporto 4", + paste = "Colar área", } } -tooltip = { - toolbar = { - bank_button = "Clique com o botão esquerdo para consultar o Gerente do Banco, botão direito para extrato bancário", - balance = "Seu saldo bancário", - reputation = "Sua reputação", - date = "Calendário", - rooms = "Construir Salas", - objects = "Оbjetos de corredor", - edit = "Editar Salas", - hire = "Contratação de Pessoal", - staff_list = "Quadro de Funcionários", - town_map = "Mapa de Cidade", - casebook = "Livro de Diagnósticos", - research = "Pesquisa", - status = "Situação", - charts = "Gráficos", - policy = "Políticas", - }, -} - --- Rooms -room_classes = { - -- S[19][2] -- "corridors" - unused for now - diagnosis = "Diagnóstico", - treatment = "Tratamento", - clinics = "Clínicas", - facilities = "Acomodações", -} +-------------------------------- UNUSED ----------------------------------- +------------------- (kept for backwards compatibility) ---------------------- ---]] -confirmation = { - abort_edit_room = "Está construindo ou editando uma sala. Se todos os objectos necessários estiverem colocados a sala estará terminada, caso contrário será eliminada. Continuar?", - return_to_blueprint = "Voltar ao modo de desenho?", - restart_level = "Deseja realmente reiniciar esta fase?", - delete_room = "Deseja realmente remover esta sala?", - quit = "Sair do jogo?", - needs_restart = "Estas alterações requerem reiniciar o jogo, todo progresso não gravado será perdido. Continuar?", - overwrite_save = "Já existe uma gravação neste arquivo. Gravar por cima?", - sack_staff = "Demitir este funcionário ?", - replace_machine = "Quer substituir %s por $%d?", -} +options_window.change_resolution = "Alterar resoluçäo" +tooltip.options_window.change_resolution = "Altera a resoluçäo de janela para as dimensöes digitadas na esquerda" +-------------------------------------------------------------------------------------------------------------------------------------------------------- +-------------------------------- MISSING STRINGS IN LANGUAGE "PORTUGUêS DO BRASIL": ----------------------------------- +--------------------------------------------------------------------------------------------------------------------------------------------------------- +rooms_long.ward = "Enfermaria" +rooms_long.blood_machine = "Sala de Transfusöes" +rooms_long.emergency = "Sala de Emergências" +rooms_long.general = "Sala de Clínica Geral" +rooms_long.cardiogram = "Sala do Cardiograma" +rooms_long.decontamination = "Sala de Descontaminaçäo" +rooms_long.jelly_vat = "Banho Gelatinoso" +rooms_long.staffroom = "Sala de Descanso" +rooms_long.hair_restoration = "Sala de Peloterapia" +rooms_long.inflation = "Sala de Inflatoterapia" +rooms_long.operating_theatre = "Sala de Operaçöes" +rooms_long.gps_office = "Consultório Geral" +rooms_long.training_room = "Sala de Formaçäo" +rooms_long.x_ray = "Sala de Raio-X" +rooms_long.tongue_clinic = "Sala de Laringologia" +rooms_long.psychiatric = "Sala de Psiquiatria" +rooms_long.corridors = "Corredores" +rooms_long.ultrascan = "Sala de Ultra Scanner" +rooms_long.dna_fixer = "Sala de Genética" +rooms_long.toilets = "Banheiro" +rooms_long.fracture_clinic = "Sala de Traumatologia" +rooms_long.pharmacy = "Farmácia" +rooms_long.general_diag = "Diagnóstico Geral" +rooms_long.research_room = "Centro de Pesquisa" +rooms_long.scanner = "Sala de Scanner" +rooms_long.electrolysis = "Sala de Eletrólise" +fax.debug_fax.text4 = "FACTORS : DOCS %d NURSES %d AREA %d ROOMS %d PRICING %d" +fax.debug_fax.text2 = "TOTAL PEOPLE IN HOSPITAL %d CHECKING AGAINST %d" +fax.debug_fax.text9 = "DISASTERS %d ALLOWED (MTHS) %d (%d)REDUCTION %d" +fax.debug_fax.text3 = "FIGURES : DOCS %d NURSES %d AREA %d ROOMS %d PRICING %d" +fax.debug_fax.close_text = "Sim, sim, sim!" +fax.debug_fax.text5 = "CONTRIBN : DOCS %d NURSES %d AREA %d ROOMS %d PRICING %d PERCENT" +fax.debug_fax.text1 = "BEST COUNT %d" +fax.debug_fax.text8 = "AMENITIES %d PEEPS HANDLED %d REDUCTION %d" +fax.debug_fax.text10 = "KILLS %d ALLOWED (MTHS) %d (%d) REDUCTION %d" +fax.debug_fax.text7 = "REPUTATION: %d EXPECTED %d REDUCTION %d" +fax.debug_fax.text11 = "PEOPLE THIS MONTH %d" +fax.debug_fax.text6 = "THE FOLLOWING FACTORS ARE ALSO APPLIED" +fax.emergency.choices.accept = "Sim, preparado para confrontar esta emergência." +fax.emergency.choices.refuse = "Näo. Nego-me a confrontar esta emergência." +fax.emergency.cure_possible_drug_name_efficiency = "Já dispöe da equipe e do pessoal qualificado. Tem o medicamento necessário. É %s e tem uma efetividade de %d por cento." +fax.emergency.bonus = "Ganhará um bônus máximo de $%d por cuidar desta emergência. Mas se fracassar, a sua reputaçäo será seriamente danificada." +fax.emergency.locations[1] = "Planta Química Thatcher" +fax.emergency.locations[2] = "Universidade Suja" +fax.emergency.locations[3] = "Centro de Plantas Aquáticas" +fax.emergency.locations[4] = "Instituto de Pesquisa de Substâncias Perigosas" +fax.emergency.locations[5] = "Congresso de Bailarinos Russos" +fax.emergency.locations[6] = "Pub O Touro e A Rä" +fax.emergency.locations[7] = "Funerária Sem Licença Para Boa Morte" +fax.emergency.locations[8] = "A Casa do Curry" +fax.emergency.locations[9] = "Empório Petroquímico Usado" +fax.emergency.cure_not_possible_employ = "Precisará contratar um(a) %s" +fax.emergency.location = "Houve um incidente em %s" +fax.emergency.cure_possible = "Tem a equipe e o pessoal qualificado necessário, poderá confrontar esta emergência." +fax.emergency.cure_not_possible = "Näo pode curar esta doença no momento." +fax.epidemic.cover_up_explanation_2 = "Se um Inspetor de Saúde visitar e encontrar uma epidemia encoberta tomará medidas drásticas contra si." +fax.epidemic.choices.cover_up = "Tratar de ocultá-la. Procurar curar a epidemia antes de que se estenda por todo o país." +fax.epidemic.choices.declare = "Há uma epidemia" +fax.epidemic.disease_name = "Os seus Médicos descobriram uma variedade contagiosa de %s." +fax.epidemic.declare_explanation_fine = "Se declarar uma epidemia, pagará uma multa de %d, danificando a sua reputaçäo e os seus pacientes seräo automaticamente vacinados." +fax.epidemic.cover_up_explanation_1 = "Se tentar encobri-la, terá um tempo limitado para curar a todos os infectados antes de que as Autoridades da Saúde descubram." +fax.vip_visit_result.close_text = "Obrigado por visitar o hospital." +fax.vip_visit_result.telegram = "Telegrama!" +fax.vip_visit_result.vip_remarked_name = "Depois de visitar o seu hospital, %s declarou:" +fax.vip_visit_result.remarks.super[1] = "Que hospital eficaz! A próxima vez que estiver gravemente doente, eu venho aqui." +fax.vip_visit_result.remarks.super[2] = "É isto o que eu chamo de um hospital." +fax.vip_visit_result.remarks.super[3] = "É um hospital excelente. E sei o que digo; visito muitos hospitais." +fax.vip_visit_result.remarks.mediocre[1] = "Bom, já vi piores. Mas deveria fazer algumas melhoras." +fax.vip_visit_result.remarks.mediocre[2] = "Oh céus! Näo é um lugar agradável para ir se estiver doente." +fax.vip_visit_result.remarks.mediocre[3] = "Vou ser sincero, é um hospital normal. Francamente, eu esperava mais, " +fax.vip_visit_result.remarks.very_bad[1] = "Vá tugúrio! Vou tentar o enclausurá-lo." +fax.vip_visit_result.remarks.very_bad[2] = "Nunca vi um hospital täo espantoso. Que vergonha!" +fax.vip_visit_result.remarks.very_bad[3] = "Estou horrorizado. Chama a isto de hospital! Vou sair com um cano." +fax.vip_visit_result.remarks.bad[1] = "Por que me zanguei? Foi pior que ir ver uma ópera de quatro horas!" +fax.vip_visit_result.remarks.bad[2] = "Estou aborrecido pelo que vi. Chama a isto um hospital? Mais parece uma pocilga!" +fax.vip_visit_result.remarks.bad[3] = "Estou farto de atrair a atençäo pública e de visitar buracos fedorentos como este! Demito-me." +fax.vip_visit_result.remarks.good[1] = "Que hospital bem dirigido! Obrigado pelo seu convite." +fax.vip_visit_result.remarks.good[2] = "Mmmm. Certamente näo é uma má instituiçäo médica." +fax.vip_visit_result.remarks.good[3] = "Gostei do seu estupendo hospital. Agora, alguém quer um curry da Casa do Curry?" +fax.vip_visit_result.cash_grant = "Você ganhou um prêmio em dinheiro de $%d." +fax.vip_visit_result.rep_boost = "Sua reputaçäo na comunidade acaba de aumentar." +fax.vip_visit_result.rep_loss = "A sua reputaçäo foi afetada em consequência" +fax.disease_discovered.close_text = "Foi encontrada uma nova doença." +fax.disease_discovered.need_to_build = "Precisa construir um(a) %s para tratar isto." +fax.disease_discovered.can_cure = "Pode tratar esta doença." +fax.disease_discovered.need_to_employ = "Contrate um(a) %s que possa solucionar este problema." +fax.disease_discovered.need_to_build_and_employ = "Se construir uma %s e contratar um(a) %s pode ter êxito." +fax.disease_discovered.discovered_name = "A sua equipe descobriu uma nova doença. É %s." +fax.epidemic_result.close_text = "Bem!" +fax.epidemic_result.compensation_amount = "O Governo decidiu lhe dar uma compensaçäo de %d pelos danos que estes incidente causara ao bom nome do seu hospital." +fax.epidemic_result.succeeded.part_1_name = "Chegou aos ouvidos do Inspetor de Saúde que na sua instituiçäo estava tratando um caso maligno de %s." +fax.epidemic_result.succeeded.part_2 = "Embora, näo fosse possível encontrar provas que comprovassem os ditos rumores..." +fax.epidemic_result.hospital_evacuated = "O Ministério da Saúde näo tem outra alternativa a näo ser evacuar o seu hospital." +fax.epidemic_result.failed.part_1_name = "Ao tentar esconder o fato de que enfrentavam um broto contagioso de %s" +fax.epidemic_result.failed.part_2 = "Os funcionários do seu hospital säo responsáveis pela doença que se propagou entre as pessoas que vivem perto do seu hospital." +fax.epidemic_result.fine_amount = "O Governo declarou uma emergência nacional e multa-o com %d." +fax.epidemic_result.rep_loss_fine_amount = "Os jornais têm feito um escândalo com isto. A sua reputaçäo será gravemente afetada. Além disso, imporá uma multa de %d." +fax.emergency_result.close_text = "Aperte para sair" +fax.emergency_result.saved_people = "Salvou %d pessoas de um total de %d." +fax.emergency_result.earned_money = "Ganhou %d, de um bônus máximo de %d." +fax.vip_visit_query.vip_name = "%s expressou o seu desejo de visitar o seu hospital." +fax.vip_visit_query.choices.refuse = "Dispensar o V.I.P." +fax.vip_visit_query.choices.invite = "Enviar um convite oficial ao V.I.P." +fax.diagnosis_failed.what_to_do_question = "O que vamos fazer com o paciente?" +fax.diagnosis_failed.choices.send_home = "Enviar o paciente para casa." +fax.diagnosis_failed.choices.take_chance = "Tentar uma possível cura." +fax.diagnosis_failed.choices.wait = "Fazer o paciente esperar enquanto constrói mais salas de diagnóstico." +fax.diagnosis_failed.partial_diagnosis_percentage_name = "Existe %d por cento de probabilidades de descobrirmos que tipo de %s sofre esse paciente." +fax.diagnosis_failed.situation = "Fizemos todos os nossos diagnósticos com este paciente e näo estamos seguros do que se trata." +fax.disease_discovered_patient_choice.what_to_do_question = "O que quer fazer com o paciente?" +fax.disease_discovered_patient_choice.choices.send_home = "Enviar o paciente para casa." +fax.disease_discovered_patient_choice.choices.research = "Enviar o paciente para Pesquisa." +fax.disease_discovered_patient_choice.choices.wait = "Faça o paciente esperar um momento no hospital." +fax.disease_discovered_patient_choice.can_not_cure = "Näo pode curar esta doença." +fax.disease_discovered_patient_choice.need_to_employ = "Contrate um(a) %s para corrigir esta situaçäo." +fax.disease_discovered_patient_choice.need_to_build = "Precisa construir um(a) %s para poder tratar isto." +fax.disease_discovered_patient_choice.need_to_build_and_employ = "Pode consegui-lo se construir um(a) %s e contratar um %s." +fax.disease_discovered_patient_choice.guessed_percentage_name = "A sua equipe tem que averiguar o que tem um paciente. Há %d por cento de probabilidade de que seja %s" +fax.disease_discovered_patient_choice.disease_name = "A sua equipe descobriu uma nova doença. É %s." +original_credits[1] = " " +original_credits[2] = " " +original_credits[3] = " " +original_credits[4] = " " +original_credits[5] = " " +original_credits[6] = " " +original_credits[7] = " " +original_credits[8] = " " +original_credits[9] = " " +original_credits[10] = " " +original_credits[11] = " " +original_credits[12] = ":Desenvolvido e criado pela" +original_credits[13] = ":Bullfrog Productions" +original_credits[14] = " " +original_credits[15] = ":Equipe de Desenvolvimento Pluto" +original_credits[16] = "," +original_credits[17] = "Mark Webley" +original_credits[18] = "Gary Carr" +original_credits[19] = "Matt Chilton" +original_credits[20] = "Matt Sullivan" +original_credits[21] = "Jo Rider" +original_credits[22] = "Rajan Tande" +original_credits[23] = "Wayne Imlach" +original_credits[24] = "Andy Bass" +original_credits[25] = "Jon Rennie" +original_credits[26] = "Adam Coglan" +original_credits[27] = "Natalie White" +original_credits[28] = " " +original_credits[29] = " " +original_credits[30] = " " +original_credits[31] = ":Programaçäo" +original_credits[32] = "," +original_credits[33] = "Mark Webley" +original_credits[34] = "Matt Chilton" +original_credits[35] = "Matt Sullivan" +original_credits[36] = "Rajan Tande" +original_credits[37] = " " +original_credits[38] = "Ben Deane" +original_credits[39] = "Gary Morgan" +original_credits[40] = "Jonty Barnes" +original_credits[41] = " " +original_credits[42] = " " +original_credits[43] = " " +original_credits[44] = ":Arte" +original_credits[45] = "," +original_credits[46] = "Gary Carr" +original_credits[47] = "Jo Rider" +original_credits[48] = "Andy Bass" +original_credits[49] = "Adam Coglan" +original_credits[50] = " " +original_credits[51] = "Eoin Rogan" +original_credits[52] = "George Svarovsky" +original_credits[53] = "Saurev Sarkar" +original_credits[54] = "Jason Brown" +original_credits[55] = "John Kershaw" +original_credits[56] = "Dee Lee" +original_credits[57] = " " +original_credits[58] = " " +original_credits[59] = " " +original_credits[60] = ":Sequência Introdutória" +original_credits[61] = "," +original_credits[62] = "Stuart Black" +original_credits[63] = " " +original_credits[64] = " " +original_credits[65] = " " +original_credits[66] = ":Música e Efeitos de Som" +original_credits[67] = "," +original_credits[68] = "Russell Shaw" +original_credits[69] = "Adrian Moore" +original_credits[70] = " " +original_credits[71] = "Jeremy Longley" +original_credits[72] = "Andy Wood" +original_credits[73] = " " +original_credits[74] = " " +original_credits[75] = " " +original_credits[76] = ":Voz da Narradora" +original_credits[77] = "," +original_credits[78] = "Rebecca Green" +original_credits[79] = " " +original_credits[80] = " " +original_credits[81] = " " +original_credits[82] = ":Desenho dos Níveis" +original_credits[83] = "," +original_credits[84] = "Wayne Imlach" +original_credits[85] = "Natalie White" +original_credits[86] = "Steven Jarrett" +original_credits[87] = "Shin Kanaoya" +original_credits[88] = " " +original_credits[89] = " " +original_credits[90] = " " +original_credits[91] = ":Roteiristas" +original_credits[92] = "," +original_credits[93] = "James Leach" +original_credits[94] = "Sean Masterson" +original_credits[95] = "Neil Cook" +original_credits[96] = " " +original_credits[97] = " " +original_credits[98] = " " +original_credits[99] = ":Pesquisa e Desenvolvimento" +original_credits[100] = "," +original_credits[101] = "Andy Cakebread" +original_credits[102] = "Richard Reed" +original_credits[103] = " " +original_credits[104] = "Glenn Corpes" +original_credits[105] = "Martin Bell" +original_credits[106] = "Ian Shaw" +original_credits[107] = "Jan Svarovsky" +original_credits[108] = " " +original_credits[109] = " " +original_credits[110] = " " +original_credits[111] = ":Bibliotecas e Ferramentas" +original_credits[112] = "," +original_credits[113] = "Mark Huntley" +original_credits[114] = "Alex Peters" +original_credits[115] = "Rik Heywood" +original_credits[116] = " " +original_credits[117] = "Ian Shippen" +original_credits[118] = "Mark Lamport" +original_credits[119] = " " +original_credits[120] = "Russell Shaw" +original_credits[121] = "Tony Cox" +original_credits[122] = " " +original_credits[123] = " " +original_credits[124] = " " +original_credits[125] = ":Programaçäo do Instalador" +original_credits[126] = "," +original_credits[127] = "Andy Nuttall" +original_credits[128] = "Tony Cox" +original_credits[129] = "Andy Cakebread" +original_credits[130] = " " +original_credits[131] = " " +original_credits[132] = " " +original_credits[133] = ":Chefe de Testes" +original_credits[134] = "," +original_credits[135] = "Andy Robson" +original_credits[136] = " " +original_credits[137] = " " +original_credits[138] = " " +original_credits[139] = ":Testadores" +original_credits[140] = "," +original_credits[141] = "Wayne Imlach" +original_credits[142] = "Jon Rennie" +original_credits[143] = " " +original_credits[144] = "Jeff Brutus" +original_credits[145] = "Wayne Frost" +original_credits[146] = "Steven Lawrie" +original_credits[147] = "Tristan Paramor" +original_credits[148] = "Nathan Smethurst" +original_credits[149] = " " +original_credits[150] = "Ryan Corkery" +original_credits[151] = "Simon Doherty" +original_credits[152] = "James Dormer" +original_credits[153] = "Martin Gregory" +original_credits[154] = "Ben Lawley" +original_credits[155] = "Joel Lewis" +original_credits[156] = "David Lowe" +original_credits[157] = "Robert Monczak" +original_credits[158] = "Dominic Mortoza" +original_credits[159] = "Karl O'Keeffe" +original_credits[160] = "Michael Singletary" +original_credits[161] = "Andrew Skipper" +original_credits[162] = "Stuart Stephen" +original_credits[163] = "David Wallington" +original_credits[164] = " " +original_credits[165] = " " +original_credits[166] = " " +original_credits[167] = ":Suporte Técnico" +original_credits[168] = "," +original_credits[169] = "Kevin Donkin" +original_credits[170] = "Mike Burnham" +original_credits[171] = "Simon Handby" +original_credits[172] = " " +original_credits[173] = " " +original_credits[174] = " " +original_credits[175] = ":Marketing" +original_credits[176] = "," +original_credits[177] = "Pete Murphy" +original_credits[178] = "Sean Ratcliffe" +original_credits[179] = " " +original_credits[180] = " " +original_credits[181] = " " +original_credits[182] = ":Relaçöes Públicas" +original_credits[183] = "," +original_credits[184] = "Cathy Campos" +original_credits[185] = " " +original_credits[186] = " " +original_credits[187] = " " +original_credits[188] = ":Documentaçäo" +original_credits[189] = "," +original_credits[190] = "Mark Casey" +original_credits[191] = "Richard Johnston" +original_credits[192] = "James Lenoel" +original_credits[193] = "Jon Rennie" +original_credits[194] = " " +original_credits[195] = " " +original_credits[196] = " " +original_credits[197] = ":Documentaçäo e Desenho da Caixa" +original_credits[198] = "," +original_credits[199] = "Caroline Arthur" +original_credits[200] = "James Nolan" +original_credits[201] = " " +original_credits[202] = " " +original_credits[203] = " " +original_credits[204] = ":Chefe do Projeto de Localizaçäo" +original_credits[205] = "," +original_credits[206] = "Carol Aggett" +original_credits[207] = " " +original_credits[208] = " " +original_credits[209] = ":Traduçäo para Português" +original_credits[210] = "," +original_credits[211] = "Altieres Lima" +original_credits[212] = "Leonardo Malaman" +original_credits[213] = "Henrique Poyatos" +original_credits[214] = " " +original_credits[215] = " " +original_credits[216] = ":Produçäo" +original_credits[217] = "," +original_credits[218] = "Rachel Holman" +original_credits[219] = " " +original_credits[220] = " " +original_credits[221] = " " +original_credits[222] = ":Produtor" +original_credits[223] = "," +original_credits[224] = "Mark Webley" +original_credits[225] = " " +original_credits[226] = " " +original_credits[227] = " " +original_credits[228] = ":Produtor Associado" +original_credits[229] = "," +original_credits[230] = "Andy Nuttall" +original_credits[231] = " " +original_credits[232] = " " +original_credits[233] = " " +original_credits[234] = ":Operaçöes" +original_credits[235] = "," +original_credits[236] = "Steve Fitton" +original_credits[237] = " " +original_credits[238] = " " +original_credits[239] = " " +original_credits[240] = ":Administraçäo da Companhia" +original_credits[241] = "," +original_credits[242] = "Audrey Adams" +original_credits[243] = "Annette Dabb" +original_credits[244] = "Emma Gibbs" +original_credits[245] = "Lucia Gobbo" +original_credits[246] = "Jo Goodwin" +original_credits[247] = "Sian Jones" +original_credits[248] = "Kathy McEntee" +original_credits[249] = "Louise Ratcliffe" +original_credits[250] = " " +original_credits[251] = " " +original_credits[252] = " " +original_credits[253] = ":Direçäo da Companhia" +original_credits[254] = "," +original_credits[255] = "Les Edgar" +original_credits[256] = "Peter Molyneux" +original_credits[257] = "David Byrne" +original_credits[258] = " " +original_credits[259] = " " +original_credits[260] = " " +original_credits[261] = ":O nosso agradecimento especial para" +original_credits[262] = "," +original_credits[263] = "Peter Molyneux" +original_credits[264] = " " +original_credits[265] = "O pessoal do Hospital Frimley Park" +original_credits[266] = " " +original_credits[267] = "em particular ao" +original_credits[268] = "," +original_credits[269] = "Beverley Cannell" +original_credits[270] = "Doug Carlisle" +original_credits[271] = " " +original_credits[272] = " " +original_credits[273] = " " +original_credits[274] = ":Continuem a pensar" +original_credits[275] = " " +original_credits[276] = " " +original_credits[277] = " " +original_credits[278] = " " +original_credits[279] = " " +original_credits[280] = " " +original_credits[281] = " " +original_credits[282] = " " +original_credits[283] = " " +original_credits[284] = " " +original_credits[285] = " " +original_credits[286] = " " +original_credits[287] = " " +original_credits[288] = " " +original_credits[289] = " " +original_credits[290] = " " +original_credits[291] = " " +original_credits[292] = " " +original_credits[293] = " " +original_credits[294] = " " +original_credits[295] = "." +buy_objects_window.choose_items = "Escolha os objetos" +buy_objects_window.total = "Total: " +buy_objects_window.price = "Preço: " +build_room_window.pick_room_type = "Escolha a sala" +build_room_window.pick_department = "Departamento" +build_room_window.cost = "Custo: " +object.bench = "Banco" +object.pharmacy_cabinet = "Primeiros socorros" +object.console = "Console" +object.atom_analyser = "Analisador atômico" +object.fire_extinguisher = "Extintor" +object.scanner = "Scanner" +object.bin = "Cesto de papéis" +object.swing_door1 = "Porta de batente" +object.pool_table = "Mesa de bilhar" +object.screen = "Tela" +object.cabinet = "Arquivo" +object.sofa = "Sofá" +object.projector = "Projetor" +object.table2 = "Mesa" +object.shower = "Ducha descontaminadora" +object.comfortable_chair = "Poltrona confortável" +object.door = "Porta" +object.computer = "Computador" +object.litter_bomb = "Bomba de lixo" +object.entrance_left = "Porta direita de entrada" +object.dna_fixer = "Reparador DNA" +object.bed = "Cama" +object.lamp = "Abajur" +object.bookcase = "Estante" +object.desk = "Escritório" +object.toilet_sink = "Pia" +object.gates_of_hell = "Portas do inferno" +object.swing_door2 = "Porta de batente" +object.cast_remover = "Removedor de gesso" +object.plant = "Planta" +object.blood_machine = "Transfusiômetro" +object.slicer = "Cortador" +object.x_ray = "Raio-X" +object.cardio = "Eletrocardiograma" +object.crash_trolley = "Carrinho" +object.bed2 = "Cama" +object.electrolyser = "Eletrólise" +object.video_game = "Videogame" +object.skeleton = "Esqueleto" +object.ultrascanner = "Ultra scanner" +object.op_sink1 = "Pia" +object.hair_restorer = "Pêlo-restaurador" +object.reception_desk = "Recepçäo" +object.radiation_shield = "Painel anti-radiaçäo" +object.couch = "Divä" +object.inflator = "Inflador" +object.toilet = "Banheiro" +object.lecture_chair = "Poltrona" +object.auto_autopsy = "Máq. autópsias" +object.chair = "Cadeira" +object.x_ray_viewer = "Máquina de raio-X" +object.radiator = "Radiador" +object.bed3 = "Cama" +object.surgeon_screen = "Tela de cirurgiäo" +object.jelly_moulder = "Moldador de gelatina" +object.drinks_machine = "Máq. de bebidas" +object.op_sink2 = "Pia" +object.table1 = "Mesa" +object.entrance_right = "Porta esquerda de entrada" +object.operating_table = "Mesa de operaçöes" +object.tv = "Televisäo" +transactions.bank_loan = "Empréstimo bancário" +transactions.buy_object = "Comprou" +transactions.cure = "Cura" +transactions.general_bonus = "Pagamento extra geral" +transactions.treat_colon = "Tratamento:" +transactions.eoy_bonus_penalty = "Bônus/multa de fim de ano" +transactions.loan_repayment = "Devoluçäo do empréstimo" +transactions.research = "Gastos em pesquisa" +transactions.epidemy_coverup_fine = "Multa por cobertura da epidemia" +transactions.build_room = "Construiu" +transactions.sell_object = "Vendeu" +transactions.vaccination = "Vacinas" +transactions.personal_bonus = "Pagamento extra individual" +transactions.drug_cost = "Medicamento" +transactions.severance = "Inden. demissäo" +transactions.deposit = "Tratamentos" +transactions.epidemy_fine = "Multa pela epidemia" +transactions.buy_land = "Comprou terreno" +transactions.hire_staff = "Contratou" +transactions.insurance_colon = "Seguro:" +transactions.drinks = "Renda: máquinas de bebidas" +transactions.overdraft = "Juros do saldo devedor" +transactions.vip_award = "Prêmio VIP" +transactions.research_bonus = "Bônus de pesquisa" +transactions.cheat = "Trapaça de dinheiro" +transactions.compensation = "Indenizaçäo do governo" +transactions.wages = "Salários" +transactions.advance_colon = "Avanços:" +transactions.cure_colon = "Cura:" +transactions.jukebox = "Renda: máquina de discos" +transactions.machine_replacement = "Custo por substituiçäo de máquinas" +transactions.heating = "Gastos de aquecimento" +transactions.final_treat_colon = "Tratamento final:" +transactions.emergency_bonus = "Pagamento extra de emergência" +transactions.eoy_trophy_bonus = "Troféu bônus de fim de ano" +transactions.loan_interest = "Juros do empréstimo" +menu_options.game_speed = " VELOCIDADE DO JOGO " +menu_options.sound_vol = " VOLUME DO SOM " +menu_options.music_vol = " VOLUME DA MUSICA " +menu_options.autosave = " AUTO-SALVAR " +menu_options.announcements_vol = " VOLUME DOS AVISOS " +newspaper[1][1] = "TERROR NO HOSPITAL" +newspaper[1][2] = "O MÉDICO AÇOUGUEIRO" +newspaper[1][3] = "PANICO GERAL" +newspaper[1][4] = "O QUE HAVIA NO LABORATORIO?" +newspaper[1][5] = "DETEVE UMA INVESTIGAÇAO DE RISCO" +newspaper[2][1] = "DR UNK É UM CANALHA" +newspaper[2][2] = "CIRURGIAO DESPEDAÇADO" +newspaper[2][3] = "ESPECIALISTA EM JOGOS" +newspaper[2][4] = "EMBRIAGADO" +newspaper[2][5] = "CIRURGIAO CACHACEIRO" +newspaper[2][6] = "EMBRIAGADO EM CIRURGIA" +newspaper[3][1] = "CIRURGIAO VICIADO" +newspaper[3][2] = "MÉDICO SEM CALÇAS" +newspaper[3][3] = "MÉDICO SEDUTOR" +newspaper[3][4] = "CIRURGIAO INSACIAVEL" +newspaper[4][1] = "MÉDICO INVADE HOSPITAL" +newspaper[4][2] = "CRIME ORGANIZADO" +newspaper[4][3] = "OPERAÇAO DE DESVIO DE FUNDOS" +newspaper[4][4] = "FECHAMENTO SEM REMUNERAÇAO" +newspaper[5][1] = "ASSALTO EM UM HOSPITAL" +newspaper[5][2] = "MÉDICO RETIRA CADAVERES" +newspaper[5][3] = "CAPTURADO COM O CORPO" +newspaper[5][4] = "AJUSTE DE CONTAS DO DR MORTE" +newspaper[5][5] = "ROUBO NO DEPOSITO" +newspaper[5][6] = "DENOMINADO DR CAVATUMBAS" +newspaper[6][1] = "DR COSTURA MAIS UMA VEZ!" +newspaper[6][2] = "FALSO MÉDICO" +newspaper[6][3] = "DIAGNOSTICO ERRADO" +newspaper[6][4] = "CONSULTOR DESAJEITADO" +newspaper[7][1] = "MÉDICO SE SENTE MARGINALIZADO" +newspaper[7][2] = "UM CIRURGIAO 'OPERA' A SI MESMO" +newspaper[7][3] = "DESCONTROLE EM BANHEIROS" +newspaper[7][4] = "MÉDICO PROTAGONIZA UM ESCANDALO" +newspaper[7][5] = "MÉDICO 'CRIA UM BARRACO" +progress_report.too_hot = "Revise o seu sistema de aquecimento. Faz muito calor." +progress_report.header = "Relatório em curso" +progress_report.percentage_pop = "% populaçäo" +progress_report.too_cold = "Faz muito frio. Coloque radiadores." +progress_report.quite_unhappy = "Os seus pacientes estäo muito contentes." +progress_report.win_criteria = "CRITÉRIOS PARA GANHAR" +progress_report.very_unhappy = "Os seus pacientes estäo muito descontentes." +progress_report.more_drinks_machines = "Coloque mais máquinas de bebidas." +staff_descriptions.bad[1] = "É uma pessoa lenta e suscetível. " +staff_descriptions.bad[2] = "Mostra preguiça e falta de motivaçäo. " +staff_descriptions.bad[3] = "Com uma má formaçäo e pouco eficaz. " +staff_descriptions.bad[4] = "Pessoa grosseira e brusca. Chateia as pessoas. " +staff_descriptions.bad[5] = "Tem pouca resistência e má atitude. " +staff_descriptions.bad[6] = "Pessoa surda como uma porta. Cheira a repolho. " +staff_descriptions.bad[7] = "Pessoa imunda no serviço. Um estorvo. " +staff_descriptions.bad[8] = "Imprudente e se distrai com facilidade. " +staff_descriptions.bad[9] = "Pessoa estressada e confusa. " +staff_descriptions.bad[10] = "Pessoa desleal e rancorosa. Cheia de ódio. " +staff_descriptions.bad[11] = "Näo toma cuidado e provoca acidentes. " +staff_descriptions.bad[12] = "Näo se importa com o trabalho. Perde tempo. " +staff_descriptions.bad[13] = "Pessoa temerária e sem cuidado. " +staff_descriptions.bad[14] = "Pessoa ardilosa, matreira e subversiva. " +staff_descriptions.bad[15] = "Pessoa arrogante e presunçosa. " +staff_descriptions.misc[1] = "Joga golfe. " +staff_descriptions.misc[2] = "Pratica mergulho. " +staff_descriptions.misc[3] = "Faz esculturas de gelo. " +staff_descriptions.misc[4] = "Bebe vinho. " +staff_descriptions.misc[5] = "Participa de rally. " +staff_descriptions.misc[6] = "Faz bungee-jump. " +staff_descriptions.misc[7] = "Coleciona latas de cerveja. " +staff_descriptions.misc[8] = "Gosta de mergulhar no público em shows. " +staff_descriptions.misc[9] = "Gosta de fazer surf. " +staff_descriptions.misc[10] = "Pratica raffiting. " +staff_descriptions.misc[11] = "Destila uísque. " +staff_descriptions.misc[12] = "Especialista em 'faça você mesmo'. " +staff_descriptions.misc[13] = "Gosta do cinema francês. " +staff_descriptions.misc[14] = "Joga muito Theme Park. " +staff_descriptions.misc[15] = "Possui carteira de habilitaçäo E. " +staff_descriptions.misc[16] = "Corre de motocicleta. " +staff_descriptions.misc[17] = "Toca violino e violoncelo. " +staff_descriptions.misc[18] = "Adora andar de trem. " +staff_descriptions.misc[19] = "Adora cachorros. " +staff_descriptions.misc[20] = "Ouve rádio. " +staff_descriptions.misc[21] = "Toma banho com frequência. " +staff_descriptions.misc[22] = "Instrutor de costura. " +staff_descriptions.misc[23] = "Tira o miolo dos vegetais para usar como saboneteira. " +staff_descriptions.misc[24] = "É policial em meio expediente. " +staff_descriptions.misc[25] = "Ex-convidado de um concurso. " +staff_descriptions.misc[26] = "Coleciona bombas da Segunda Guerra. " +staff_descriptions.misc[27] = "Restaura móveis. " +staff_descriptions.misc[28] = "Escuta rap e hip-pop. " +staff_descriptions.misc[29] = "Extermina insetos borrifando desodorante. " +staff_descriptions.misc[30] = "Ridiculariza comediantes ruins. " +staff_descriptions.misc[31] = "Investiga para a Câmara Municipal. " +staff_descriptions.misc[32] = "Cuida do jardim às escondidas. " +staff_descriptions.misc[33] = "Faz contrabando de relógios falsos. " +staff_descriptions.misc[34] = "Vocalista de uma banda de rock & roll. " +staff_descriptions.misc[35] = "Adora programas de televisäo vespertinos. " +staff_descriptions.misc[36] = "Pesca trutas com a mäo. " +staff_descriptions.misc[37] = "Isca turistas em museus. " +staff_descriptions.good[1] = "Trabalha de forma rápida e diligente. " +staff_descriptions.good[2] = "Trabalha com consciência e seriedade. " +staff_descriptions.good[3] = "Sabe fazer muitas coisas. " +staff_descriptions.good[4] = "Muito agradável e gosta de rir. " +staff_descriptions.good[5] = "Tem muita energia. Näo para. " +staff_descriptions.good[6] = "Pessoa educada e de boas maneiras. " +staff_descriptions.good[7] = "Com talento e capacidade incríveis. " +staff_descriptions.good[8] = "Preocupa-se muito pelo seu trabalho. " +staff_descriptions.good[9] = "Procura a perfeiçäo e nunca se rende. " +staff_descriptions.good[10] = "Ajuda as pessoas com um sorriso. " +staff_descriptions.good[11] = "Tem encanto, educaçäo e disponibilidade. " +staff_descriptions.good[12] = "Normalmente tem estímulo e dedicaçäo. " +staff_descriptions.good[13] = "É boa pessoa e trabalha muito. " +staff_descriptions.good[14] = "Leal e amigável. " +staff_descriptions.good[15] = "Pessoa atenta e confiável em caso de emergência. " +humanoid_name_ends[1] = "SMITH" +humanoid_name_ends[2] = "WICK" +humanoid_name_ends[3] = "CLIFFE" +humanoid_name_ends[4] = "SON" +humanoid_name_ends[5] = "INGTON" +humanoid_name_ends[6] = "BURY" +humanoid_name_ends[7] = "TON" +humanoid_name_ends[8] = "SON" +humanoid_name_ends[9] = "LEY" +humanoid_name_ends[10] = "BERRY" +humanoid_name_ends[11] = "BAUM" +humanoid_name_ends[12] = "LAN" +humanoid_name_ends[13] = "HAM" +humanoid_name_ends[14] = "SILL" +humanoid_name_ends[15] = "WIN" +humanoid_name_ends[16] = "LET" +humanoid_name_ends[17] = "ERS" +humanoid_name_ends[18] = "TON" +humanoid_name_ends[19] = "MOND" +humanoid_name_ends[20] = "MAN" +humanoid_name_ends[21] = "ELTON" +humanoid_name_ends[22] = "E" +humanoid_name_ends[23] = "MORE" +humanoid_name_ends[24] = "MOOR" +humanoid_name_ends[25] = "LET" +humanoid_name_ends[26] = "LIN" +menu.options = " OPÇOES " +menu.display = " TELA " +menu.file = " ARQUIVO " +menu.debug = " DEBUG " +menu.charts = " GRAFICOS " +letter[1][1] = "Olá %s!//" +letter[1][2] = "Fantástico! Dirigiu este hospital de uma maneira excelente. Nós, a elite do Ministério da Saúde, queríamos saber se estaria interessado em fazer parte de um grande projeto. Há um trabalho, no qual acreditamos que seja a pessoa perfeita. O salário seria de %d. Pense nisto.//" +letter[1][3] = "Está interessado em trabalhar no Hospital %s?" +letter[2][1] = "Olá %s!//" +letter[2][2] = "Parabéns! Realizou notáveis melhorias no seu hospital. Temos outro serviço que poderia se encarregar, se gostar de mudança e novos desafios. Näo tem que aceitar, mas seria bom que o fizesse. O salário é de %d//" +letter[2][3] = "Quer trabalhar no Hospital %s?" +letter[3][1] = "Olá %s!//" +letter[3][2] = "Dirigiu com notável desempenho este hospital durante o seu exercício. Ao chegar este ao seu fim, prevejo um brilhante futuro, e gostaríamos de lhe oferecer um cargo em outro lugar. O salário seria de %d, e acredito que adoraria o desafio que isto criaria.//" +letter[3][3] = "Gostaria de ter um posto no Hospital %s?" +letter[4][1] = "Olá %s!//" +letter[4][2] = "Parabéns! No Ministério estamos muito impressionados pela sua capacidade como diretor do hospital. É sem dúvida, uma pessoa valiosa para o Departamento de Saúde, mas acreditamos que preferiria um trabalho mais qualificado. Receberia um salário de %d, embora a decisäo seja sua.//" +letter[4][3] = "Está interessado em trabalhar no Hospital %s?" +letter[5][1] = "Olá %s!//" +letter[5][2] = "Saudaçöes novamente. Respeitamos os seus desejos de näo querer sair do seu estupendo hospital, mas pedimos que o reconsidere. Ofereceremos para você um alto salário de %d se decidir ir para o outro hospital e se encarregar da sua direçäo.//" +letter[5][3] = "Gostaria de ir agora para o Hospital %s?" +letter[6][1] = "Olá %s!//" +letter[6][2] = "Receba as nossas saudaçöes. Sabemos que desfrutou muito da sua estadia nesta instituiçäo, täo agradável e bem dirigida, mas acreditamos que agora deveria pensar no seu futuro. Naturalmente, teria um salário de %d se decidisse sair. Vale a pena pensar.//" +letter[6][3] = "Gostaria de ter um posto no Hospital %s?" +letter[7][1] = "Olá %s!//" +letter[7][2] = "Bom dia! O Ministério da Saúde queria saber se reconsideraria a sua decisäo de ficar no seu hospital. Compreendemos que tenha um estupendo hospital, mas acreditamos que faria muito bem em aceitar um trabalho mais estimulante, com um salário de %d.//" +letter[7][3] = "Aceitaria um posto no Hospital %s?" +letter[8][1] = "Olá %s!//" +letter[8][2] = "Olá, outra vez. Recebemos a sua resposta negativa na nossa última carta, em que oferecíamos um posto de direçäo em um outro hospital, e um alto salário de %d. Contudo, acreditamos que deveria reconsiderar esta decisäo. Como verá, temos o trabalho perfeito para você.//" +letter[8][3] = "Aceitaria um posto no Hospital %s, por favor?" +letter[9][1] = "Olá %s!//" +letter[9][2] = "Demonstrou ser o melhor diretor de hospital na longa e infeliz história da medicina. O lucro que obteve näo pode ficar sem recompensa, por isso lhe oferecemos o posto de Diretor Chefe de Todos os Hospitais. Terá um salário de %d, uma apresentaçäo com todas as honras e as pessoas demonstraräo o seu reconhecimento esteja onde estiver.//" +letter[9][3] = "Agradecemos por tudo o que fez e desfrute de uma longa semi-aposentadoria.//" +letter[9][4] = "" +letter[10][1] = "Olá %s!//" +letter[10][2] = "Parabéns por dirigir com êxito todos os hospitais que lhe atribuímos. Esta grande atuaçäo o capacita a viajar livremente por todo mundo. Receberá uma pensäo de %d e uma limousine, para poder viajar de cidade em cidade, saudando o seu incondicional público e incentivando o trabalho que realiza em todos os hospitais.//" +letter[10][3] = "Estamos orgulhosos e agradecidos pelo seu trabalho ao salvar vidas.//" +letter[10][4] = "" +letter[11][1] = "Olá %s!//" +letter[11][2] = "Sua carreira tem sido exemplar, e você é uma inspiraçäo para todos nós. Obrigado por dirigir täo bem tantos hospitais. Gostaríamos de lhe conceder um salário vitalício de %d, e só lhe pedimos que viaje em um carro oficial descoberto de cidade em cidade, dando conferências sobre os seus rápidos lucros.//" +letter[11][3] = "É um exemplo para todos os homens de bem e uma pessoa de enorme valor.//" +letter[11][4] = "" +letter[12][1] = "Olá %s!//" +letter[12][2] = "A sua bem-sucedida carreira como o melhor diretor de hospital desde Moisés está chegando ao seu fim. Você provocou tanto efeito nos círculos médicos, que o Ministério quer lhe oferecer um salário de %s, só para inaugurar festas, navios e organizar entrevistas em nosso nome. Você seria um excelente relaçöes públicas!//" +letter[12][3] = "Por favor, aceite. Será fácil e irá dispor de um veículo e uma escolta policial.//" +letter[12][4] = "" +place_objects_window.place_objects_in_corridor = "Coloque os objetos em um corredor." +place_objects_window.drag_blueprint = "Arraste a marca azul até que consiga o tamanho que deseja." +place_objects_window.pick_up_object = "Aperte sobre um objeto para selecioná-lo ou escolher outra opçäo do diálogo." +place_objects_window.place_windows = "Se quiser, coloque algumas janelas. Em seguida, aperte confirmar." +place_objects_window.place_objects = "Coloque os objetos e mova-os ao seu gosto. Em seguida, confirme." +place_objects_window.confirm_or_buy_objects = "Pode confirmar a sala, comprar ou mover alguns objetos." +place_objects_window.place_door = "Coloque a porta" +level_names[1] = "Cidade Contaminada" +level_names[2] = "Cidade do Sonho" +level_names[3] = "Vila Grande" +level_names[4] = "Vila Praia" +level_names[5] = "Vila Simples" +level_names[6] = "Vilaúlcera" +level_names[7] = "Cidade Verde" +level_names[8] = "Cidade do Porto" +level_names[9] = "Cidade Leste" +level_names[10] = "Ovovile" +level_names[11] = "Vila Corvo" +level_names[12] = "Vila Próspera" +level_names[13] = "Vila Amistosa" +level_names[14] = "Vila Pancadaria" +level_names[15] = "Vila Sepultura" +pay_rise.definite_quit = "Faça o que fizer, näo ficarei. Estou farto deste local." +pay_rise.regular[1] = "Estou esgotado. Preciso de umas boas férias, mais um aumento de %d, se näo quiser deixo este maldito emprego." +pay_rise.regular[2] = "Estou muito cansado. Preciso de umas férias e de um aumento salarial de %d, até um total de %d. E quero já, seu tirano!" +pay_rise.regular[3] = "Vamos! Trabalho como um escravo. Se me der um bônus de %d, ficarei no seu hospital." +pay_rise.regular[4] = "Estou muito descontente. Exijo um aumento de %d, e um salário final de %d, caso contrário, vou embora." +pay_rise.regular[5] = "Os meus pais me disseram que os médicos ganham um bom salário, sendo assim, me dê um aumento de %d ou me dedicarei à produçäo de jogos de computador." +pay_rise.regular[6] = "Estou farto. Pague-me um bom salário. Será suficiente um aumento de %d." +pay_rise.poached = "%s ofereceu-me um salário de %d. Se näo me pagar o mesmo, vou embora." +casebook.reputation = "reputaçäo" +casebook.earned_money = "dinheiro ganho" +casebook.cure_desc.no_cure_known = "Näo há cura conhecida." +casebook.cure_desc.hire_doctors = "Você precisa contratar alguns médicos." +casebook.cure_desc.build_ward = "Ainda tem que construir uma enfermaria." +casebook.cure_desc.improve_cure = "Melhorar Cura." +casebook.cure_desc.build_room = "Sugiro que construa %s" +casebook.cure_desc.hire_surgeons = "Você precisa contratar cirurgiöes." +casebook.cure_desc.cure_known = "Cura." +casebook.cure_desc.hire_psychiatrists = "Você precisa contratar psiquiatras." +casebook.cure_desc.hire_nurses = "Você deve contratar algumas enfermeiras." +casebook.sent_home = "rejeitados" +casebook.cured = "recuperaçöes" +casebook.deaths = "falecimentos" +casebook.treatment_charge = "custo tratamento" +casebook.research = "pesquisa intensiva" +casebook.cure = "cura" +confirmation.replace_machine = "Quer mesmo substituir esta máquina?" +confirmation.quit = "Escolheu sair do jogo. Tem certeza de que pretende sair do jogo?" +confirmation.sack_staff = "Tem certeza de que pretende despedir este funcionário?" +confirmation.delete_room = "Quer mesmo eliminar esta consulta?" +confirmation.return_to_blueprint = "Tem certeza de que pretende substituir o(a) %s por $%d?" +confirmation.overwrite_save = "Já existe um jogo salvo neste local. Tem certeza de que pretende substitui-lo?" +menu_options_volume[80] = " 80% " +menu_options_volume[50] = " 50% " +menu_options_volume[100] = " 100% " +menu_options_volume[70] = " 70% " +menu_options_volume[40] = " 40% " +menu_options_volume[90] = " 90% " +menu_options_volume[60] = " 60% " +menu_options_volume[20] = " 20% " +menu_options_volume[30] = " 30% " +menu_options_volume[10] = " 10% " +vip_names[1] = "O Maior dos Ricaços" +vip_names[2] = "Lawrence Nightingale" +vip_names[3] = "Rei Bernard da Holanda" +vip_names[4] = "Aung Sang Su Kyi" +vip_names[5] = "Sir Reginald Crumbly" +vip_names[7] = "O Vereador Joäo Precipício" +vip_names[8] = "O Marquês do Figo de Chumbo" +vip_names[9] = "Uma estrela do futebol" +vip_names[10] = "A. Eskoplovitz, II" +vip_names.health_minister = "O Ministro da Saúde" +menu_charts.briefing = " INSTRUÇOES " +diseases.kidney_beans.cause = "Causa - Mastigar os cubos de gelo das bebidas." +diseases.kidney_beans.name = "Incontinência" +diseases.kidney_beans.symptoms = "Sintomas - Dor e idas frequentes ao banheiro." +diseases.kidney_beans.cure = "Cura - Dois cirurgiöes extraem as pedras dos rins." +diseases.ruptured_nodules.cause = "Causa - Fazer bungee jumping em tempo frio." +diseases.ruptured_nodules.name = "Boluditis" +diseases.ruptured_nodules.symptoms = "Sintomas - Incapacidade de se sentar confortavelmente." +diseases.ruptured_nodules.cure = "Cura - Dois cirurgiöes qualificados colocam certas partes com mäos firmes." +diseases.fractured_bones.cause = "Causa - Queda de um lugar alto." +diseases.fractured_bones.name = "Fraturas ósseas" +diseases.fractured_bones.symptoms = "Sintomas - Um grande rangido e a impossibilidade de usar os membros afetados." +diseases.fractured_bones.cure = "Cura - É colocado um molde, depois com uma máquina à laser o remove. " +diseases.diag_psych.name = "Diag: Psiquiatria" +diseases.jellyitis.cause = "Causa - Uma dieta rica em gelatina e muito exercício." +diseases.jellyitis.name = "Gelatinitis" +diseases.jellyitis.symptoms = "Sintomas - Um tremor excessivo e cair ao chäo muitas vezes." +diseases.jellyitis.cure = "Cura - Inunda-se o paciente durante um momento no banheiro gelatinoso em uma consulta especial." +diseases.discrete_itching.cause = "Causa - Insetos diminutos com os dentes afiados." +diseases.discrete_itching.name = "Coceira leve" +diseases.discrete_itching.symptoms = "Sintomas - Arranhar-se, o que conduz a um inchaço da parte afetada." +diseases.discrete_itching.cure = "Cura - O paciente bebe um xarope farmacêutico para evitar a coceira da pele." +diseases.alien_dna.cause = "Causa - Enfrentara gigantes providos de sangue alienígena inteligente." +diseases.alien_dna.name = "DNA alienígena" +diseases.alien_dna.symptoms = "Sintomas - Metamorfose alienígena gradual e desejo de destruir nossas cidades." +diseases.alien_dna.cure = "Cura - O DNA é mecanicamente removido, limpo de elementos alienígenas e substituídos rapidamente." +diseases.infectious_laughter.cause = "Causa - Comédia clássica de situaçäo." +diseases.infectious_laughter.name = "Risada contagiosa" +diseases.infectious_laughter.symptoms = "Sintomas - Näo poder parar de rir e repetir frases feitas nada divertidas." +diseases.infectious_laughter.cure = "Cura - Um psiquiatra qualificado deve recordar o paciente que a sua doença é grave." +diseases.diag_general_diag.name = "Diag: Geral" +diseases.spare_ribs.cause = "Causa - Sentar-se sobre chäos muito frios." +diseases.spare_ribs.name = "Costelas de mais" +diseases.spare_ribs.symptoms = "Sintomas- Um mal-estar no peito." +diseases.spare_ribs.cure = "Cura - Dois cirurgiöes extraem as costelas e däo ao paciente em uma sacola." +diseases.transparency.cause = "Causa - Lamber tampa de iogurte já usado." +diseases.transparency.name = "Transparentitis" +diseases.transparency.symptoms = "Sintomas - A carne fica transparente e fica horrível." +diseases.transparency.cure = "Cura - Tomar uma preparaçäo farmacêutica de água esfriada e colorida de modo especial." +diseases.baldness.cause = "Causa - Contar mentiras e inventar histórias para ser famoso." +diseases.baldness.name = "Calvície" +diseases.baldness.symptoms = "Sintomas - Ter a cabeça brilhante e passar vergonha." +diseases.baldness.cure = "Cura - O cabelo está costurado à cabeça do paciente com uma dolorosa máquina." +diseases.sleeping_illness.cause = "Causa - Uma glândula do sono hiperativa no céu da boca." +diseases.sleeping_illness.name = "Sonolência" +diseases.sleeping_illness.symptoms = "Sintomas - Um desejo imprescindível de mergulhar no sono." +diseases.sleeping_illness.cure = "Cura - Uma enfermeira administra uma dose elevada de um poderoso estimulante." +diseases.pregnancy.cause = "Causa - Cortes de eletricidade em áreas urbanas." +diseases.pregnancy.name = "Grávida" +diseases.pregnancy.symptoms = "Sintomas - Muita vontade de comer e um mal-estar no estômago." +diseases.pregnancy.cure = "Cura - Extrai-se ao bebé na sala de operaçöes, limpa-se e entrega-se ao paciente." +diseases.general_practice.name = "Clínica Geral" +diseases.tv_personalities.cause = "Causa - Ver televisäo durante o dia." +diseases.tv_personalities.name = "Personalitis" +diseases.tv_personalities.symptoms = "Sintomas - Ter a ilusäo de apresentar na televisäo um programa de cozinha." +diseases.tv_personalities.cure = "Cura - Um psiquiatra perito deve convencer o paciente de que venda o seu televisor e compre um rádio." +diseases.broken_wind.cause = "Causa - Usar um aparelho ginástico depois das comidas." +diseases.broken_wind.name = "Aerofagia" +diseases.broken_wind.symptoms = "Sintomas - Incomoda as pessoas que estäo mesmo atrás do paciente." +diseases.broken_wind.cure = "Cura - Na farmácia bebe-se rapidamente uma forte mistura de átomos aquosos." +diseases.hairyitis.cause = "Causa - Exposiçäo prolongada à lua." +diseases.hairyitis.name = "Peludismo" +diseases.hairyitis.symptoms = "Sintomas - Pacientes com olfato mais sensível." +diseases.hairyitis.cure = "Cura - Uma máquina de eletrólise elimina o pêlo e fecha os poros." +diseases.diag_ward.name = "Diag: Clínico" +diseases.third_degree_sideburns.cause = "Causa - Desejar muito os anos 70 ." +diseases.third_degree_sideburns.name = "Costeletas de terceiro grau" +diseases.third_degree_sideburns.symptoms = "Sintomas - Corte comprido, roupa larga, plataformas e muita maquilhagem." +diseases.third_degree_sideburns.cure = "Cura - O pessoal psiquiátrico deve, empregando técnicas atualizadas, convencer o paciente de que esta moda é horrível." +diseases.gut_rot.cause = "Causa - O Xarope para a tosse, a base de uísque, da Sra. McGuiver." +diseases.gut_rot.name = "Ulcera gástrica" +diseases.gut_rot.symptoms = "Sintomas - O paciente näo tosse, mas também näo tem paredes no estômago." +diseases.gut_rot.cure = "Cura - Uma enfermeira administra uma variada dissoluçäo de substâncias químicas para revestir o estômago." +diseases.chronic_nosehair.cause = "Causa - Cheirar com desprezo aqueles que estäo pior que o paciente." +diseases.chronic_nosehair.name = "Nariz peludo" +diseases.chronic_nosehair.symptoms = "Sintomas - Ter tanto cabelo no nariz para fazer uma peruca." +diseases.chronic_nosehair.cure = "Cura - Tomar por via oral um xarope retira-pêlo, que a enfermeira prepara na farmácia." +diseases.the_squits.cause = "Causa - Comer pizza que encontrou debaixo da mesa da cozinha." +diseases.the_squits.name = "Decomposiçäo" +diseases.the_squits.symptoms = "Sintomas - Agh! Certamente pode imaginar isto." +diseases.the_squits.cure = "Cura - Uma mistura pegajosa de substâncias viscosas preparada na farmácia solidifica as tripas do paciente." +diseases.fake_blood.cause = "Causa - O paciente está acostumado a ser o branco das brincadeiras." +diseases.fake_blood.name = "Sangue falso" +diseases.fake_blood.symptoms = "Sintomas - Fluido vermelho nas veias que se evapora no contato com a roupa." +diseases.fake_blood.cure = "Cura - Este problema só se resolve com tratamento psiquiátrico." +diseases.corrugated_ankles.cause = "Causa - Avançar sinal vermelho do semáforo." +diseases.corrugated_ankles.name = "Tornozelo torcido" +diseases.corrugated_ankles.symptoms = "Sintomas - Os pés näo cabem bem nos sapatos." +diseases.corrugated_ankles.cure = "Cura - Os tornozelos säo endireitados, bebendo uma infusäo ligeiramente tóxica de ervas e plantas." +diseases.diag_x_ray.name = "Diag: Raio-X" +diseases.invisibility.cause = "Causa - A picada de uma formiga radioativa (e invisível)." +diseases.invisibility.name = "Invisibilidade" +diseases.invisibility.symptoms = "Sintomas - Os Pacientes näo sofrem, porém, às vezes gostam de pregar peças em seus familiares." +diseases.invisibility.cure = "Cura - Beber um líquido colorido na farmácia, fazendo completamente visível o paciente." +diseases.sweaty_palms.cause = "Causa - Temer as entrevistas de trabalho." +diseases.sweaty_palms.name = "Mäos suadas" +diseases.sweaty_palms.symptoms = "Sintomas - Dar a mäo ao paciente é como agarrar uma esponja encharcada." +diseases.sweaty_palms.cure = "Cura - Um psiquiatra deve discutir a fundo com o paciente sobre esta doença inventada." +diseases.bloaty_head.cause = "Causa - Cheirar queijo e beber água da chuva näo purificada." +diseases.bloaty_head.name = "Cabeça inchada" +diseases.bloaty_head.symptoms = "Sintomas - Muito desconforto pelo que parece." +diseases.bloaty_head.cure = "Cura - Fura-se a cabeça inflada, em seguida, volta-se a inflar até o tamanho correto com uma máquina inteligente." +diseases.heaped_piles.cause = "Causa - Permanecer de pé junto a refrigeradores de água." +diseases.heaped_piles.name = "Hemorroidas" +diseases.heaped_piles.symptoms = "Sintomas - O paciente sente-se como se estivesse sentado sobre bolas de gude." +diseases.heaped_piles.cure = "Cura - Uma bebida agradável, embora muito ácida, dissolve as hemorroidas internas." +diseases.king_complex.cause = "Causa - O espírito do rei entrou na mente do paciente e se apoderou dela." +diseases.king_complex.name = "Complexo de rei" +diseases.king_complex.symptoms = "Sintomas - Calçar sapatos de camurça e comer hambúrgueres." +diseases.king_complex.cure = "Cura - Um Psiquiatra conta ao paciente como ele está ridículo." +diseases.golf_stones.cause = "Causa - Inalar gás venenoso contendo bolas de golfe." +diseases.golf_stones.name = "Cálculos de golfe" +diseases.golf_stones.symptoms = "Sintomas - Delirar e sentir muita vergonha." +diseases.golf_stones.cure = "Cura - Dois cirurgiöes operam para extrair os cálculos." +diseases.gastric_ejections.cause = "Causa - Comida mexicana ou da India muito condimentada." +diseases.gastric_ejections.name = "Vômito" +diseases.gastric_ejections.symptoms = "Sintomas - O paciente vomita a comida ao meio digerir em qualquer momento." +diseases.gastric_ejections.cure = "Cura - Beber um preparado adstringente especial para parar os vômitos." +diseases.unexpected_swelling.cause = "Causa - Algo inesperado." +diseases.unexpected_swelling.name = "Inchaço inesperado" +diseases.unexpected_swelling.symptoms = "Sintomas - Inchaço." +diseases.unexpected_swelling.cure = "Cura - Só pode reduzir o inchaço com uma lanceta durante uma operaçäo que requer dois cirurgiöes." +diseases.slack_tongue.cause = "Causa - Fazer muita fofoca." +diseases.slack_tongue.name = "Língua comprida" +diseases.slack_tongue.symptoms = "Sintomas - A língua cresce até cinco vezes o seu tamanho original." +diseases.slack_tongue.cure = "Cura - Coloca-se a língua no corta-línguas e elimina-se de forma rápida, eficaz e dolorosa." +diseases.diag_scanner.name = "Diag: Scanner" +diseases.uncommon_cold.cause = "Causa - Pequenas partículas de muco no ar." +diseases.uncommon_cold.name = "Catarro atípico" +diseases.uncommon_cold.symptoms = "Sintomas - Mucosidade, espirros e pulmöes descoloridos." +diseases.uncommon_cold.cure = "Cura - Beber um grande gole de um xarope estranho para tosse fabricado na farmácia com ingredientes especiais." +diseases.broken_heart.cause = "Causa - Alguém mais rico, mais jovem e mais magro que o paciente." +diseases.broken_heart.name = "Infelicidade" +diseases.broken_heart.symptoms = "Sintomas - Chorar e rir depois de passar horas rasgando as fotos das férias." +diseases.broken_heart.cure = "Cura - Dois cirurgiöes abrem o peito e arrumam com delicadeza o coraçäo enquanto prendem a respiraçäo." +diseases.diag_blood_machine.name = "Diag: Análise Sanguínea" +diseases.diag_cardiogram.name = "Diag: Cardiologia" +diseases.serious_radiation.cause = "Causa - Confundir isótopos de plutônio com chiclete." +diseases.serious_radiation.name = "Radiaçäo Grave" +diseases.serious_radiation.symptoms = "Sintomas - Os pacientes com essa doença se sentem muito mal." +diseases.serious_radiation.cure = "Cura - O Paciente deve ir para a Ducha de Descontaminaçäo para se limpar." +diseases.iron_lungs.cause = "Causa - A contaminaçäo urbana misturada com restos do Kebab." +diseases.iron_lungs.name = "Pulmäo de aço" +diseases.iron_lungs.symptoms = "Sintomas - Capacidade para aspirar fogo e gritar debaixo da água." +diseases.iron_lungs.cure = "Cura - Dois cirurgiöes realizam uma operaçäo para eliminar as partes duras do pulmäo na sala de operaçöes." +diseases.diag_ultrascan.name = "Diag: Ultra Scanner" +diseases.autopsy.name = "Autópsia" +dynamic_info.staff.ability = "Habilidade" +dynamic_info.staff.psychiatrist_abbrev = "Psiq." +dynamic_info.staff.actions.waiting_for_patient = "Esperando um paciente" +dynamic_info.staff.actions.wandering = "Andando por aí" +dynamic_info.staff.actions.going_to_repair = "Indo reparar %s" +dynamic_info.staff.tiredness = "Cansaço" +dynamic_info.vip = "Visitante VIP" +dynamic_info.patient.diagnosis_progress = "Diagnóstico em curso" +dynamic_info.patient.emergency = "Emergências: %s" +dynamic_info.patient.diagnosed = "Diagnóstico: %s " +dynamic_info.patient.guessed_diagnosis = "Bom diagnóstico: %s" +dynamic_info.patient.actions.fed_up = "Perdeu a paciência - Indo para casa" +dynamic_info.patient.actions.waiting_for_diagnosis_rooms = "Esperando a construçäo da consulta" +dynamic_info.patient.actions.sent_to_other_hospital = "Enviado para outro local" +dynamic_info.patient.actions.on_my_way_to = "Indo para %s" +dynamic_info.patient.actions.waiting_for_treatment_rooms = "Esperando a construçäo do tratamento" +dynamic_info.patient.actions.queueing_for = "Na fila para %s" +dynamic_info.patient.actions.epidemic_contagious = "Tenho uma doença contagiosa" +dynamic_info.patient.actions.no_diagnoses_available = "Näo há mais diagnósticos, vou embora" +dynamic_info.patient.actions.awaiting_decision = "Esperando por sua decisäo" +dynamic_info.patient.actions.sent_home = "Dado alta" +dynamic_info.patient.actions.cured = "Curado!" +dynamic_info.patient.actions.prices_too_high = "Os seus preços säo muito altos, vou embora" +dynamic_info.patient.actions.epidemic_sent_home = "Enviado para casa por um Inspetor" +dynamic_info.patient.actions.no_treatment_available = "Näo há tratamentos, vou para casa." +dynamic_info.patient.actions.dying = "Morrendo!" +dynamic_info.object.strength = "Resistência %d" +dynamic_info.object.queue_expected = "Fila esperada %d" +dynamic_info.object.times_used = "Utilizado %d vezes" +dynamic_info.object.queue_size = "Tamanho da fila %d" +dynamic_info.health_inspector = "Inspetor de Saúde" +town_map.chat = "Detalhes da cidade" +town_map.not_for_sale = "Näo vende-se" +town_map.price = "Preço" +town_map.number = "Número" +town_map.owner = "Proprietário" +town_map.for_sale = "Vende-se" +town_map.area = "Terreno" +misc.grade_adverb.mildly = "ligeiramente" +misc.grade_adverb.moderately = "moderadamente" +misc.grade_adverb.extremely = "extremamente" +misc.out_of_sync = "Jogo fora de sincronismo" +misc.load_failed = "Jogo näo carregado" +misc.send_message_all = "Enviar mensagem para todos os jogadores" +misc.hospital_open = "Hospital Aberto" +misc.save_failed = "ERRO: Näo foi possível salvar o jogo" +misc.mouse = "Rato" +misc.pause = "Pausa" +misc.done = "Concluído" +misc.send_message = "Enviar mensagem para o jogador %d" +misc.balance = "Arquivo de Balanço:" +misc.low_res = "Baixa Resoluçäo" +misc.force = "Mäo-de-obra" +misc.save_success = "Jogo salvo com êxito" +drug_companies[1] = "Laboratórios Joäo" +drug_companies[2] = "Curatudo S.A." +drug_companies[3] = "Pequena Pílula Co." +drug_companies[4] = "Remédios Seguros S.A" +drug_companies[5] = "Omnipharma Corp." +high_score.score = "PONTOS" +high_score.pos = "POS" +high_score.worst_scores = "GALERIA DA VERGONHA" +high_score.categories.cures = "NUMERO DE CURAS" +high_score.categories.cure_death_ratio = "MEDIA DE CURAS E MORTES" +high_score.categories.total_value = "VALOR TOTAL" +high_score.categories.visitors = "MAIS VISITANTES" +high_score.categories.clean = "LIMPEZA" +high_score.categories.money = "O MAIS RICO" +high_score.categories.salary = "SALARIO MAIS ALTO" +high_score.categories.deaths = "NUMERO DE MORTES" +high_score.categories.patient_happiness = "CLIENTES SATISFEITOS" +high_score.categories.staff_number = "FUNCIONARIOS" +high_score.categories.staff_happiness = "FUNCIONARIOS CONTENTES" +high_score.player = "JOGADOR" +high_score.best_scores = "GALERIA DA FAMA" +high_score.killed = "Morto" +competitor_names[1] = "ORAC" +competitor_names[2] = "COLOSSUS" +competitor_names[3] = "HAL" +competitor_names[4] = "MULTIVAC" +competitor_names[5] = "HOLLY" +competitor_names[6] = "DEEP THOUGHT" +competitor_names[7] = "ZEN" +competitor_names[8] = "LEON" +competitor_names[9] = "MARVIN" +competitor_names[10] = "AKIRA" +competitor_names[11] = "MOTHER" +competitor_names[12] = "JAYNE" +competitor_names[13] = "CORSIX" +competitor_names[14] = "ROUJIN" +competitor_names[15] = "EDVIN" +competitor_names[16] = "SAM" +competitor_names[17] = "CHARLIE" +competitor_names[18] = "ARTHUR" +competitor_names[19] = "MAGNUS" +competitor_names[20] = "SAL" +competitor_names[21] = "JOSHUA" +competitor_names[22] = "DANEEL" +competitor_names[23] = "OLIVAW" +competitor_names[24] = "NIC" +staff_class.handyman = "Faz-tudo" +staff_class.nurse = "Enfermeira" +staff_class.surgeon = "Cirurgiäo" +staff_class.receptionist = "Recepcionista" +staff_class.doctor = "Médico" +menu_debug.display_pager = " MOSTRAR PAGINADOR " +menu_debug.nav_bits = " NAV BITS " +menu_debug.win_level_anim = " SUPERAR NIVEL ANIM " +menu_debug.plant_pagers = " PAGINADORES DE PLANTAS " +menu_debug.display_room_status = " MOSTRAR ESTADO DA CONSULTA" +menu_debug.show_nav_cells = " MOSTRAR CELAS NAV " +menu_debug.entry_cells = " CELAS DE ENTRADA " +menu_debug.object_cells = " CELAS DE OBJETO " +menu_debug.lose_game_anim[1] = " PERDER JOGO 1 ANIM " +menu_debug.lose_game_anim[2] = " PERDER JOGO 2 ANIM " +menu_debug.lose_game_anim[3] = " PERDER JOGO 3 ANIM " +menu_debug.lose_game_anim[4] = " PERDER JOGO 4 ANIM " +menu_debug.lose_game_anim[5] = " PERDER JOGO 5 ANIM " +menu_debug.lose_game_anim[6] = " PERDER JOGO 6 ANIM " +menu_debug.lose_game_anim[7] = " PERDER JOGO 7 ANIM " +menu_debug.show_help_hotspot = " MOSTRAR AJUDAS " +menu_debug.porter_pagers = " PAGINADORES DE FAZ-TUDO " +menu_debug.mapwho_checking = " VERIFICAR LOCALIZAÇAO " +menu_debug.machine_pagers = " PAGINADORES DE MAQUINA " +menu_debug.keep_clear_cells = " CONSERVAR AS CELAS LIMPAS " +menu_debug.enter_nav_debug = " INTRODUZIR NAV DEBUG " +menu_debug.win_game_anim = " GANHAR JOGO ANIM " +menu_debug.remove_objects = " RETIRAR OBJETOS " +menu_debug.display_big_cells = " MOSTRAR CELAS GRANDES " +menu_debug.pixbuf_cells = " CELAS PIXBUF " +menu_debug.remove_walls = " RETIRAR PAREDES " +research.categories.drugs = "Pesquisa farmacêutica" +research.categories.cure = "Equipam. de cura" +research.categories.improvements = "Melhorias" +research.categories.specialisation = "Especializaçäo" +research.categories.diagnosis = "Equipam. de diagnóstico" +research.funds_allocation = "Alocaçäo de fundos" +research.allocated_amount = "Quantidade alocada" +months[1] = "Jan" +months[2] = "Fev" +months[3] = "Mar" +months[4] = "Abr" +months[5] = "Mai" +months[6] = "Jun" +months[7] = "Jul" +months[8] = "Ago" +months[9] = "Set" +months[10] = "Out" +months[11] = "Nov" +months[12] = "Dez" +trophy_room.cleanliness.award[1] = "Os Inspetores notaram que o seu hospital está muito limpo. Um hospital limpo é um hospital seguro. Continue assim." +trophy_room.cleanliness.regional_good[1] = "Seu hospital foi apontado como um dos menos limpos da regiäo. Um hospital sujo, que cheira mal e é perigoso. Deveria se preocupar mais com a limpeza." +trophy_room.cleanliness.regional_bad[1] = "O seu hospital é o mais sujo da regiäo. Outros diretores conseguiram manter os seus hospitais mais limpos. Você é a vergonha da profissäo médica." +trophy_room.happy_vips.trophies[1] = "Ganhou o Prêmio Nobel de VIP Exemplares. Todos os que visitaram o seu hospital no ano passado o elogiaram muito." +trophy_room.happy_vips.trophies[2] = "A Agência de Pessoas Famosas deseja-lhe conceder o Prêmio à Celebridade por ter agradado a todos os VIP que visitaram o seu hospital." +trophy_room.happy_vips.trophies[3] = "Ganhou a VIAGEM VIP por melhorar a imagem dos trabalhadores aos olhos de todos os que visitaram o seu hospital. Estupendo!" +trophy_room.gen_repairs.awards[1] = "Foi-lhe concedido um prêmio especial pela diligência dos seus faz-tudo na hora de manter as máquinas do seu hospital em bom estado. Muito bem. Tire umas férias." +trophy_room.gen_repairs.awards[2] = "Os seus faz-tudo trabalharam melhor que os de qualquer outro hospital. Este é um importante acontecimento de felicidade." +trophy_room.gen_repairs.awards[3] = "As suas máquinas estäo em um magnífico estado. A dedicaçäo dos seus faz-tudo foi extraordinária. Merecem este prestigioso prêmio. Um trabalho estupendo!" +trophy_room.gen_repairs.penalty[1] = "Os seus faz-tudo näo cuidaram bem das suas máquinas. Deveria fiscalizá-los melhor ou contratar mais para que façam o trabalho melhor." +trophy_room.gen_repairs.penalty[2] = "Näo fez uma boa manutençäo. Os seus funcionários deveriam cuidar melhor dos seus equipamentos." +trophy_room.many_cured.penalty[1] = "O seu hospital näo cura com eficácia os pacientes que o necessitam. Tenha mais atençäo às curas para que sejam mais eficazes." +trophy_room.many_cured.penalty[2] = "O seu hospital é o menos eficaz na hora de curar pacientes. Decepcionou o Ministério e defraudou a si mesmo. Näo diremos mais." +trophy_room.many_cured.trophies[1] = "Parabéns pela concessäo do prêmio Marie Curie por ter curado quase todos os pacientes do seu hospital no ano passado." +trophy_room.many_cured.trophies[2] = "A Fundaçäo Nacional de Curas deseja premiá-lo por ter curado um grande número de pacientes no ano passado, concedendo o Galardäo ao Maior Curador." +trophy_room.many_cured.trophies[3] = "Foi-lhe concedido a Medalha do Paciente Säo por ter conseguido curar no seu hospital uma enorme porcentagem de pacientes no ano passado." +trophy_room.many_cured.awards[1] = "Parabéns por curar um montäo de pessoas no ano passado. Um grande número de pessoas sente-se muito melhor, graças ao seu trabalho." +trophy_room.many_cured.awards[2] = "Pedimos que aceite este prêmio por ter curado mais pacientes que qualquer outro hospital. Um excelente trabalho." +trophy_room.many_cured.regional[1] = "Você recebeu o prêmio de cura total por ter curado mais pessoas do que todos os outros hospitais juntos." +trophy_room.sold_drinks.trophies[1] = "A Associaçäo Odontológica orgulha-se de lhe conceder este troféu e esta placa por vender um montäo de bebidas em lata no seu hospital." +trophy_room.sold_drinks.trophies[2] = "O seu hospital foi premiado com o prêmio Bizz-Efervescente pela Venda de Refrigerante em reconhecimento ao número de bebidas vendidas em seu hospital no ano passado." +trophy_room.sold_drinks.trophies[3] = "Em nome de DK Obturaçöes Inc., você recebe o prêmio coberto de chocolate para celebrar a enorme quantidade de refrigerantes que vendeu no seu hospital este ano." +trophy_room.consistant_rep.trophies[1] = "O Conselho de ministros concedeu-lhe a Mençäo de Honra por ter alcançado o nível máximo de eficácia e reputaçäo durante o ano presente. Muito bem." +trophy_room.consistant_rep.trophies[2] = "Parabéns pela concessäo do Prêmio Lençóis Limpos por ser o hospital com a melhor reputaçäo do ano. Você mereceu." +trophy_room.cash = "EFETIVO" +trophy_room.high_rep.penalty[1] = "Vai ser sancionado pela má reputaçäo que teve no ano passado. Procure melhorar no futuro." +trophy_room.high_rep.penalty[2] = "A reputaçäo do seu hospital é a pior da área. É uma vergonha. Melhore ou consiga outro emprego." +trophy_room.high_rep.awards[1] = "Muito bem! Ganhou um pequeno prêmio por alcançar uma impressionante reputaçäo no ano passado." +trophy_room.high_rep.awards[2] = "Maravilhoso! O seu hospital ganhou um prêmio por conseguir a melhor reputaçäo no ano passado." +trophy_room.high_rep.regional[1] = "Por favor, aceite o Prêmio Bullfrog por dirigir o melhor hospital do ano. Você mereceu, aproveite." +trophy_room.high_rep.regional[2] = "Este ano, a reputaçäo do seu hospital superou a do resto dos hospitais. Um estupendo lucro." +trophy_room.best_value_hosp.trophies[1] = "Parabéns pela concessäo do Prêmio Lençóis Limpos por ser o hospital com a melhor reputaçäo do ano. Você mereceu." +trophy_room.best_value_hosp.regional[1] = "Parabéns por ter o hospital mais valioso do jogo. Bom trabalho! Por favor, continue assim." +trophy_room.best_value_hosp.penalty[1] = "Todos os hospitais da área valem mais do que o seu. Faça algo a respeito desta vergonhosa situaçäo. Consiga coisas mais caras!" +trophy_room.reputation = "REPUTAÇAO" +trophy_room.happy_staff.regional_good[1] = "Os seus funcionários säo os mais satisfeitos de todos os hospitais. Se os funcionários estäo contentes, há mais ganhos e menos mortes. No Ministério estäo satisfeitos." +trophy_room.happy_staff.penalty[1] = "Os seus funcionários desejam que saiba que estäo muito descontentes. Ter bons funcionários é muito proveitoso. Faça com que eles estejam mais satisfeitos ou algum dia irá perdê-los." +trophy_room.happy_staff.trophies[1] = "Ganhou o Prêmio Médico Sorridente por manter o mais contente possível os seus funcionários." +trophy_room.happy_staff.trophies[2] = "A Fundaçäo para a Felicidade do Pessoal Sanitário concedeu-lhe este galardäo por näo ter tido trabalhadores descontentes no seu hospital no ano passado." +trophy_room.happy_staff.trophies[3] = "Concedemos a você o prêmio Monopoliza do Sorriso Radiante por manter contente todos os seus funcionários, mais à frente do cumprimento do dever, durante o ano passado." +trophy_room.happy_staff.awards[1] = "Sua equipe te concedeu um prêmio. Eles dizem que, em geral, você manda muito bem." +trophy_room.happy_staff.awards[2] = "Seus funcionários säo täo felizes trabalhando para você que näo conseguem tirar os sorrisos dos seus rostos. Você é um gerente magnífico." +trophy_room.happy_staff.regional_bad[1] = "A sua equipe esteve muito infeliz durante o ano passado. Você deveria ter notado. Do jeito que está, as equipes dos outros hospitais estäo muito mais contentes do que a sua." +trophy_room.hosp_value.penalty[1] = "O seu hospital fracassou em alcançar um valor razoável. Gerenciou mal o dinheiro. Lembre-se, um bom hospital também é um hospital caro." +trophy_room.hosp_value.awards[1] = "O Ministério da Saúde gostaria de parabenizá-lo pelo impressionante valor alcançado em seu hospital." +trophy_room.hosp_value.regional[1] = "É uma promessa dos negócios. O hospital é o mais valioso de toda a área." +trophy_room.healthy_plants.awards[1] = "Parabéns por ganhar o galardäo do Grande Fertilizante por manter as suas plantas vivas durante o ano passado." +trophy_room.healthy_plants.trophies[1] = "Os Amigos das Plantas de Interior desejam lhe conceder o Prêmio de Saúde Verde por manter vivas as suas plantas durante os últimos doze meses." +trophy_room.healthy_plants.trophies[2] = "Salvem as Plantas quer concede-lhes o Prêmio do Maior Ecologista por manter vivas as plantas do seu hospital durante o ano passado." +trophy_room.research.penalty[1] = "Foi pouco eficiente ao investigar curas, máquinas e remédios novos. Isto é fatal, já que o avanço tecnológico é algo fundamental." +trophy_room.research.regional_good[1] = "As suas pesquisas conseguiram colocar o seu hospital nos últimos avanços de hoje em dia. Os seus pesquisadores merecem este prêmio. Muito bem!" +trophy_room.research.awards[1] = "As suas pesquisas conseguiram colocar o seu hospital nos últimos avanços de hoje em dia. Os seus pesquisadores merecem este prêmio. Muito bem!" +trophy_room.research.awards[2] = "No ano passado, descobriu mais remédios e máquinas do que se podia esperar. Por favor, aceite este prêmio de todos nós no Ministério." +trophy_room.research.regional_bad[1] = "Outros hospitais säo melhores que o seu na pesquisa. No Ministério estäo furiosos, seu hospital deveria lhe conceder mais importância." +trophy_room.no_deaths.penalty[1] = "O número de mortes no seu hospital, no ano passado, foi muito elevado. Empresta mais atençäo ao seu trabalho. Assegure-se de que no futuro sobreviva mais pessoas." +trophy_room.no_deaths.penalty[2] = "O seu hospital é um risco para os pacientes. Supöe-se que deve curar muitas pessoas, näo deixar morrer." +trophy_room.no_deaths.trophies[1] = "Ganhou o Galardäo da Queixa Ausente por manter 100%% dos seus pacientes com vida o ano passado." +trophy_room.no_deaths.trophies[2] = "A Associaçäo A Vida Continua concede-lhe este prêmio pela ausência de falecimentos no seu hospital este ano." +trophy_room.no_deaths.trophies[3] = "Você recebeu o Prêmio pela Conservaçäo da Vida por ter conseguido evitar falecimentos no seu hospital durante este ano. Genial!" +trophy_room.no_deaths.awards[1] = "Ganhou este prêmio como reconhecimento ao sob índice de falecimentos no seu hospital, este ano. É estupendo!" +trophy_room.no_deaths.awards[2] = "A sua habilidade conseguiu reduzir ao mínimo o número de mortes no seu hospital. Deve estar muito feliz com este resultado." +trophy_room.no_deaths.regional[1] = "No ano passado, a taxa de mortalidade do seu hospital foi inferior a dos outros. Por favor, aceite este prêmio." +trophy_room.rats_accuracy.trophies[1] = "Você recebeu o Prêmio de Disparos Certeiros Syndicate Wars por acertar em %d%% ratos no seu hospital no ano passado." +trophy_room.rats_accuracy.trophies[2] = "Este prêmio é para celebrar a sua incrível pontaria ao eliminar %d%% dos ratos que disparou no seu hospital no ano passado." +trophy_room.rats_accuracy.trophies[3] = "Para celebrar o fato de que eliminou %d%% dos ratos do seu hospital, foi-lhe concedido o Troféu de Eliminador de Roedores. Parabéns!" +trophy_room.emergencies.penalty[1] = "Foi muito pouco eficiente nos casos de emergência. Os pacientes de emergência merecem uma atençäo rápida e precisa, que você näo lhes deu." +trophy_room.emergencies.award[1] = "Parabéns! Ganhou este prêmio pela maneira eficaz e eficiente com a qual solucionou as emergências. Bom trabalho." +trophy_room.emergencies.award[2] = "Confrontou as emergências de uma maneira extraordinária. Ganhou este prêmio por ser o melhor na hora de lidar com uma grande quantidade de pacientes." +trophy_room.emergencies.regional_good[1] = "O Ministério reconhece que o ano passado no seu hospital, você tratou as emergências melhor do que qualquer outro hospital, entäo lhe concedeu este prêmio." +trophy_room.emergencies.regional_bad[1] = "O seu hospital é o pior da regiäo para tratar casos de emergência. Tem a culpa de ocupar o último lugar na Liga Local de Tratamentos de Emergência." +trophy_room.curesvdeaths.awards[1] = "Os meus mais sinceros parabéns. No ano passado, o número de curas foi superior ao de falecimentos no seu hospital." +trophy_room.curesvdeaths.penalty[1] = "A sua proporçäo entre curas e mortes é extremamente baixa. Deveria assegurar de que cura mais pessoas do que mata. Näo deixe os seus funcionários em mau lugar." +trophy_room.wait_times.award[1] = "Parabéns! No seu hospital a gente fez fila durante muito pouco tempo. Este é um acontecimento importante." +trophy_room.wait_times.penalty[1] = "No seu hospital, os pacientes esperam muito tempo. Há sempre filas inaceitáveis. Poderia tratar os seus pacientes com mais eficácia se quisesse." +trophy_room.happy_patients.awards[1] = "Deve estar orgulhoso de que, no ano passado, as pessoas estivesse muito contente no seu hospital." +trophy_room.happy_patients.awards[2] = "Os pacientes que visitaram o seu hospital sentiram-se mais contentes com o seu tratamento, que no resto dos hospitais." +trophy_room.happy_patients.penalty[1] = "As pessoas que väo para o hospital tem uma experiência terrível. Terá que fazê-lo muito melhor se quiser ganhar o respeito do Ministério." +trophy_room.happy_patients.penalty[2] = "As pessoas que recebeu tratamento no seu hospital queixaram-se do estado do mesmo. Deveria ter muito mais em conta o bem-estar dos pacientes." +trophy_room.pop_percentage.awards[1] = "Note, o ano passado curou uma grande parte da populaçäo local no seu hospital. Muito bem." +trophy_room.pop_percentage.awards[2] = "Parabéns! A maioria da populaçäo local vai ao seu hospital em vez de ir a qualquer outra instituiçäo." +trophy_room.pop_percentage.awards[3] = "Brilhante! O seu hospital recebeu o maior número de pacientes que todos os outros hospitais juntos." +trophy_room.pop_percentage.penalty[1] = "Teve muito poucos pacientes este ano. Para ganhar dinheiro, precisa que haja pacientes que paguem." +trophy_room.pop_percentage.penalty[2] = "Todos os hospitais da área conseguiram mais pacientes do que você. Deveria estar envergonhado." +trophy_room.rats_killed.trophies[1] = "Você recebeu o Troféu Raticida por eliminar %s ratos no seu hospital no ano passado." +trophy_room.rats_killed.trophies[2] = "Você merece este prêmio da Federaçäo Anti Ratos, pela sua excepcional habilidade em eliminar ratos, demonstrada ao eliminar %s exemplares." +trophy_room.rats_killed.trophies[3] = "Você recebeu o Troféu Acaba com Ratos pela sua grande habilidade em eliminar %d ratos no seu hospital no ano passado." +trophy_room.all_cured.awards[1] = "Parabéns por ter ganho o Prêmio Marie Curie por curar a todos os pacientes do seu hospital no ano passado." +trophy_room.all_cured.trophies[1] = "A Fundaçäo Curadores Nacionais premia-o por ter curado todos os pacientes do seu hospital no ano passado, concedendo-lhe o Prêmio do Maior Curador." +trophy_room.all_cured.trophies[2] = "Você recebeu a Medalha do Paciente Säo por ter conseguido curar todos os pacientes do seu hospital no ano passado." +graphs.cures = "Curas" +graphs.reputation = "Reputaçäo" +graphs.balance = "Balanço" +graphs.wages = "Salários" +graphs.visitors = "Visitantes" +graphs.time_spans[1] = "1 Ano " +graphs.time_spans[2] = "12 Anos" +graphs.time_spans[3] = "48 Anos" +graphs.deaths = "Mortes" +graphs.money_out = "Pagamento" +graphs.money_in = "Crédito" +queue_window.max_queue_size = "Máximo" +queue_window.num_expected = "Previsto" +queue_window.num_in_queue = "Tamanho da fila" +queue_window.num_entered = "Pacientes totais" +room_classes.clinics = "Clínica" +room_classes.facilities = "Instalaçöes" +room_classes.diagnosis = "Diagnóstico" +room_classes.treatment = "Tratamento" +rooms_short.ward = "Enfermaria" +rooms_short.blood_machine = "Transfusöes" +rooms_short.fracture_clinic = "Traumatologia" +rooms_short.cardiogram = "Cardiologia" +rooms_short.decontamination = "Descontaminaçäo" +rooms_short.jelly_vat = "Banho gelatinoso" +rooms_short.staffroom = "Sala de Descanso" +rooms_short.hair_restoration = "Pêloterapia" +rooms_short.inflation = "Inflatoterapia" +rooms_short.operating_theatre = "Sala de Operaçöes" +rooms_short.reception = "Recepçäo" +rooms_short.gps_office = "Consultório Geral" +rooms_short.training_room = "Formaçäo" +rooms_short.x_ray = "Raio-X" +rooms_short.tongue_clinic = "Laringologia" +rooms_short.general_diag = "Diagnóstico Geral" +rooms_short.ultrascan = "Ultra Scanner" +rooms_short.dna_fixer = "Genética" +rooms_short.psychiatric = "Psiquiatria" +rooms_short.toilets = "Banheiro" +rooms_short.corridor_objects = "Objetos do corredor" +rooms_short.pharmacy = "Farmácia" +rooms_short.destroyed = "Destruída" +rooms_short.research_room = "Centro de Pesquisa" +rooms_short.scanner = "Scanner" +rooms_short.electrolysis = "Eletrólise" +tooltip.status.warmth = "Nível global de calor das pessoas no seu hospital" +tooltip.status.close = "Fechar tela de condiçäo" +tooltip.status.thirst = "Nível global de sede das pessoas no seu hospital" +tooltip.status.population = "Você precisa ter %d%% da populaçäo total vindo para o seu hospital" +tooltip.status.num_cured = "O objetivo é curar %d pessoas. Até agora curou %d" +tooltip.status.percentage_killed = "O objetivo é matar pelo menos %d%% dos seus pacientes. Até agora morreram %d%%" +tooltip.status.percentage_cured = "Você precisa tratar %d%% dos visitantes do seu hospital. Até agora tratou %d%%" +tooltip.status.win_progress_own = "Mostra o progresso para conquistar os critérios do seu próprio hospital" +tooltip.status.value = "O seu hospital deve valer $%d. Agora vale $%d" +tooltip.status.happiness = "Nível global de satisfaçäo das pessoas no seu hospital" +tooltip.status.win_progress_other = "Mostra o progresso para conquistar os critérios de %s" +tooltip.status.population_chart = "Gráfico que mostra a proporçäo de pacientes de cada hospital da cidade" +tooltip.objects.bench = "Banco: serve de assento aos pacientes para que esperem com mais conforto." +tooltip.objects.pharmacy_cabinet = "Farmácia: onde se guardam os remédios" +tooltip.objects.console = "15 CONSOLES DE SCANNER" +tooltip.objects.atom_analyser = "Misturador químico: situado no Dept. de Desenvolvimento, esta máquina acelera todo o processo de pesquisa." +tooltip.objects.fire_extinguisher = "Extintor: reduz o perigo do mau funcionamento das máquinas." +tooltip.objects.scanner = "14 SCANNER" +tooltip.objects.bin = "Cesto de papéis: os pacientes atiram aqui os seus desperdícios." +tooltip.objects.swing_door1 = "52 PORTAS DUPLAS 1" +tooltip.objects.pool_table = "Mesa de bilhar: ajuda os seus funcionários a relaxarem." +tooltip.objects.screen = "16 TELAS" +tooltip.objects.cabinet = "Armário: contém fichas dos pacientes, notas e documentos sobre pesquisa." +tooltip.objects.sofa = "Sofá: Os empregados que descansam na sala de descanso sentaräo em um sofá, a menos que tenham uma maneira melhor de relaxar-se." +tooltip.objects.projector = "37 PROJETORES" +tooltip.objects.table2 = "12 MESAS" +tooltip.objects.shower = "54 DUCHAS DESCONTAMINADORAS" +tooltip.objects.comfortable_chair = "61 CADEIRA DE LEITURA" +tooltip.objects.door = "Porta: as pessoas fecham e abrem um montäo de vezes." +tooltip.objects.computer = "Computador: componente chave para a pesquisa" +tooltip.objects.litter_bomb = "Bomba de lixo: sabota os hospitais dos oponentes" +tooltip.objects.entrance_left = "58 PORTAS DIREITAS DE ENTRADA" +tooltip.objects.dna_fixer = "23 REPARADORES DE DNA" +tooltip.objects.bed = "Cama: as pessoas que estejam mesmo doentes deitam-se nela." +tooltip.objects.lamp = "Abajur: ilumina e permite que o pessoal veja." +tooltip.objects.bookcase = "Livraria: material de consulta para os médicos." +tooltip.objects.desk = "Escritório: é fundamental para que o médico coloque o seu PC." +tooltip.objects.toilet_sink = "Pia: os seus pacientes mais limpos lavam as suas mäos sujas aqui. Se näo houver suficientes pias, os pacientes ficam infelizes." +tooltip.objects.gates_of_hell = "48 PORTAS DO INFERNO" +tooltip.objects.swing_door2 = "53 PORTAS DUPLAS 2" +tooltip.objects.cast_remover = "24 REMOVEDOR DE GESSO" +tooltip.objects.plant = "Planta: alegra os pacientes e purifica o ar." +tooltip.objects.blood_machine = "42 TRANSFUSIOMETROS" +tooltip.objects.slicer = "26 CORTADORES" +tooltip.objects.x_ray = "27 RAIOS-X" +tooltip.objects.cardio = "13 ELETROCARDIOGRAMA" +tooltip.objects.crash_trolley = "20 CARROS" +tooltip.objects.bed2 = "näo se utiliza" +tooltip.objects.electrolyser = "46 ELETROLISIS" +tooltip.objects.video_game = "Videogame: deixe que os seus funcionários se divirtam com o Hi-Octane." +tooltip.objects.skeleton = "Esqueleto: é utilizado para aprender e na Noite do Halloween." +tooltip.objects.ultrascanner = "22 ULTRA SCANNER" +tooltip.objects.op_sink1 = "33 PIAS 1 OP" +tooltip.objects.hair_restorer = "25 PELO-RESTAURADORES" +tooltip.objects.reception_desk = "Recepçäo: requer uma recepcionista para que envie os pacientes para o médico." +tooltip.objects.radiation_shield = "28 TELAS ANTI-RADIACAO" +tooltip.objects.couch = "18 POLTRONAS" +tooltip.objects.inflator = "Inflador: cura a cabeça inflada." +tooltip.objects.toilet = "Banheiro: a natureza uma hora chama..." +tooltip.objects.lecture_chair = "Cadeira de leitura: os médicos que estäo estudando sentam-se aqui para tomar notas, aborrecer-se e rabiscar desnecessariamente. Quantas mais cadeiras colocar, mais compridas as aulas seräo." +tooltip.objects.auto_autopsy = "Autópsia: uma grande ajuda para descobrir novas curas." +tooltip.objects.chair = "Cadeira: os pacientes sentam-se sobre ela e falam das suas doenças." +tooltip.objects.x_ray_viewer = "29 TELAS DE RAIOS-X" +tooltip.objects.radiator = "Radiador: evita que o seu hospital fique frio." +tooltip.objects.bed3 = "näo se utiliza" +tooltip.objects.surgeon_screen = "35 TELAS DE CIRURGIAO" +tooltip.objects.jelly_moulder = "47 BANHOS GELATINOSOS" +tooltip.objects.drinks_machine = "Máquina de bebidas: impede que os pacientes tenham sede e contribui com ganhos." +tooltip.objects.op_sink2 = "34 PIAS 2 OP" +tooltip.objects.table1 = "Mesa: sobre ela coloca-se um montäo de revistas para que os pacientes esperem contentes." +tooltip.objects.entrance_right = "59 PORTAS ESQUERDAS DE ENTRADA" +tooltip.objects.operating_table = "30 MESAS DE OPERACOES" +tooltip.objects.tv = "TV: assegura de que os seus funcionários näo percam os seus programas favoritos." +tooltip.watch.hospital_opening = "Cronômetro de construçäo: é o tempo que resta para que o seu hospital seja declarado aberto. Se apertar o botäo IR abrirá o hospital imediatamente." +tooltip.watch.epidemic = "Epidemia: tempo que resta para encobrir a epidemia. Quando este tempo expire ou um paciente contagioso abandone o seu hospital, um Inspetor de Saúde vem visitar. O botäo liga ou desliga o modo vacina. Aperte em um paciente para que uma Enfermeira o vacine." +tooltip.watch.emergency = "Emergência: tempo que resta para curar todos os pacientes nas emergências." +tooltip.buy_objects_window.increase = "Comprar mais um objeto" +tooltip.buy_objects_window.price = "Preço do objeto" +tooltip.buy_objects_window.confirm = "Comprar objeto(s)" +tooltip.buy_objects_window.cancel = "Cancelar" +tooltip.buy_objects_window.decrease = "Comprar menos um objeto" +tooltip.buy_objects_window.total_value = "Custo total dos objetos solicitados" +tooltip.machine_window.status = "Estado das máquinas." +tooltip.machine_window.close = "Cancelar caixa de diálogo" +tooltip.machine_window.repair = "Mandar o faz-tudo reparar as máquinas." +tooltip.machine_window.name = "Nome" +tooltip.machine_window.times_used = "Número de vezes que reparou as máquinas." +tooltip.machine_window.replace = "Substituir máquinas" +tooltip.pay_rise_window.accept = "Satisfazer a sua demanda salarial" +tooltip.pay_rise_window.decline = "Näo pagar; despedi-los" +tooltip.staff_window.psychiatrist = "Psiquiatra" +tooltip.staff_window.close = "Cancelar caixa de diálogo" +tooltip.staff_window.sack = "Despedir" +tooltip.staff_window.name = "Nome do empregado" +tooltip.staff_window.pick_up = "Selecionar" +tooltip.staff_window.tiredness = "Nível de cansaço" +tooltip.staff_window.ability = "Nível de qualificaçäo" +tooltip.staff_window.researcher = "Pesquisador" +tooltip.staff_window.skills = "Qualificaçöes especiais" +tooltip.staff_window.salary = "Salário mensal" +tooltip.staff_window.happiness = "Nível de satisfaçäo" +tooltip.staff_window.doctor_seniority = "Categoria - Residente, Médico ou Consultor" +tooltip.staff_window.surgeon = "Cirurgiäo" +tooltip.research.cure_dec = "Reduzir a porcentagem dos equipamentos de curas" +tooltip.research.close = "Fechar tela de pesquisa" +tooltip.research.diagnosis_inc = "Aumentar a porcentagem dos equipamentos de diagnóstico" +tooltip.research.cure_inc = "Aumentar a porcentagem dos equipamentos de curas" +tooltip.research.specialisation_inc = "Aumentar a porcentagem em pesquisa especial" +tooltip.research.diagnosis_dec = "Reduzir a porcentagem dos equipamentos de diagnóstico" +tooltip.research.improvements_inc = "Aumentar a porcentagem nas melhorias" +tooltip.research.drugs_dec = "Reduzir a porcentagem da pesquisa farmacêutica" +tooltip.research.specialisation_dec = "Reduzir a porcentagem em pesquisa especial" +tooltip.research.improvements_dec = "Reduzir a porcentagem nas melhorias" +tooltip.research.drugs_inc = "Aumentar a porcentagem da pesquisa farmacêutica" +tooltip.research.allocated_amount = "Quantidade do orçamento alocado" +tooltip.statement.close = "Fechar tela do estado das contas" +tooltip.rooms.ward = "As enfermarias säo úteis tanto para diagnosticar como para tratamento. Envie aqui os pacientes para observaçäo e para recuperar de uma operaçäo sob o cuidado de uma enfermeira." +tooltip.rooms.blood_machine = "O médico usa o Transfusiômetro para diagnosticar os pacientes" +tooltip.rooms.fracture_clinic = "A enfermeira utiliza a consulta de traumatologia para arrumar fraturas" +tooltip.rooms.cardiogram = "O médico usa a cardiologia para diagnosticar os pacientes" +tooltip.rooms.decontamination = "O médico usa a ducha descontaminadora para curar a radioatividade" +tooltip.rooms.jelly_vat = "O médico usa o Banho Gelatinoso para curar a gelatinitis" +tooltip.rooms.staffroom = "Os médicos e as enfermeiras descansam na Sala de Descanso" +tooltip.rooms.hair_restoration = "O médico usa o Pêlo-restaurador para curar a calvície" +tooltip.rooms.inflation = "O médico usa a Inflatoterapia para curar a cabeça inflada" +tooltip.rooms.gps_office = "Os pacientes recebem sua primeira consulta na sala de Consultório Geral" +tooltip.rooms.training_room = "A sala de formaçäo com um consultor serve para formar outros médicos" +tooltip.rooms.x_ray = "O médico usa Raio-X para diagnosticar os pacientes" +tooltip.rooms.general_diag = "O médico utiliza a sala de Diagnóstico Geral para fazer um diagnóstico básico. É barato e frequentemente eficaz" +tooltip.rooms.operating_theatre = "Na sala de operaçöes faltam dois cirurgiöes qualificados" +tooltip.rooms.ultrascan = "O médico usa o Ultra-scanner para diagnosticar os pacientes" +tooltip.rooms.psychiatry = "A consulta de psiquiatria cura os pacientes loucos e ajuda a diagnosticar outros pacientes, mas requer um médico qualificado em psiquiatria." +tooltip.rooms.toilets = "Construa banheiros para impedir que os pacientes armem uma confusäo no seu hospital!" +tooltip.rooms.dna_fixer = "O médico usa o Reparador de DNA para curar os pacientes com DNA alienígena" +tooltip.rooms.pharmacy = "Na enfermaria, a enfermeira administra remédios para curar os pacientes" +tooltip.rooms.tongue_clinic = "O médico usa a Laringologia para curar a língua comprida" +tooltip.rooms.research_room = "Os médicos pesquisadores investigam remédios e máquinas novas no Centro de Pesquisa" +tooltip.rooms.scanner = "O médico usa o Scanner para diagnosticar os pacientes" +tooltip.rooms.electrolysis = "O médico usa a consulta de eletrólise para curar o peludismo" +tooltip.policy.diag_procedure = "Se o diagnóstico de um médico é menos seguro que a porcentagem de ENVIAR PARA CASA, o paciente será enviado para casa. Se o diagnóstico for melhor que a porcentagem de TENTAR CURA, será administrado o tratamento adequado ao paciente" +tooltip.policy.staff_leave = "Aperte aqui para que os funcionários livres ajudem os companheiros que precisem" +tooltip.policy.close = "Fechar tela de normas" +tooltip.policy.staff_rest = "Nível de cansaço dos funcionários antes de poderem descansar" +tooltip.policy.diag_termination = "O diagnóstico de um paciente continuará até que os médicos estejam seguros da porcentagem de PARAR PROCESSO, ou até que sejam utilizados todos os diagnósticos" +tooltip.policy.staff_stay = "Aperte aqui para assegurar que o funcionário fique nas consultas que foram atribuídas a ele" +tooltip.main_menu.load_menu.empty_slot = "VAZIO" +tooltip.main_menu.load_menu.load_slot = "JOGO" +tooltip.main_menu.network = "Iniciar um jogo em rede" +tooltip.staff_list.psychiatrist = "Psiquiatra qualificado" +tooltip.staff_list.close = "Fechar gerenciamento de funcionários" +tooltip.staff_list.happiness_2 = "Moral do empregado" +tooltip.staff_list.ability = "Mostra o nível de habilidade destes empregados" +tooltip.staff_list.tiredness_2 = "Cansaço do empregado" +tooltip.staff_list.ability_2 = "Nível de habilidade do empregado" +tooltip.staff_list.salary = "Salário atual pago a esta pessoa" +tooltip.staff_list.researcher_train = "Formado um %d%% para ser Pesquisador" +tooltip.staff_list.happiness = "Mostra o quanto contentes estäo estes empregados" +tooltip.staff_list.sack = "Despedir esta pessoa" +tooltip.staff_list.surgeon = "Cirurgiäo qualificado" +tooltip.staff_list.view_staff = "Ver a pessoa trabalhando" +tooltip.staff_list.surgeon_train = "Formado um %d%% para ser Cirurgiäo" +tooltip.staff_list.tiredness = "Mostra o quanto cansados estäo estes empregados" +tooltip.staff_list.receptionists = "Ver a lista das recepcionistas contratadas neste hospital" +tooltip.staff_list.pay_rise = "Subir o salário desta pessoa em 10%" +tooltip.staff_list.bonus = "Pagar a esta pessoa um bônus de 10%" +tooltip.staff_list.doctor_seniority = "Experiência do médico" +tooltip.staff_list.nurses = "Ver a lista das enfermeiras contratadas neste hospital" +tooltip.staff_list.skills = "Outras qualificaçöes" +tooltip.staff_list.detail = "Cuidar os detalhes" +tooltip.staff_list.doctors = "Ver a lista dos médicos contratados neste hospital" +tooltip.staff_list.handymen = "Ver a lista dos faz-tudo contratados neste hospital" +tooltip.staff_list.researcher = "Pesquisador qualificado" +tooltip.staff_list.psychiatrist_train = "Formado um %d%% para ser Psiquiatra" +tooltip.place_objects_window.confirm = "Confirmar" +tooltip.place_objects_window.buy_sell = "Comprar/vender objetos" +tooltip.place_objects_window.pick_up = "Pegar objeto" +tooltip.place_objects_window.cancel = "Cancelar" +tooltip.casebook.increase = "Aumentar quantidade" +tooltip.casebook.reputation = "Reputaçäo de curas ou diagnósticos" +tooltip.casebook.close = "Fechar ficha clínica" +tooltip.casebook.earned_money = "Ganhos até a data" +tooltip.casebook.decrease = "Reduzir quantidade" +tooltip.casebook.up = "Subir" +tooltip.casebook.research = "Clique aqui para utilizar o orçamento de Pesquisa Especializada para este tratamento" +tooltip.casebook.down = "Baixar" +tooltip.casebook.sent_home = "Número de pacientes dados alta" +tooltip.casebook.cured = "Número de restabelecimentos" +tooltip.casebook.deaths = "Número de falecimentos" +tooltip.casebook.treatment_charge = "Preço" +tooltip.casebook.cure_type.psychiatrist = "Os psiquiatras realizam este tratamento" +tooltip.casebook.cure_type.drug_percentage = "Este tratamento requer um remédio. O seu tem uma eficácia de %d%%" +tooltip.casebook.cure_type.drug = "Este tratamento requer um remédio" +tooltip.casebook.cure_type.machine = "É preciso de uma máquina para este tratamento" +tooltip.casebook.cure_type.surgery = "Esta doença requer cirurgia" +tooltip.casebook.cure_requirement.hire_staff_old = "Você precisa contratar um %s para este tratamento" +tooltip.casebook.cure_requirement.not_possible = "Näo pode administrar este tratamento" +tooltip.casebook.cure_requirement.hire_surgeon = "Você precisa contratar um segundo cirurgiäo para que realize operaçöes" +tooltip.casebook.cure_requirement.build_ward = "Você precisa construir uma enfermaria para administrar este tratamento" +tooltip.casebook.cure_requirement.possible = "Pode administrar este tratamento" +tooltip.casebook.cure_requirement.build_room = "Você precisa construir uma consulta para dar este tratamento" +tooltip.casebook.cure_requirement.hire_surgeons = "Você precisa contratar dois cirurgiöes para as operaçöes" +tooltip.casebook.cure_requirement.research_machine = "Precisa inventar alguma máquina para este tratamento." +tooltip.casebook.cure_requirement.ward_hire_nurse = "Você precisa de uma enfermeira que trabalhe na enfermaria para administrar este tratamento" +tooltip.patient_window.center_view = "Enfocar a pessoa" +tooltip.patient_window.warmth = "Quanto calor tem a pessoa" +tooltip.patient_window.close = "Cancelar caixa de diálogo" +tooltip.patient_window.send_home = "Dar alta à pessoa" +tooltip.patient_window.thirst = "Quanta sede tem a pessoa" +tooltip.patient_window.graph = "Clique para escolher entre o gráfico do estado de saúde da pessoa ou o seu histórico clínico" +tooltip.patient_window.queue = "Ver detalhes da pessoa que faz fila" +tooltip.patient_window.happiness = "Satisfaçäo da pessoa" +tooltip.patient_window.casebook = "Ver detalhes da doença da pessoa" +tooltip.patient_window.abort_diagnosis = "Colocar a pessoa em tratamento em vez de esperar que complete o diagnóstico" +tooltip.town_map.fire_extinguishers = "Alternar extintores" +tooltip.town_map.people = "Alternar pessoas" +tooltip.town_map.balance = "Saldo" +tooltip.town_map.objects = "Alternar objetos" +tooltip.town_map.heat_inc = "Subir aquecimento" +tooltip.town_map.heating_bill = "Recibo de aquecimento" +tooltip.town_map.heat_level = "Nível de aquecimento" +tooltip.town_map.radiators = "Alternar radiadores" +tooltip.town_map.plants = "Alternar plantas" +tooltip.town_map.heat_dec = "Baixar aquecimento" +tooltip.town_map.close = "Fechar mapa da cidade" +tooltip.graphs.cures = "Alternar curas" +tooltip.graphs.reputation = "Alternar o valor do hospital" +tooltip.graphs.close = "Fechar tela de gráficos" +tooltip.graphs.balance = "Alternar saldo" +tooltip.graphs.wages = "Alternar salários" +tooltip.graphs.visitors = "Alternar visitantes" +tooltip.graphs.money_in = "Alternar crédito" +tooltip.graphs.deaths = "Alternar mortes" +tooltip.graphs.scale = "Tabela de gráficos" +tooltip.graphs.money_out = "Alternar gastos" +tooltip.toolbar.policy = "Normas" +tooltip.toolbar.status = "Condiçäo" +tooltip.toolbar.research = "Pesquisa" +tooltip.toolbar.hire = "Contratar funcionários" +tooltip.toolbar.bank_button = "Aperte o botäo esquerdo para o diretor do banco e o direito para o saldo bancário" +tooltip.toolbar.charts = "Gráficos" +tooltip.toolbar.balance = "O seu saldo" +tooltip.toolbar.edit = "Editar salas e objetos" +tooltip.toolbar.date = "A data" +tooltip.toolbar.rooms = "Construir salas" +tooltip.toolbar.staff_list = "Gerenciamento de funcionários" +tooltip.toolbar.town_map = "Mapa da cidade" +tooltip.toolbar.casebook = "Ficha clínica" +tooltip.toolbar.reputation = "A sua reputaçäo" +tooltip.toolbar.objects = "Colocar objetos de corredor" +tooltip.queue_window.patient_dropdown.reception = "Enviar paciente à Recepçäo" +tooltip.queue_window.patient_dropdown.hospital_1 = "Enviar o paciente para outro hospital" +tooltip.queue_window.patient_dropdown.send_home = "Dar alta ao paciente" +tooltip.queue_window.patient_dropdown.hospital_3 = "Enviar o paciente para outro hospital" +tooltip.queue_window.patient_dropdown.hospital_2 = "Enviar o paciente para outro hospital" +tooltip.queue_window.close = "Fecha esta caixa de diálogo" +tooltip.queue_window.num_expected = "Número de pacientes que a recepcionista calcula que logo faräo fila" +tooltip.queue_window.front_of_queue = "Arraste um paciente para este ícone para colocá-lo no início da fila" +tooltip.queue_window.dec_queue_size = "Reduzir o máximo do tamanho da fila" +tooltip.queue_window.num_in_queue = "Número de pacientes em fila" +tooltip.queue_window.num_entered = "Número de pacientes que foram tratados nesta consulta até agora" +tooltip.queue_window.max_queue_size = "Tamanho máximo da fila que permite a recepcionista" +tooltip.queue_window.inc_queue_size = "Aumentar o máximo do tamanho da fila" +tooltip.queue_window.end_of_queue = "Arraste um paciente para este ícone para colocá-lo no final da fila" +tooltip.queue_window.patient = "Arraste um paciente para colocá-lo na fila. Aperte o botäo direito sobre um paciente para mandá-lo para a fila ou para um hospital rival" +tooltip.bank_manager.graph = "Gráfico dos pagamentos esperados de %s" +tooltip.bank_manager.close = "Fechar tela do gerente do banco" +tooltip.bank_manager.balance = "O seu saldo bancário" +tooltip.bank_manager.borrow_5000 = "Pedir $5000 ao banco" +tooltip.bank_manager.hospital_value = "Valor atual do seu hospital" +tooltip.bank_manager.insurance_owed = "Quantidade de dinheiro que lhe deve %s" +tooltip.bank_manager.interest_payment = "Pagamentos dos juros mensais" +tooltip.bank_manager.repay_5000 = "Devolver $5000 ao banco" +tooltip.bank_manager.graph_return = "Voltar para a tela anterior" +tooltip.bank_manager.interest_rate = "Taxa de juro anual" +tooltip.bank_manager.inflation_rate = "Taxa de inflaçäo anual" +tooltip.bank_manager.show_graph = "Mostra o gráfico dos pagamentos esperados de %s" +tooltip.bank_manager.current_loan = "Empréstimos pendentes" +tooltip.jukebox.play = "Ligar máquina de discos" +tooltip.jukebox.stop = "Parar máquina de discos" +tooltip.jukebox.close = "Fechar máquina de discos" +tooltip.jukebox.fast_forward = "Avançar rápido da máquina de discos" +tooltip.jukebox.rewind = "Rebobinar máquina de discos" +tooltip.jukebox.current_title = "Máquina de discos" +tooltip.jukebox.loop = "Funcionamento contínuo da máquina de discos" +tooltip.build_room_window.cost = "Preço da consulta selecionada" +tooltip.build_room_window.room_classes.treatment = "Selecione consultas de clínica geral" +tooltip.build_room_window.room_classes.facilities = "Selecione consultas especiais" +tooltip.build_room_window.room_classes.diagnosis = "Selecione consultas de diagnóstico" +tooltip.build_room_window.room_classes.clinic = "Selecione consultas de especialidade médica" +tooltip.build_room_window.close = "Sair desta caixa de diálogo e voltar para o jogo" +tooltip.hire_staff_window.surgeon = "Cirurgiäo" +tooltip.hire_staff_window.psychiatrist = "Psiquiatra" +tooltip.hire_staff_window.qualifications = "Outras habilidades do médico" +tooltip.hire_staff_window.receptionists = "Ver as recepcionistas que pode contratar" +tooltip.hire_staff_window.hire = "Contratar pessoa" +tooltip.hire_staff_window.nurses = "Ver as enfermeiras que pode contratar" +tooltip.hire_staff_window.doctor_seniority = "Experiência médica (Residente, Médico, Consultor)" +tooltip.hire_staff_window.cancel = "Cancelar" +tooltip.hire_staff_window.researcher = "Pesquisador" +tooltip.hire_staff_window.prev_person = "Ver pessoa anterior" +tooltip.hire_staff_window.salary = "Salário" +tooltip.hire_staff_window.staff_ability = "Qualificaçäo dos funcionários" +tooltip.hire_staff_window.doctors = "Ver os médicos que pode contratar" +tooltip.hire_staff_window.next_person = "Ver pessoa seguinte" +tooltip.hire_staff_window.handymen = "Ver os faz-tudo que pode contratar" +tooltip.handyman_window.center_view = "Enfocar o faz-tudo" +tooltip.handyman_window.close = "Cancelar caixa de diálogo" +tooltip.handyman_window.sack = "Despedir" +tooltip.handyman_window.name = "Nome do faz-tudo" +tooltip.handyman_window.pick_up = "Apanhar" +tooltip.handyman_window.prio_litter = "Aumentar a prioridade do faz-tudo para a limpeza" +tooltip.handyman_window.ability = "Qualificaçäo" +tooltip.handyman_window.prio_machines = "Aumentar a prioridade do faz-tudo para reparar as máquinas" +tooltip.handyman_window.salary = "Salário" +tooltip.handyman_window.face = "Face do faz-tudo" +tooltip.handyman_window.happiness = "Satisfaçäo" +tooltip.handyman_window.tiredness = "Cansaço" +tooltip.handyman_window.prio_plants = "Aumentar a prioridade do faz-tudo para regar as plantas" +tooltip.window_general.cancel = "Cancelar" +tooltip.window_general.confirm = "Confirmar" +adviser.earthquake.ended = "Nossa! Acreditei que ia ser o pior de todos! Alcançou um %d na Escala Richter." +adviser.earthquake.damage = "Por causa do terremoto há %d máquinas danificadas e %d pessoas feridas no hospital." +adviser.earthquake.alert = "Perigo de terremoto! As suas máquinas podem danificar-se durante o terremoto se näo tiverem uma boa manutençäo." +adviser.staff_place_advice.only_psychiatrists = "Os Médicos só podem trabalhar em uma sala de psiquiatria se estiverem qualificados para isso." +adviser.staff_place_advice.doctors_cannot_work_in_room = "Os Médicos näo podem trabalhar em %s" +adviser.staff_place_advice.only_researchers = "Os Médicos só podem trabalhar em um Centro de Pesquisa se estiverem qualificados para isso." +adviser.staff_place_advice.nurses_cannot_work_in_room = "As Enfermeiras näo podem trabalhar em %s" +adviser.staff_place_advice.only_surgeons = "Os Médicos só podem trabalhar em uma sala de operaçöes se estiverem qualificados para isso." +adviser.staff_place_advice.receptionists_only_at_desk = "As Recepcionistas só podem trabalhar na Recepçäo." +adviser.staff_place_advice.only_doctors_in_room = "Apenas Médicos podem trabalhar em %s" +adviser.staff_place_advice.only_nurses_in_room = "Só Enfermeiras podem trabalhar na %s" +adviser.competitors.staff_poached = "Um dos seus funcionários recebeu uma boa oferta de trabalho de um outro hospital." +adviser.competitors.land_purchased = "%s acaba de comprar terrenos." +adviser.competitors.hospital_opened = "%s, da concorrência, abriu um hospital na área." +adviser.epidemic.hurry_up = "Se näo acabar em seguida com esta epidemia, terá muitos problemas. Despacha-se!" +adviser.epidemic.multiple_epidemies = "Parece que tem mais de uma epidemia de uma vez. Isto poderia ser desastroso, sendo assim faz algo rapidamente." +adviser.epidemic.serious_warning = "Esta doença contagiosa começa a ser grave. Tem que fazer algo brevemente!" +adviser.warnings.patients_unhappy = "Os pacientes näo gostam do seu hospital. Deveria fazer algo para melhorá-lo." +adviser.warnings.too_much_litter = "Há um problema de limpeza. Mais faz-tudo é a soluçäo." +adviser.warnings.patients_very_thirsty = "Os pacientes têm muita sede. Se näo colocar logo algumas máquinas de bebidas, as pessoas iräo embora do seu hospital para tomar algum refresco." +adviser.warnings.queue_too_long_at_reception = "Tem muitos pacientes à espera de reservas para as consultas na recepçäo. Coloque outra Recepçäo e contrate outra Recepcionista." +adviser.warnings.patients_thirsty = "As pessoas começam a ter sede. Talvez deveria colocar máquinas de bebidas." +adviser.warnings.nurses_tired = "As suas enfermeiras estäo cansadas. Mande-as descansar agora mesmo." +adviser.warnings.patients_too_hot = "Os pacientes têm muito calor. Retire alguns radiadores, baixa a temperatura ou coloca mais máquinas de bebidas." +adviser.warnings.patients_thirsty2 = "As pessoas queixam-se de que têm sede. Deveria colocar mais máquinas de bebidas ou colocar mais perto as que já há." +adviser.warnings.machines_falling_apart = "Suas máquinas estäo caindo aos pedaços. Chame a manutençäo para que as reparem." +adviser.warnings.financial_trouble3 = "O seu saldo tem um aspecto preocupante. Pensa em fazer algo de efetivo. Está a %d do desastre." +adviser.warnings.nurses_tired2 = "As suas enfermeiras estäo muito cansadas. Faça descansá-las agora mesmo." +adviser.warnings.people_have_to_stand = "Há pacientes de pé. Faça-os sentar já!" +adviser.warnings.handymen_tired = "Os seus faz-tudo estäo muito cansados. Mande-os descansar agora mesmo." +adviser.warnings.change_priorities_to_plants = "Tem que alterar as prioridades dos seus faz-tudo para que empreguem mais tempo regando as suas plantas." +adviser.warnings.staff_tired = "Os seus funcionários estäo incrivelmente cansados. Se näo os deixa descansar um momento em uma Sala de Descanso, alguns poderäo cair de esgotamento." +adviser.warnings.some_litter = "Os faz-tudo podem recolher tudo este lixo antes de que se converta em um grave problema." +adviser.warnings.cash_low_consider_loan = "As suas finanças andam mal. Já pensou em um empréstimo?" +adviser.warnings.reduce_staff_rest_threshold = "Tente alterar o Tempo de Descanso dos funcionários no tela de Normas para que possam descansar mais frequentemente. É só uma sugestäo." +adviser.warnings.build_staffroom = "Construa uma Sala de Descanso o mais rápido possível. Os seus funcionários trabalham muito e estäo à beira do colapso. Vamos, seja razoável!" +adviser.warnings.many_epidemics = "Parece que tem mais de uma epidemia de uma vez. Isto poderia ser desastroso, sendo assim faz algo rapidamente." +adviser.warnings.build_toilets = "Construa um banheiro agora mesmo ou verá algo muito desagradável. E pode imaginar como cheirará o seu hospital." +adviser.warnings.staff_overworked = "Os seus empregados têm muito trabalho. Estäo perdendo eficácia e väo começar a cometer erros desastrosos." +adviser.warnings.doctors_tired2 = "Os seus médicos estäo cansadíssimos. Precisam descansar imediatamente." +adviser.warnings.queues_too_long = "Tem muitos pacientes fazendo fila." +adviser.warnings.staff_unhappy = "Os seus funcionários estäo descontentes. Dê-lhes um pagamento extra ou, ainda melhor, construa uma Sala de Descanso para eles. Também poderia alterar o seu tempo de descanso na tela de Normas." +adviser.warnings.patient_leaving = "Há um paciente que parte. A causa? A má direçäo e a péssima qualidade dos seus funcionários e seus equipamentos." +adviser.warnings.patient_stuck = "Alguém ficou bloqueado. Planeje melhor seu hospital." +adviser.warnings.receptionists_tired = "As suas recepcionistas estäo extenuadas. Mande-as descansar agora mesmo." +adviser.warnings.charges_too_low = "Cobra muito pouco. Terá pacientes no seu hospital, mas näo lhe contribuiräo com muitos ganhos." +adviser.warnings.epidemic_getting_serious = "Esta doença contagiosa começa a ser grave. Tem que fazer algo brevemente!" +adviser.warnings.patients_really_thirsty = "Os pacientes têm muita sede. Coloque mais máquinas de bebidas ou aproxime as existentes às filas mais compridas." +adviser.warnings.patients_annoyed = "As pessoas estäo enormemente desagradadas pelo modo que dirige o seu hospital. E näo pode dizer que näo tenham culpa. Solucione o problema ou confronte as consequências!" +adviser.warnings.place_plants3 = "Os pacientes estäo descontentes. Coloque mais plantas para animá-los." +adviser.warnings.machinery_deteriorating = "As suas máquinas começam a se deteriorar por uso excessivo. Vigie-as." +adviser.warnings.place_plants4 = "Alegra aos pacientes colocando mais plantas." +adviser.warnings.money_very_low_take_loan = "O seu saldo bancário é muito baixo. Poderia pedir um empréstimo." +adviser.warnings.finanical_trouble2 = "Consiga algum crédito ou estará acabado. Perderá o nível se perder outros %d." +adviser.warnings.patients_very_cold = "Os pacientes têm muito frio. Suba o aquecimento ou coloque mais radiadores no seu hospital." +adviser.warnings.deal_with_epidemic_now = "Se näo acabar em seguida com esta epidemia, terá muitos problemas. Despacha-se!" +adviser.warnings.litter_catastrophy = "O problema da falta de limpeza é grave. Ponha a trabalhar agora mesmo uns quantos faz-tudo!" +adviser.warnings.litter_everywhere = "Há sujidade por toda parte. Ponha mais faz-tudo a trabalhar." +adviser.warnings.machinery_slightly_damaged = "A maquinaria do seu hospital está um pouco danificada. Näo se esqueça de as reparar." +adviser.warnings.patients_getting_hot = "Os pacientes têm muito calor. Baixe o aquecimento ou retire alguns radiadores." +adviser.warnings.no_patients_last_month = "No último mês, näo vieram novos pacientes ao seu hospital. Horrível!" +adviser.warnings.many_killed = "Matou %d pacientes. Acho que tem que conseguir melhor, näo?" +adviser.warnings.build_toilet_now = "Construa já uns banheiros. As pessoas näo aguentam mais. Näo se ria, é grave." +adviser.warnings.people_freezing = "Que horrível! Nesta era de aquecimento central, alguns dos seus pacientes estäo se congelando. Coloque radiadores para que sejam aquecidos e suba o aquecimento." +adviser.warnings.place_plants_to_keep_people = "As pessoas estäo indo embora. Se colocasse mais planta poderia convencê-los a ficar." +adviser.warnings.patients_leaving = "Os pacientes partem. Melhora o seu hospital colocando plantas, bancos, máquinas de bebidas, etc., para os seus visitantes." +adviser.warnings.doctors_tired = "Os seus médicos estäo esgotados. Mande-os descansar agora mesmo." +adviser.warnings.charges_too_high = "Os seus preços säo muito altos. Terá grandes benefícios a curto prazo, mas à longo ficará sem pacientes." +adviser.warnings.financial_trouble = "Tem sérios problemas financeiros. Arranja a sua financia já! Se perder outros %d, terá arruinado este nível!" +adviser.warnings.reception_bottleneck = "Há um gargalo na Recepçäo. Contrate outra Recepcionista." +adviser.warnings.pay_back_loan = "Tem dinheiro de sobra. Por que você näo liquida o seu empréstimo?" +adviser.warnings.nobody_cured_last_month = "No mês passado, näo houve nenhuma cura." +adviser.warnings.queue_too_long_send_doctor = "As filas de %s säo muito longas. Certifique-se de que há um Médico na sala." +adviser.warnings.staff_too_hot = "Os seus empregados têm muito calor. Baixe a temperatura ou retire alguns radiadores das suas consultas." +adviser.warnings.place_plants2 = "Os pacientes estäo indo. Com mais planta poderia conseguir que ficassem mais tempo." +adviser.warnings.doctor_crazy_overwork = "Oh, näo! Um dos seus médicos ficou louco pelo excesso de trabalho. Irá se recuperar se descansar agora mesmo." +adviser.warnings.machinery_damaged = "Repare, o mais brevemente possível, as suas máquinas. Näo falta muito para que comecem a cair aos a pedaços." +adviser.warnings.more_benches = "Poderia colocar mais bancos. Os doentes protestam por terem que estar de pé." +adviser.warnings.bankruptcy_imminent = "Ei! Vai ficar sem máquinas. Tome cuidado!" +adviser.warnings.need_toilets = "Os pacientes precisam de casas de banho. Coloca-as em um lugar acessível." +adviser.warnings.more_toilets = "Você precisa de mais banheiros. As pessoas näo aguentam mais." +adviser.warnings.plants_dying = "As suas plantas estäo secando. Precisam de água. Consiga mais faz-tudo para que cuidem disso. Os pacientes näo gostam das plantas mortas." +adviser.warnings.people_did_it_on_the_floor = "Alguns dos seus pacientes näo podem aguentar mais. Alguém vai ter que limpar sem descanso." +adviser.warnings.need_staffroom = "Construa uma sala de descanso para que os seus empregados possam descansar." +adviser.warnings.plants_thirsty = "Precisa cuidar das suas plantas. Estäo secando." +adviser.warnings.too_many_plants = "Tem muitas plantas. Isto parece uma selva." +adviser.warnings.receptionists_tired2 = "As suas recepcionistas estäo esgotadas. Deixa que descansem agora mesmo." +adviser.warnings.machine_severely_damaged = "%s está prestes a se quebrar." +adviser.warnings.machinery_very_damaged = "É uma emergência! Faça com que que um faz-tudo repare as sas máquinas em seguida. Estäo a ponto de explodir!" +adviser.warnings.hospital_is_rubbish = "As pessoas näo têm dúvidas em dizer que o seu hospital é uma porcaria. Já sabe que logo iräo queixar-se a outra parte." +adviser.warnings.handymen_tired2 = "Os seus faz-tudo estäo destroçados. Mande-os descansar imediatamente." +adviser.warnings.machinery_damaged2 = "Precisa contratar um faz-tudo para reparar as suas máquinas rapidamente." +adviser.warnings.staff_very_cold = "O pessoal reclama do frio. Suba o aquecimento ou coloque mais radiadores." +adviser.warnings.desperate_need_for_watering = "Necessita desesperadamente contratar um faz-tudo para que cuide das suas plantas." +adviser.warnings.staff_unhappy2 = "Os seus funcionários, no geral, estäo descontentes. Logo, pediräo mais dinheiro." +adviser.staff_advice.too_many_nurses = "Está contratando muitas enfermeiras." +adviser.staff_advice.need_handyman_litter = "Os pacientes estäo sujando o seu hospital. Contrate uma faz-tudo para se encarregar da limpeza." +adviser.staff_advice.need_nurses = "Contrate mais enfermeiras. Na enfermaria e na farmácia faltam enfermeiras." +adviser.staff_advice.need_doctors = "Você precisa de mais médicos. Tente colocar os seus melhores médicos nas consultas com mais pacientes." +adviser.staff_advice.too_many_doctors = "Tem muitos médicos. Alguns estäo desocupados neste momento." +adviser.staff_advice.need_handyman_machines = "Terá que contratar um faz-tudo se quiser que as máquinas do seu hospital funcionem." +adviser.staff_advice.need_handyman_plants = "Contrate um faz-tudo para regar as plantas." +adviser.praise.few_have_to_stand = "Quase ninguém fica de pé no seu hospital. Os seus pacientes estäo contentes." +adviser.praise.patients_cured = "%d pacientes curados." +adviser.praise.plants_are_well = "Muito bem. Está cuidando bem das suas plantas. Estupendo." +adviser.praise.plenty_of_benches = "Há muitos assentos, assim näo há problema." +adviser.praise.plants_thriving = "Muito bem. As suas plantas estäo muito viçosas. Têm um aspecto maravilhoso. Mantenha-as assim e poderá ganhar um prêmio por isto." +adviser.praise.many_benches = "Agora os seus pacientes têm suficientes assentos. Muito bem!" +adviser.praise.many_plants = "Fantástico! Tem muitas plantas. Os seus pacientes agradeceräo isso." +adviser.surgery_requirements.need_surgeons_ward_op = "Precisa contratar dois cirurgiöes e construir uma enfermaria e uma sala de operaçöes para realizar operaçöes." +adviser.surgery_requirements.need_surgeon_ward = "Precisa contratar um outro cirurgiäo e construir uma enfermaria para poder realizar operaçöes." +adviser.multiplayer.objective_completed = "Completou o objetivo. Felicidades!" +adviser.multiplayer.objective_failed = "Näo conseguiu completar o objetivo." +adviser.multiplayer.everyone_failed = "Todos falharam ao satisfazer aquele último objetivo." +adviser.multiplayer.players_failed = "O(s) seguinte jogador(es) falharam ao alcançar o último objetivo: " +adviser.multiplayer.poaching.not_interested = "Ha! Näo lhes interessa trabalhar para si. Estäo contentes onde estäo." +adviser.multiplayer.poaching.already_poached_by_someone = "Nem pensar! Alguém trate de pescar essa pessoa!" +adviser.multiplayer.poaching.in_progress = "Eu o informarei se esta pessoa deseja trabalhar pra você." +adviser.research.new_drug_researched = "Um novo medicamento para curar %s foi descoberto." +adviser.research.new_machine_researched = "Pesquisou com êxito %s." +adviser.research.drug_fully_researched = "Pesquisou 100%% %s." +adviser.research.drug_improved = "O seu Centro de Pesquisa melhorou o medicamento para %s." +adviser.research.new_available = "Já pode utilizar um novo %s." +adviser.research.machine_improved = "O Centro de Pesquisa trouxe melhorias para %s." +adviser.research.autopsy_discovered_rep_loss = "Foi descoberta uma máquina de autópsias. Aguarde uma reaçäo desfavorável das pessoas." +adviser.information.emergency = "Há uma emergência! Mexa-se! Mexa-se! Mexa-se!" +adviser.information.handyman_adjust = "Pode conseguir que o faz-tudo limpe melhor se estabelecer as suas prioridades." +adviser.information.promotion_to_specialist = "Um dos seus Médicos foi promovido para %s." +adviser.information.pay_rise = "Um funcionário ameaça se demitir. Pode atender a sua petiçäo ou despedi-lo. Clique no último ícone da esquerda para ver quem deseja demitir." +adviser.information.first_death = "Acabou de matar o seu primeiro paciente. Como se sente?" +adviser.information.fax_received = "O ícone que acaba de aparecer no canto inferior esquerdo do tela alerta-lhe sobre uma informaçäo importante ou de que tem que tomar uma decisäo." +adviser.information.promotion_to_consultant = "Um dos seus MEDICOS converteu-se em CONSULTOR." +adviser.information.patient_abducted = "Os alienígenas raptaram um dos seus pacientes." +adviser.information.vip_arrived = "Cuidado! %s acaba de chegar para visitar o seu hospital! Faça com que tudo funcione bem para lhe agradar." +adviser.information.extra_items = "Os funcionários ficam mais confortáveis e melhoram o seu rendimento se colocar objetos complementares nas salas." +adviser.information.epidemic_health_inspector = "O Ministério da Saúde soube de que tem uma epidemia. Prepare-se para receber brevemente a visita de um Inspetor de Saúde." +adviser.information.first_cure = "Muito bem! Acaba de curar o seu primeiro paciente." +adviser.information.epidemic = "Há uma doença contagiosa no seu hospital. Tem que solucioná-la em seguida!" +adviser.information.patient_leaving_too_expensive = "Um paciente está indo embora sem pagar %s. É muito dinheiro." +adviser.information.place_windows = "Se colocar janelas, as salas teräo mais luz e os seus empregados estaräo mais contentes." +adviser.information.initial_general_advice.first_patients_thirsty = "No seu hospital as pessoas têm sede. Coloque máquinas de bebidas." +adviser.information.initial_general_advice.epidemic_spreading = "Há uma doença contagiosa no seu hospital. Tente curar as pessoas infectadas antes que elas possam ir embora." +adviser.information.initial_general_advice.research_now_available = "Construiu o seu primeiro centro de pesquisa. Agora pode acessar a tela de pesquisa." +adviser.information.initial_general_advice.autopsy_available = "Foi inventada uma máquina de autópsias. Com ela, poderá se livrar dos pacientes problemáticos e investigar os seus restos. Tome cuidado, o uso desta máquina suscita muita polêmica." +adviser.information.initial_general_advice.rats_have_arrived = "Os ratos invadiram o seu hospital. Tente eliminá-los com o mouse." +adviser.information.initial_general_advice.surgeon_symbol = "Os médicos especializados em cirurgia levam o símbolo: {" +adviser.information.initial_general_advice.machine_needs_repair = "Há uma máquina que precisa ser reparada. Encontre a máquina e aperte sobre ela. Em seguida, aperte no botäo do faz-tudo." +adviser.information.initial_general_advice.research_symbol = "Os médicos pesquisadores levam o símbolo: }" +adviser.information.initial_general_advice.decrease_heating = "As pessoas têm muito calor no seu hospital. Baixe o aquecimento. Isto é feito na tela de mapa da cidade." +adviser.information.initial_general_advice.taking_your_staff = "Alguém está subornando a sua equipe. Terá que discutir com eles para que fiquem." +adviser.information.initial_general_advice.first_VIP = "Vai receber o seu primeiro visitante VIP. Assegure-se de que o VIP näo veja nada sujo nem nenhum paciente descontente." +adviser.information.initial_general_advice.increase_heating = "As pessoas têm frio. Ligue o aquecimento na tela de mapa da cidade." +adviser.information.initial_general_advice.psychiatric_symbol = "Os médicos especializados em psiquiatria levam o símbolo: |" +adviser.information.initial_general_advice.first_epidemic = "Há uma epidemia no seu hospital! Decida se quer tratá-la ou liberar ela." +adviser.information.initial_general_advice.place_radiators = "As pessoas têm frio no seu hospital. Pode colocar mais radiadores selecionando-os no menu de mobiliário do corredor." +adviser.information.initial_general_advice.first_emergency = "Os pacientes de emergência têm uma luz azul que pisca sobre a sua cabeça. Cure eles antes de que morram ou de que o tempo limite se esgote." +adviser.information.promotion_to_doctor = "Um dos seus RESIDENTES converteu-se em um MEDICO." +adviser.information.larger_rooms = "Se fizer salas espaçosas, os seus funcionários se sentiräo mais importantes e melhoraräo o seu rendimento." +adviser.goals.win.value = "AUMENTE O VALOR DO SEU HOSPITAL EM %d" +adviser.goals.win.reputation = "AUMENTE A SUA REPUTAÇAO EM %d PARA SATISFAZER O NIVEL DO CRITÉRIO PARA GANHAR" +adviser.goals.win.cure = "Cure mais %d paciente(s) e terá curado os suficientes para ganhar este nível." +adviser.goals.win.money = "Você precisa de outros %d para alcançar o critério financeiro deste nível." +adviser.build_advice.door_not_reachable = "As pessoas näo poderäo passar por essa porta. Pense sobre isto." +adviser.build_advice.blueprint_would_block = "Essa marca azul tapará outras consultas. Tente alterar o tamanho ou coloque em outro local!" +adviser.build_advice.placing_object_blocks_door = "Se colocar este objeto aí, impedirá que se possa acessar alguma porta." +adviser.build_advice.blueprint_invalid = "Esta marca azul näo é válida." +adviser.level_progress.three_quarters_won = "Falta 75%% para superar este nível." +adviser.level_progress.reputation_good_enough = "De acordo, a sua reputaçäo é muito boa para ganhar este nível, mantenha acima de %d e resolva outros problemas para terminar." +adviser.level_progress.nearly_won = "Falta muito pouco para superar este nível." +adviser.level_progress.hospital_value_enough = "Mantenha o valor do seu hospital acima de %d e atenda os seus outros problemas para ganhar o nível." +adviser.level_progress.improve_reputation = "Você precisa melhorar a sua reputaçäo em %d para ter uma oportunidade de ganhar o nível." +adviser.level_progress.halfway_won = "Falta 50%% para superar este nível." +adviser.level_progress.close_to_win_increase_value = "Está próximo da vitória. Aumente o valor do seu hospital em $%d." +adviser.level_progress.another_patient_cured = "Muito bem! Outro paciente curado. Isto faz um total de %d curados." +adviser.level_progress.nearly_lost = "Falta muito pouco para perder este nível." +adviser.level_progress.three_quarters_lost = "Falta 75%% para perder este nível." +adviser.level_progress.dont_kill_more_patients = "Näo pode permitir deixar que morram mais pacientes!" +adviser.level_progress.cured_enough_patients = "Curou muitos pacientes, mas precisa manter o seu hospital em melhor estado para ganhar o nível." +adviser.level_progress.financial_criteria_met = "Tem satisfeito o critério financeiro deste nível. Agora mantenha o seu saldo acima de %d, enquanto assegura de que o hospital funcione eficazmente." +adviser.level_progress.halfway_lost = "Falta 50%% para perder este nível." +adviser.level_progress.another_patient_killed = "Oh, näo! Matou outro paciente. Agora há um total de %d mortes." +adviser.vomit_wave.started = "Parece que tem um vírus de vômitos no seu hospital. Isto näo teria acontecido se o tivesse mantido limpo. Talvez devesse contratar um faz-tudo." +adviser.vomit_wave.ended = "Ufa! Parece que o vírus que causou essa epidemia de vômitos está controlado. No futuro, mantenha o seu hospital limpo." +adviser.placement_info.staff_cannot_place = "Näo pode colocar este funcionário aqui. Desculpe." +adviser.placement_info.room_cannot_place_2 = "Näo pode colocar a consulta aqui." +adviser.placement_info.object_cannot_place = "Eh! Näo pode colocar aqui este objeto." +adviser.placement_info.object_can_place = "Pode colocar este objeto aqui." +adviser.placement_info.door_can_place = "Se quiser, pode colocar a porta aqui." +adviser.placement_info.reception_cannot_place = "Näo pode colocar a Recepçäo aqui." +adviser.placement_info.door_cannot_place = "Desculpe, mas näo pode colocar aqui a porta." +adviser.placement_info.window_cannot_place = "Ah! Näo pode colocar a janela aqui." +adviser.placement_info.staff_can_place = "Pode colocar este funcionário aqui." +adviser.placement_info.window_can_place = "Pode colocar a janela aqui. Está bem." +adviser.placement_info.reception_can_place = "Näo pode colocar aqui a Recepçäo." +adviser.placement_info.room_cannot_place = "Näo pode colocar aqui a consulta." +adviser.boiler_issue.maximum_heat = "A caldeira do poräo ficou danificada. Os radiadores estäo no máximo. As pessoas väo derreter! Seria bom que colocasse mais máquinas de bebidas." +adviser.boiler_issue.minimum_heat = "Ah, aí está! A caldeira do poräo ficou danificada. Parece que dentro de pouco tempo as pessoas väo congelar no seu hospital!" +adviser.boiler_issue.resolved = "Boas notícias. A caldeira e os radiadores voltaram a funcionar corretamente. Os seus pacientes e os seus funcionários desfrutaräo de uma boa temperatura." +adviser.tutorial.build_reception = "Você precisa de uma Recepçäo no seu hospital. Escolha uma do menu de mobiliário do corredor." +adviser.tutorial.click_and_drag_to_build = "Aperte o botäo esquerdo e arraste para desenhar a sala." +adviser.tutorial.window_in_invalid_position = "Esta janela está mal colocada. Tente colocá-la em outro lugar da parede." +adviser.tutorial.room_in_invalid_position = "Esta marca azul näo é válida. As áreas vermelhas assinalam onde ocupou parte de outro quarto ou das paredes do hospital." +adviser.tutorial.choose_receptionist = "Clique no ícone que pisca para contratar a recepcionista que escolheu." +adviser.tutorial.place_doctor = "Coloque o médico na consulta." +adviser.tutorial.build_gps_office = "É imprescindível um médico para diagnosticar os doentes." +adviser.tutorial.select_doctors = "Clique no ícone que pisca para ver os médicos que pode contratar." +adviser.tutorial.click_gps_office = "Clique na linha que pisca para escolher o Consultório Geral." +adviser.tutorial.prev_receptionist = "Clique no ícone que pisca para ver a recepcionista disponível anterior." +adviser.tutorial.information_window = "A funçäo de ajuda proporciona toda a informaçäo sobre a consulta que acaba de construir." +adviser.tutorial.place_receptionist = "Mova a recepcionista e coloque-a no seu lugar." +adviser.tutorial.confirm_room = "Clique no ícone que pisca para abrir a consulta ou cancelar para voltar para passo anterior." +adviser.tutorial.doctor_in_invalid_position = "Näo pode colocar o médico aqui." +adviser.tutorial.place_objects = "Aperte o botäo esquerdo para colocar os objetos, e o direito para fazê-los girar." +adviser.tutorial.hire_receptionist = "Agora você precisa de uma recepcionista para atender os seus pacientes." +adviser.tutorial.hire_doctor = "Você precisa de um médico para diagnosticar e atender os seus pacientes." +adviser.tutorial.room_too_small_and_invalid = "A marca azul é muito pequena e está mal colocada." +adviser.tutorial.receptionist_invalid_position = "Näo pode colocar a sua recepcionista aqui." +adviser.tutorial.door_in_invalid_position = "Tentou colocar a porta em um lugar incorreto. Tente em outro lugar da grade azul." +adviser.tutorial.next_receptionist = "Clique no ícone que pisca para ver a seguinte recepcionista disponível." +adviser.tutorial.object_in_invalid_position = "Este objeto está mal colocado. Por favor, coloque em outro lugar ou tente girar." +adviser.tutorial.choose_doctor = "Veja as habilidades de cada médico antes de escolher um." +adviser.tutorial.rotate_and_place_reception = "Coloque a Recepçäo e aperte o botäo direito do mouse para girá-la." +adviser.tutorial.accept_purchase = "Clique com o botäo esquerdo no ícone que pisca para colocá-lo." +adviser.tutorial.room_too_small = "A marca azul desta sala é muito pequena. Arraste-a ou aumente o seu tamanho." +adviser.tutorial.room_big_enough = "A marca azul é agora suficientemente grande. Se quiser, pode movê-la ou colocá-la." +adviser.tutorial.start_tutorial = "Leia as instruçöes. Quando terminar, aperte o botäo esquerdo do mouse para começar o tutorial." +adviser.tutorial.place_door = "Mova o mouse ao redor das paredes marcadas de azul para colocar a porta." +adviser.tutorial.select_receptionists = "Clique no ícone que pisca para ver as recepcionistas que estäo disponíveis." +adviser.tutorial.order_one_reception = "Clique na linha que pisca com o botäo esquerdo do mouse para comprar uma Recepçäo." +adviser.tutorial.place_windows = "Coloque as janelas da mesma forma que a porta. Se näo quiser janelas, näo tem que as colocar." +adviser.tutorial.select_diagnosis_rooms = "Clique com o botäo esquerdo no ícone que pisca para ver a lista de salas de diagnóstico." +adviser.tutorial.reception_invalid_position = "A Recepçäo ficou cinzenta porque näo é possível colocar a¡. Mover ou girá-la." +adviser.tutorial.build_pharmacy = "Parabéns! Agora, construa uma farmácia e contrate uma enfermeira para fazer o seu hospital funcionar." +adviser.room_requirements.pharmacy_need_nurse = "Contrate uma enfermeira para a Farmácia." +adviser.room_requirements.op_need_two_surgeons = "Contrate dois cirurgiöes para que operem na sala de operaçöes." +adviser.room_requirements.training_room_need_consultant = "Terá que contratar um especialista para que de conferências nesta sala de formaçäo." +adviser.room_requirements.research_room_need_researcher = "Terá que contratar um médico pesquisador para que utilize o centro de pesquisa." +adviser.room_requirements.op_need_ward = "Precisa construir uma enfermaria para os pacientes que väo ser operados." +adviser.room_requirements.reception_need_receptionist = "Precisa contratar uma recepcionista para atender os seus pacientes." +adviser.room_requirements.op_need_another_surgeon = "Precisa contratar um outro cirurgiäo para poder usar o sala de operaçöes." +adviser.room_requirements.gps_office_need_doctor = "Contrate um médico para atender no consultório." +adviser.room_requirements.ward_need_nurse = "Contrate uma enfermeira para que trabalhe na enfermaria." +adviser.room_requirements.psychiatry_need_psychiatrist = "Agora que construiu uma sala de psiquiatria, precisará de um psiquiatra." +introduction_texts.level15 = "Bem, estes säo os mecanismos básicos para pôr em funcionamento um hospital.//Os seus Médicos väo precisar de toda a ajuda que possam obter para diagnosticar alguns dos pacientes. Pode ajudá-los construindo outros equipamentos de diagnóstico como a sala de Diagnóstico Geral." +introduction_texts.level6 = "Utilize toda a sua capacidade para conseguir um hospital que funcione bem e consiga curar muitos pacientes e que possa tratar qualquer caso que pressentem os doentes.//Está avisado de que o ambiente, aqui, é especialmente propenso a germes e infecçöes. A menos que mantenha uma escrupulosa limpeza na sua instituiçäo, terá que fazer frente a uma série de epidemias entre os pacientes. Procure obter um lucro de $20.000 e fazer o valor do seu hospital superar os $140.000. " +introduction_texts.level3 = "Desta vez colocará o seu hospital em uma área rica.//O Ministério da Saúde espera que consiga curar muitos pacientes. Terá que ganhar uma boa reputaçäo para começar, mas uma vez que o hospital comece a funcionar, concentre-se em ganhar todo o dinheiro que puder. Também pode haver emergências. Produzem-se quando chega muita gente que sofre da mesma doença. Se os curar dentro de um prazo determinado, conseguirá aumentar a sua reputaçäo e ganhar um grande extra. Haverá doenças, como o complexo de rei, e deverá ter orçamento para construir uma sala de operaçöes e junto a ela, uma enfermaria. Tem que ganhar $20.000 para superar este nível." +introduction_texts.level12 = "Agora enfrentará o maior dos desafios. Impressionado com os seus lucros, o Ministério tem uma grande tarefa para você; querem que construa outro magnífico hospital, que tenha um excelente lucro e uma reputaçäo incrível. Também querem que compre todo o terreno que puder, cure tudo (e queremos dizer todas as doenças) e ganhe todos os prêmios. Acha que conseguirá? Ganhe $650.000, cure 750 pessoas e consiga uma reputaçäo de 800 para ganhar este nível. " +introduction_texts.level9 = "Depois de depositar o dinheiro na conta bancária do Ministério e pagar uma nova limousine para o Ministro, agora pode dedicar a criar um bom hospital para cuidar dos doentes e necessitados. Aqui terá um montäo de problemas diferentes. Se os seus funcionários tiverem uma boa formaçäo e suficientes consultas, poderäo resolver qualquer situaçäo. O seu hospital terá que valer $200.000 e precisará ter $400.000 no banco. Se näo o conseguir näo poderá terminar o nível." +introduction_texts.level11 = "Tem a oportunidade de construir o hospital definitivo. Esta é uma área de enorme prestígio e o Ministério quer que este seja o melhor hospital. Esperamos que ganhe muito dinheiro, alcance uma excelente reputaçäo e que se encarregue de todos os casos que sejam apresentados. Este é um trabalho importante. Terá que ser muito hábil para completá-lo. Também deve ter em conta que foram vistos OVNIs na área. Assegure-se de que os seus funcionários estejam preparados para receber algumas visitas inesperadas. O seu hospital terá que alcançar um valor de $240.000, precisará ter $500.000 no banco e uma reputaçäo de 700." +introduction_texts.level14 = "Ainda tem mais um desafio: um hospital surpresa totalmente imprevisível. Se conseguir ter êxito, será o vencedor dos vencedores. E näo espere que seja fácil, porque é a tarefa mais difícil que confrontará. Boa sorte!" +introduction_texts.level10 = "Além de dever curar todas as doenças que possa haver, o Ministério pede que empregue um pouco de tempo em aumentar a eficácia dos seus remédios.//Houve algumas queixas por parte do D. Salutíssimo, o Cachorro Guardiäo da Saúde, assim deve procurar com que todos os seus remédios sejam extremamente eficazes para ficar bem. Também, assegure-se de que o seu hospital tenha uma reputaçäo irrepreensível. Procure deixar morrer poucos pacientes. Como sugestäo, deveria deixar espaço para um banho gelatinoso. Para ganhar, os seus remédios deveräo ter uma eficácia de, pelo menos, 80%, tem que conseguir uma reputaçäo de 650 e guardar $500.000 no banco." +introduction_texts.level5 = "Este será um hospital concorrido, que tratará casos muito variados.//Os seus médicos acabam de sair da faculdade, por isso é fundamental que construa uma sala de formaçäo para que alcancem o nível de formaçäo necessário. Só tem três especialistas para ensinar os seus funcionários inexperientes, entäo faça com que estejam contentes. Tem que ter em conta que o hospital está localizado em cima da falha geológica de San Android. Sempre há risco de terremoto. Os terremotos provocaräo danos importantes nas suas máquinas e alteraräo o bom funcionamento do seu hospital. Aumente a sua reputaçäo até 400 e consiga ganhos de $50.000 para triunfar. Também, cure 200 pacientes. " +introduction_texts.level1 = "Bem-vindo ao seu primeiro hospital!//Para fazê-lo funcionar, coloque uma Recepçäo, construa um Consultório e contrate uma recepcionista e um médico. Em seguida, espere que cheguem os pacientes. Seria uma boa ideia construir uma consulta de psiquiatria e contratar um psiquiatra. Uma farmácia e uma enfermeira säo fundamentais para curar os seus pacientes. Cuidado com os casos malignos de cabeça inflada; eles säo solucionados na sala de inflatoterapia. Terá que curar 10 pessoas e assegurar de que a sua reputaçäo näo seja inferior a 200." +introduction_texts.level17 = "Um último aviso. Fique de olho na sua Reputaçäo, é o que atrairá pacientes ao seu estabelecimento. Se näo matar muitas pessoas e os mantiver razoavelmente felizes näo deverá ter muitos problemas com este nível!//Agora é com você, boa sorte." +introduction_texts.level7 = "Aqui, estará sob a estrita vigilância do Ministério da Saúde, entäo faça com que suas contas reflitam excelentes lucros e aumente a sua reputaçäo.//Näo podemos permitir que haja mortes desnecessárias; Näo beneficiam nada o negócio. Certifique-se de que os seus funcionários estejam em plena forma e de ter todos os equipamentos necessários. Obtenha uma reputaçäo de 600, e um saldo bancário de $200.000." +introduction_texts.level4 = "Faça com que todos os seus pacientes estejam contentes, trate-os com a maior eficácia e tente deixar que morram o menos possíveis.//A sua reputaçäo está em jogo, entäo procure aumentá-la o máximo que puder. Näo se preocupe muito com o dinheiro; Irá ganhando à medida que cresce a sua reputaçäo. Também poderá formar os seus médicos para ampliar os seus conhecimentos. Eles poderäo curar os pacientes mais difíceis. Alcance uma reputaçäo acima de 500." +introduction_texts.level18 = "" +introduction_texts.level16 = "Uma vez que tenha diagnosticado algum dos pacientes, precisará construir salas de tratamento e clínicas para curá-los. Pode começar com uma Farmácia, onde precisará de uma Enfermeira que distribua os remédios." +introduction_texts.level13 = "A sua incrível habilidade como diretor do hospital atraiu a atençäo da Divisäo Secreta Especial do Serviço Secreto Especial. Tenho um trabalho especial para você. Há um hospital infestado de ratos que precisa de um exterminador eficiente. Você deve matar todos os ratos que puder antes de que o pessoal de Manutençäo limpe toda a sujeira. Acha que é apto para esta missäo?" +introduction_texts.level8 = "Só depende de você construir o hospital mais rentável e eficiente possível.//As pessoas por aqui, säo bastante ricas, entäo tente arrecadar o máximo possível. Lembre-se que curar as pessoas é uma coisa muito bonita, mas o que PRECISAMOS de verdade é do dinheiro delas. Arranque todo o dinheiro destes doentes. Acumule a enorme quantia de $300.000 para completar este nível. " +humanoid_name_starts[1] = "GOLD" +humanoid_name_starts[2] = "HIGH" +humanoid_name_starts[3] = "AND" +humanoid_name_starts[4] = "BEN" +humanoid_name_starts[5] = "BAN" +humanoid_name_starts[6] = "BILL" +humanoid_name_starts[7] = "WY" +humanoid_name_starts[8] = "WAT" +humanoid_name_starts[9] = "POD" +humanoid_name_starts[10] = "KING" +humanoid_name_starts[11] = "BAR" +humanoid_name_starts[12] = "PET" +humanoid_name_starts[13] = "MAN" +humanoid_name_starts[14] = "BOY" +humanoid_name_starts[15] = "WAR" +humanoid_name_starts[16] = "JACK" +humanoid_name_starts[17] = "CRAB" +humanoid_name_starts[18] = "FISH" +humanoid_name_starts[19] = "WATER" +humanoid_name_starts[20] = "MIL" +humanoid_name_starts[21] = "BY" +humanoid_name_starts[22] = "FEN" +humanoid_name_starts[23] = "RICH" +humanoid_name_starts[24] = "SCOT" +humanoid_name_starts[25] = "BUR" +humanoid_name_starts[26] = "PIKE" +humanoid_name_starts[27] = "CUR" +humanoid_name_starts[28] = "WHIT" +humanoid_name_starts[29] = "BINN" +humanoid_name_starts[30] = "BONN" +humanoid_name_starts[31] = "POG" +humanoid_name_starts[32] = "WRIGHT" +humanoid_name_starts[33] = "KER" +policy.diag_procedure = "Procedimento de diagnóstico" +policy.header = "NORMAS DO HOSPITAL" +policy.staff_leave_rooms = "Abandonar as consultas" +policy.staff_rest = "Enviar os funcionários para descansar" +policy.diag_termination = "Conclusäo do diagnóstico" +policy.sliders.send_home = "ENVIA PARA CASA" +policy.sliders.guess = "TENTAR CURA" +policy.sliders.stop = "PARAR PROCESSO" +policy.sliders.staff_room = "IR DESCANSAR" +menu_display.mcga_lo_res = " BAIXA RESOLUÇAO MCGA " +menu_display.shadows = " SOMBRAS " +menu_display.high_res = " ALTA RESOLUÇAO " +staff_title.surgeon = "Cirurgiäo" +staff_title.psychiatrist = "Psiquiatra" +staff_title.general = "Geral" +staff_title.junior = "Residente" +staff_title.researcher = "Pesquisador" +staff_title.consultant = "Consultor" +staff_title.nurse = "Enfermeira" +staff_title.doctor = "Médico" +staff_title.receptionist = "Recepcionista" +bank_manager.insurance_owed = "Dívida do seguro" +bank_manager.interest_rate = "Juros" +bank_manager.interest_payment = "Pagamento de juros" +bank_manager.statistics_page.date = "Data" +bank_manager.statistics_page.money_out = "Débito" +bank_manager.statistics_page.money_in = "Crédito" +bank_manager.statistics_page.balance = "Saldo" +bank_manager.statistics_page.current_balance = "Saldo atual" +bank_manager.statistics_page.details = "Detalhes" +bank_manager.balance = "Saldo" +bank_manager.inflation_rate = "Inflaçäo" +bank_manager.hospital_value = "Valor do hospital" +bank_manager.current_loan = "Empréstimo pendente" +menu_file_save[1] = " JOGO 1 " +menu_file_save[2] = " JOGO 2 " +menu_file_save[3] = " JOGO 3 " +menu_file_save[4] = " JOGO 4 " +menu_file_save[5] = " JOGO 5 " +menu_file_save[6] = " JOGO 6 " +menu_file_save[7] = " JOGO 7 " +menu_file_save[8] = " JOGO 8 " +insurance_companies[1] = "Seguros Estrelinha" +insurance_companies[2] = "Seguros Nacional" +insurance_companies[3] = "Mútua Seguril" +insurance_companies[4] = "Seguros Ponderoso" +insurance_companies[5] = "Geral Seguro" +insurance_companies[6] = "Seguro Fiel" +insurance_companies[7] = "Holding de Seguros" +insurance_companies[8] = "Seguros Leon" +insurance_companies[9] = "Joäo e Maria Ltda." +insurance_companies[10] = "Seguro Feliz" +insurance_companies[11] = "Seguros Sindicato" +insurance_companies.out_of_business = "FECHADO" +room_descriptions.ward[1] = "Enfermaria//" +room_descriptions.ward[2] = "Os pacientes ficam aqui para serem atendidos por uma enfermeira enquanto säo diagnosticados. Permanecem aqui antes de serem operados.//" +room_descriptions.ward[3] = "A enfermaria requer uma enfermeira. " +room_descriptions.blood_machine[1] = "Sala de Transfusöes//" +room_descriptions.blood_machine[2] = "O transfusiômetro é um elemento do equipamento de diagnóstico que revisa as células do sangue do paciente para descobrir do que sofrem.//" +room_descriptions.blood_machine[3] = "A sala de transfusöes requer um médico. Também precisa de manutençäo. " +room_descriptions.fracture_clinic[1] = "Traumatologia//" +room_descriptions.fracture_clinic[2] = "Os pacientes que têm a desgraça de ter fraturas vêm aqui. O removedor de gesso usa poderosos lasers industriais para cortar os gessos mais duros, causando ao paciente só uma pequena dor.//" +room_descriptions.fracture_clinic[3] = "A sala de traumatologia requer uma enfermeira. Também precisa de uma manutençäo muito frequente. " +room_descriptions.cardiogram[1] = "Sala de Cardiologia//" +room_descriptions.cardiogram[2] = "Aqui é diagnosticado e examinado os pacientes antes que voltem para a consulta, onde porá o tratamento.//" +room_descriptions.cardiogram[3] = "A sala de cardiologia requer um médico. Também precisa de manutençäo. " +room_descriptions.decontamination[1] = "Descontaminaçäo//" +room_descriptions.decontamination[2] = "Os pacientes que estiveram expostos à radiaçäo säo enviados rapidamente à consulta de descontaminaçäo. Esta consulta dispöe de uma ducha que os purifica de toda a horrível radioatividade e sujeira.//" +room_descriptions.decontamination[3] = "A ducha descontaminadora requer um médico. Também precisa de um faz-tudo que se ocupe da sua manutençäo. " +room_descriptions.jelly_vat[1] = "Banho Gelatinoso//" +room_descriptions.jelly_vat[2] = "Os pacientes que sofrem da risível doença da gelatinitis devem ir a cambalear-se para a consulta de gelatinitis e ser inundados no banheiro gelatinoso. Isto faz com que se curem de um modo que näo resulta de tudo compreensível para a profissäo médica.//" +room_descriptions.jelly_vat[3] = "O banho gelatinoso requer um médico. Também precisa de uma faz-tudo para a sua manutençäo. " +room_descriptions.gp[1] = "Sala de Consultório Geral//" +room_descriptions.gp[2] = "Esta é a consulta mais importante do seu hospital. Os novos pacientes säo enviados aqui para averiguar o que é que eles têm. Entäo, ou fazem outro diagnóstico ou mandam para uma consulta onde possam ser curados. Possivelmente queira construir outro consultório se o primeiro tiver muito trabalho. Quanto maior for o consultório e quanto mais objetos colocar nele, maior prestígio terá o médico. O mesmo acontece com todas as consultas abertas.//" +room_descriptions.gp[3] = "O consultório geral requer um médico. " +room_descriptions.hair_restoration[1] = "Peloterapia//" +room_descriptions.hair_restoration[2] = "Os pacientes que sofrem de calvície seräo enviados ao pêlo-restaurador desta sala. Um médico ligará o pêlo-restaurador, que, rapidamente, implantará na cabeça do paciente ar puro.//" +room_descriptions.hair_restoration[3] = "A consulta de peloterapia requer um médico. Também precisa de manutençäo periódica. " +room_descriptions.inflation[1] = "Inflatoterapia//" +room_descriptions.inflation[2] = "Os pacientes que sofrem a dolorosa doença de terem a cabeça inflada devem ir à sala de inflatoterapia, será desinflada sua cabeça e em seguida vota a ser inflada à pressäo correta.//" +room_descriptions.inflation[3] = "A Inflatoterapia requer um médico. Também precisa de um faz-tudo que se ocupe do seu bom funcionamento. " +room_descriptions.psych[1] = "Sala de Psiquiatria//" +room_descriptions.psych[2] = "Os pacientes que säo diagnosticados com uma doença psiquiátrica têm que ir a uma consulta de psiquiatria para receber o tratamento. Os psiquiatras também podem realizar diagnósticos para saber que tipo de doença que sofrem os pacientes, e se estas säo do tipo mental, podem tratá-los deitando-os no divä.//" +room_descriptions.psych[3] = "A sala de psiquiatria requer um médico especializado em psiquiatria. " +room_descriptions.operating_theatre[1] = "Sala de Operaçöes//" +room_descriptions.operating_theatre[2] = "Esta importante instalaçäo serve para curar um grande número de doenças. A sala de operaçöes tem que ser espaçosa e deve estar bem equipada. É uma parte essencial do seu hospital.//" +room_descriptions.operating_theatre[3] = "A sala de operaçöes requer dois médicos especializados em cirurgia. " +room_descriptions.no_room[1] = "" +room_descriptions.x_ray[1] = "Sala de Raio X//" +room_descriptions.x_ray[2] = "O Raio X fotografa o interior do paciente empregando uma radiaçäo especial para ajudar a equipe a descobrir o que acontece.//" +room_descriptions.x_ray[3] = "A sala de Raio X requer um médico. Também precisa de manutençäo. " +room_descriptions.tv_room[1] = "TV ROOM NOT USED" +room_descriptions.staff_room[1] = "Sala de Descanso//" +room_descriptions.staff_room[2] = "Os seus funcionários se cansam quando realizam o seu trabalho. Precisam desta sala para descansar e se refrescar. Os funcionários cansados säo mais lentos, pedem mais dinheiro e por fim väo embora. Também cometem mais erros. Vale a pena construir uma sala que tenham muitos passatempos. Assegure-se de que há lugar para vários funcionários ao mesmo tempo. " +room_descriptions.slack_tongue[1] = "Laringologia//" +room_descriptions.slack_tongue[2] = "Os pacientes que sejam diagnosticados com língua comprida na consulta seräo enviados aqui para receber tratamento. O médico utilizará uma máquina de alta tecnologia para estirar a língua e cortá-la e, com o que o paciente voltará a estar säo.//" +room_descriptions.slack_tongue[3] = "A sala de laringologia requer um médico. Também precisa de uma manutençäo muito frequente. " +room_descriptions.dna_fixer[1] = "Genética//" +room_descriptions.dna_fixer[2] = "Os pacientes que foram manipulados por alienígenas, devem ter seu DNA substituído nesta sala. O reparador de DNA é uma máquina complexa e seria sensato ter um extintor na sala, só por garantia.//" +room_descriptions.dna_fixer[3] = "O reparador de DNA requer que um faz-tudo o revise de vez em quando. Também requer um médico especializado em pesquisa para poder usá-lo. " +room_descriptions.training[1] = "Sala de Formaçäo//" +room_descriptions.training[2] = "Os seus residentes e médicos podem obter uma valiosa qualificaçäo extra aprendendo nesta sala. Um especialista em cirurgia, pesquisa ou psiquiatria ensinará a sua especialidade aos médicos que recebem formaçäo. Os médicos que já possuem estas especialidades veräo a sua habilidade aumentar enquanto estäo aqui.//" +room_descriptions.training[3] = "A sala de formaçäo requer um especialista. " +room_descriptions.toilets[1] = "Banheiro//" +room_descriptions.toilets[2] = "Os pacientes estäo sentindo um chamado da natureza e precisam se aliviar no conforto de suas instalaçöes de banheiro. Pode construir mais banheiros e pias se esperar muitos visitantes. Em alguns casos, terá que pôr mais banheiros em outras partes do hospital. " +room_descriptions.ultrascan[1] = "Ultra Scanner//" +room_descriptions.ultrascan[2] = "O ultra scanner é, virtualmente, o mais avançado em equipamentos de diagnóstico. Tem um preço alto mas merece a pena se quiser que o seu hospital realize diagnósticos excelentes.//" +room_descriptions.ultrascan[3] = "O ultra scanner requer um médico. Também precisa de manutençäo. " +room_descriptions.pharmacy[1] = "Farmácia//" +room_descriptions.pharmacy[2] = "Os pacientes que foram diagnosticados e que devem tomar um medicamento devem visitar a farmácia para tomá-lo. Quantos mais remédios forem descobertos e estejam disponíveis, mais concorrida estará a farmácia. Possivelmente queira construir outra farmácia mais para frente.//" +room_descriptions.pharmacy[3] = "A farmácia requer uma enfermeira. " +room_descriptions.research[1] = "Centro de Pesquisa//" +room_descriptions.research[2] = "No centro de pesquisa säo inventados ou melhoram novos remédios e curas. É uma parte essencial do seu hospital, e fará maravilhas para elevar a sua porcentagem de curas.//" +room_descriptions.research[3] = "O Centro de Pesquisa requer um médico especializado em pesquisa. " +room_descriptions.general_diag[1] = "Sala de Diagnóstico Geral//" +room_descriptions.general_diag[2] = "Aqui säo examinados os pacientes que precisam de outro diagnóstico. Se em uma consulta näo descobrir os seus problemas, o diagnosticador geral normalmente consegue. Em seguida, volta a enviar os pacientes para a consulta para analisar os resultados obtidos aqui.//" +room_descriptions.general_diag[3] = "A sala de diagnóstico geral requer um médico. " +room_descriptions.scanner[1] = "Scanner//" +room_descriptions.scanner[2] = "É diagnosticado com precisäo os pacientes empregando um sofisticado scanner. Em seguida, väo para a consulta para que o médico veja o tratamento posterior.//" +room_descriptions.scanner[3] = "O scanner requer um médico. Também precisa de manutençäo. " +room_descriptions.electrolysis[1] = "Eletrólise//" +room_descriptions.electrolysis[2] = "Os pacientes com peludismo säo enviados para esta consulta, onde uma máquina especial de eletrólise elimina os pelos e fecha os poros com eletricidade empregando um composto parecido ao cal.//" +room_descriptions.electrolysis[3] = "A sala de eletrólise requer um médico. Também precisa que um faz-tudo faça a sua manutençäo. " +staff_list.skill = "NIVEL" +staff_list.morale = "MORAL" +staff_list.tiredness = "CANSAÇO" +staff_list.total_wages = "SALARIOS TOTAIS" +menu_file_load[1] = " JOGO 1 " +menu_file_load[2] = " JOGO 2 " +menu_file_load[3] = " JOGO 3 " +menu_file_load[4] = " JOGO 4 " +menu_file_load[5] = " JOGO 5 " +menu_file_load[6] = " JOGO 6 " +menu_file_load[7] = " JOGO 7 " +menu_file_load[8] = " JOGO 8 " -vip_names = { - [1] = "Presidente da Cruz Vermelha", - [2] = "Ricardo Araújo Pereira", - [3] = "D. Duarte Pio de Bragança", - [4] = "Joe Berardo", - [5] = "José Mourinho", - [6] = "Alberto João Jardim", - [7] = "Marcelo Rebelo de Sousa", - [8] = "Cavaco Silva", - [9] = "Cristiano Ronaldo", - [10] = "Tradutor Filipe Carvalho", - health_minister = "Ministro da Saúde", -} - -room_descriptions = { - ultrascan = { - [1] = "Ultrasom//", - [2] = "O ultrasom é a última palavra em equipamento de diagnóstico. Custa caro, mais vale a pena se deseja um diagnóstico soberbo em seu hospital.//", - [3] = "The Ultrasom precisa de manutenção e um médico (qualquer nível) para funcionamento. ", - }, - gp = { - [1] = "Clínica Geral//", - [2] = "Esta é a sala de diagnósticos primordial de um hospital. Novos pacientes sentarão aqui para descobrir o que há de errado com eles. Serão enviados posteriormente para outras salas de dianóstico ou para serem curados. Você poderá construir outra Sala de Clínica Geral se esta ficar muito ocupada. Quanto maior a sala for, mais objetos adicionais podem ser colocados nela, e maior o prestígio do médico. Isso vale igualmente para todas as outras salas.//", - [3] = "A Sala de Clínica Geral precisa de um médico de qualquer nível. ", - }, - fracture_clinic = { - [1] = "Clínica de Fraturas//", - [2] = "Aqueles pacientes azarados o bastante por terem seus ossos quebrados vem aqui. A máquina de remover gesso irá empregar lasers industriais para partir o mais duro gesso, causando apenas um ligeira agonia ao paciente.//", - [3] = "A Clínica de Fraturas precisa de uma Enfermeira para funcionamento e contínua manutenção. ", - }, - tv_room = { - [1] = "TV ROOM NOT USED", - }, - inflation = { - [1] = "Inflador//", - [2] = "Pacientes que sofrerem da dolorosa-porém-engraçada condição de 'Cabeça Inchada' devem vir ao Inflador, onde seu avantajado crânico será estourado e reinflado instantaneamente na pressão correta.//", - [3] = "O Inflador precisa de um médico de qualquer nível, além de cuidados constantes de um Funcionário da Manutenção. ", - }, - jelly_vat = { - [1] = "Clínica de Geléia//", - [2] = "Pacientes amaldiçoados com a rídicula Geléite devem ser encaminhados para a Clínica de Geléia, e colocados no tanque de Geléia, sendo curados de uma maneira até então não compreendida totalmente pela medicina.//", - [3] = "A Clínica de Geléia precisa de um médico de qualquer nível, e de cuidados dos funcionários da manutenção. ", - }, - scanner = { - [1] = "Ressonância Magnética//", - [2] = "Os pacientes são diagnosticados de forma precisa usando esta máquina de Ressonância Magnética. Eles irão então ver um médico na Clínica Geral para tratamento posterior.//", - [3] = "A máquina de Ressonância Magnética precisa de um médico de qualquer nível, além de manutenção. ", - }, - blood_machine = { - [1] = "Máquina de Sangue//", - [2] = "A Máquina de Sangue é uma parte do arsenal de diagnósticos que verifica as células no sangue do paciente para descobrir o que há de errado com ele.//", - [3] = "A Máquina de Sangue precisa de um médico de qualquer nível, além de manutenção. ", - }, - pharmacy = { - [1] = "Farmácia//", - [2] = "Pacientes que tenham sido diagnosticados e seu tratamento prevê algum medicamento devem visitar a Farmácia para tomá-lo. Conforme novos medicamentos vão sendo pesquisados e disponibilizados, a sala vai ficando movimentada, portanto você pode ter a necessidade de construir outra no futuro.//", - [3] = "A Farmácia precisa de uma Enfermeira. ", - }, - cardiogram = { - [1] = "Eletrocardiograma//", - [2] = "Pacientes são diagnosticados e checados aqui, antes de voltarem à Sala de Clínica Geral para um diagnóstico final.//", - [3] = "O Eletrocardiograma precisa de um médico de qualquer nível, além de manutenção. ", - }, - ward = { - [1] = "Enfermaria//", - [2] = "Pacientes que forem mantidos aqui sob observação de uma Enfermeira durante diagnóstico. Eles permanecem aqui antes de serem operados.//", - [3] = "A Enfermaria precisa de uma Enfermeira. ", - }, - psych = { - [1] = "Psiquiatria//", - [2] = "Pacientes diagnosticados com males psiquiátricos devem visitar o Departamento de Psiquiatria para receber aconselhamento. Psiquiatras podem ainda fazer diagnósticos, descobrindo que tipo de mal o paciente possui, se há origem mental, tratando-se no divã.//", - [3] = "O Departamento de Psiquiatria precisa de um Psiquiatra. ", - }, - staff_room = { - [1] = "Sala de Relaxamento//", - [2] = "Sua equipe fica estressada ao longo de um dia de trabalho. Eles precisam desta sala para relaxar e descansar. Funcionários cansados trabalham em marcha lenta, exigem mais dinheiro e eventualmente pedem demissão, além de cometer mais erros. Construa uma sala de relaxamento com muitas possibilidades de entretenimento é muito interessante. Certifique-se que a sala comporte vários funcionários de uma só vez. ", - }, - operating_theatre = { - [1] = "Sala de Operações//", - [2] = "Esta importante instalação é onde uma série de condições serão tratadas. Deve ter um bom tamanho, e deve ser ocupado com o equipamento correto. Ele é vital para seu hospital.//", - [3] = "A Sala de Operações precisa de dois Cirurgiões. ", - }, - training = { - [1] = "Sala de Treinamento//", - [2] = "Seus médicos de nível junior e pleno podem adquirir qualificações extras estudando nesta sala. Um Cirurgião, Pesquisador e/ou Psiquiatra Sênior pode passar este conhecimento para quaisquer médicos sendo treinados, e aqueles que já possuírem estas habilidades poderão aprimorá-las aqui.//", - [3] = "A Sala de Treinamento precisa de um Doutor Sênior. ", - }, - dna_fixer = { - [1] = "Clínica de DNA//", - [2] = "Pacientes que foram abduzidos por alienígenas de outro mundo deve ter seu DNA substituído nesta sala. A máquina de fixação de DNA é um equipamento complexo e pode ser sensato manter um extintor de incêndio dentro da sala, por via das dúvidas.//", - [3] = "A máquina de fixação de DNA deverá ter manutenção constante de um funcionário, precisando de um Pesquisador para operá-la. ", - }, - research = { - [1] = "Departamento de Pesquisas//", - [2] = "Novos medicamentos e cruas são inventados e aprimorados no Departamento de Pesquisas. Vital para seu hospital, fará maravilhas em seu percentual de curas.//", - [3] = "A Departamento de Pesquisas precisa de um Pesquisador. ", - }, - hair_restoration = { - [1] = "Clínica de Restauração de Cabelos//", - [2] = "Pacientes que sofrem de uma condição de calvície extrema serão encaminhados para a máquina de restauração de cabelos desta Clínica. Um médico irá operar a máquina, que irá fazer crescer quase instantaneamente um cabelo novo.//", - [3] = "A Clínica de Restauração de Cabelos precisa de um médico de qualquer nível, além de cuidados de um funcionário da manutenção. ", - }, - general_diag = { - [1] = "Diagnósticos Gerais//", - [2] = "Pacientes que necessitem de uma investigação mais profunda são analisados aqui. Se a Clínica Geral não encontrar o que há de errado com eles, Diagnósticos Gerais geralmente irá. Daqui ele é enviado de volta à Clínica Geral para análise dos resultados produzidos aqui.//", - [3] = "O Diagnósticos Gerais precisa de um médico de qualquer nível.", - }, - electrolysis = { - [1] = "Sala de Eletrólise//", - [2] = "Pacientes com Pelulite são encaminhados para esta sala, onde uma máquina especial chamada Eletrolizador arranca os pêlos e esteriliza os poros eletricamente usando um composto similar à uma argamassa.//", - [3] = "A Sala de Eletrólise precisa de um médico de qualquer nível, além de cuidados de um funcionário da manutenção. ", - }, - slack_tongue = { - [1] = "Clínica de Língua Negligente//", - [2] = "Paciente diagnosticados na Clínica Geral com Língua Negligente serão enviados para esta clínica para tratamento. O médico irá usando um maquinário de última geração para extender a língua e cortá-la fora, restaurando a saúde do paciente.//", - [3] = "A Clínica de Língua Negligente precisa de um médico de qualquer nível, e manutenção frequente. ", - }, - toilets = { - [1] = "Toalete//", - [2] = "Pacientes que ouvirem o chamado da natureza irão se aliviar no conforto deste toalete. Você poderá construir baias e lavatórios extras se houver a expectativa de muitos visitantes. Em alguns casos, considere construir toaletes em outros pontos do hospital. ", - }, - no_room = { - [1] = "", - }, - x_ray = { - [1] = "Raio-X//", - [2] = "A máquina de Raio-X fotografa as pessoas por dentro usando radiação especial, fornecendo à equipe uma boa idéia do que há de errado com elas.//", - [3] = "O Raio-X precisa de um médico de qualquer nível, além de manutenção. ", - }, - decontamination = { - [1] = "Clínica de Descontaminação//", - [2] = "Pacientes que foram expostos à radiação devem ser levados rapidamente à Clínica de Descontaminação. Esta sala contém um chuveiro lavar toda a horrível radiação e.. sujeira.//", - [3] = "O chuveiro de descontaminação precisa de um médico de qualquer nível, além de cuidados de um funcionário da manutenção. ", - }, -} - -pay_rise = { - definite_quit = "Nada que você fizer vai me manter aqui, pra mim chega.", - regular = { - [1] = "Estou em frangalhos. Preciso de um bom descanso, além de um aumento de %d se você não quer me ver por aqui neste trabalho enfadonho.", - [2] = "Estou muito cansado. Preciso de um descanso e um aumento de salário de %d, indo para %d. Faça agora, seu tirano!", - [3] = "Veja bem, estou trabalhando como uma mula! Quero um bônus de %d para ficar neste hospital.", - [4] = "Estou infeliz. Exijo um aumento de %d, aumentando meus honorários para %d, caso contrário estou fora.", - [5] = "Meus pais haviam me dito que a área médica pagava bem. Então me dê um aumento de %d ou largo a área para fazer jogos de computador.", - [6] = "Estou de saco cheio. Pague-me um salário decente, um aumento de %d deve bastar.", - }, - poached = "Recebi uma proposta de %d feita pelo %s. Pague-me o mesmo ou estou fora.", -} - -level_names = { - [1] = "Toxilândia", - [2] = "Sleepy Hollow", - [3] = "Peito largo", - [4] = "Frimpton-on-Sea", - [5] = "Simplolândia", - [6] = "Festering-on-the-Wold", - [7] = "Greenpool", - [8] = "Manquay", - [9] = "Vila do Leste", - [10] = "Eggsenham", - [11] = "Croaking", - [12] = "Battenburg", - [13] = "Chumleigh", - [14] = "Sova", - [15] = "Enterra Enterra", -} - -staff_descriptions = { - good = { - [1] = "Trabalha muito rápido e aplicado(a). ", - [2] = "Muito consciente. Importa-se profundamente. ", - [3] = "Possui várias habilidades. ", - [4] = "Amistoso(a) e adora uma gargalhada. ", - [5] = "Resistência admirável, trabalha pesado. ", - [6] = "Educado(a) e cordial de forma notável. ", - [7] = "Incrivelmente talentoso(a) e capaz. ", - [8] = "Dedica-se muito ao trabalho designado. ", - [9] = "Perfeccionista e persistente. ", - [10] = "Dedicado(a) a ajudar pessoas com um sorriso no rosto. ", - [11] = "Charmoso(a), educado(a) e prestativo(a). ", - [12] = "Frequentemente muito motivado(a) e dedicado(a). ", - [13] = "Bem-humorado(a) e muito trabalhador(a). ", - [14] = "Leal e amigável. ", - [15] = "Cuidadoso(a) e confiável em uma emergência.", - }, - misc = { - [1] = "Joga golfe. ", - [2] = "Pratica mergulho. ", - [3] = "Faz esculturas no gelo. ", - [4] = "Bebe vinho. ", - [5] = "Participa de rally. ", - [6] = "Faz bungee-jump. ", - [7] = "Coleciona latas de cerveja. ", - [8] = "Gosta de mergulhar no público nos shows. ", - [9] = "Jogar de praticar surf. ", - [10] = "Jogar de praticar raffiting. ", - [11] = "Destila whisky. ", - [12] = "Especialista no 'faça-você-mesmo'. ", - [13] = "Gosta de filmes de arte franceses. ", - [14] = "Joga 'Theme Park' muito. ", - [15] = "Possui carteira de habilitação E. ", - [16] = "Corre de motocicleta. ", - [17] = "Toca violino e violoncelo clássicos. ", - [18] = "Adora colisões de trens. ", - [19] = "Amante de cães. ", - [20] = "Ouve rádio. ", - [21] = "Toma banho frequentemente. ", - [22] = "Instrutor de tricô. ", - [23] = "Tira o miolo dos vegetais para usar como porta sabão. ", - [24] = "Policial especial meio-período. ", - [25] = "Ex-apresentador de programa de calouros. ", - [26] = "Coleciona estilhaços da Segunda Guerra. ", - [27] = "Restaurador de mobília. ", - [28] = "Ouve rave e trip-hop. ", - [29] = "Extermina insetos com desodorante spray. ", - [30] = "Ridiculariza comediantes ruins. ", - [31] = "Arruma confusão em reunião de condomínio. ", - [32] = "Jardineiro incorrigível. ", - [33] = "Contrabandeia relógios falsificados. ", - [34] = "Vocalista de uma banda de rock and roll. ", - [35] = "Adora os programas da televisão vespertina. ", - [36] = "Cutuca trutas. ", - [37] = "Isca turistas em museus. ", - }, - bad = { - [1] = "Lento e inquieto. ", - [2] = "Preguiçoso e pouco motivado. ", - [3] = "Mal treinado e ineficaz. ", - [4] = "Rude e áspero. Afasta as pessoas. ", - [5] = "Resistência terrível - tem uma gênio ruim. ", - [6] = "Surdo como uma porta. Cheira à repolho. ", - [7] = "Péssimo(a) no trabalho, meramente responsável. ", - [8] = "Imprudente e distraído. ", - [9] = "Estressado com tendência e cometer erros. ", - [10] = "Retorcido e ressentido - explodindo de raiva. ", - [11] = "Descuidado e propenso à acidentes. ", - [12] = "Não se preocupa com o trabalho. Muito preguiçoso. ", - [13] = "Tolo que gosta se assumir riscos e não se importa com nada. ", - [14] = "Dissimulado, malandro e subversivo. ", - [15] = "Arrogante e convencido. ", - }, -} diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/czech.lua corsix-th-0.62/CorsixTH/Lua/languages/czech.lua --- corsix-th-0.30/CorsixTH/Lua/languages/czech.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/czech.lua 2018-07-21 11:13:17.000000000 +0000 @@ -105,6 +105,8 @@ create_patient = "Vytvořit Pacienta", end_month = "Konec Měsíce", vip = "Vytvořit VIP", + epidemic = "Vytvořit nakažlivého pacienta", + toggle_infected = "Zapnout/Vypnout ikony nakažení", }, } menu_file_save = { @@ -137,6 +139,7 @@ custom_game_window = { free_build = "Volné stavění", caption = "Vlastní Hra", + load_selected_level = "Spustit", } menu_debug_overlay = { positions = " POZICE ", @@ -244,6 +247,7 @@ awaiting_decision = "Čekám na Vaše rozhodnutí", sent_to_other_hospital = "Odkázán jinam", epidemic_sent_home = "Poslán domů Inspektorem", + epidemic_vaccinated = "Již nejsem nakažlivý", }, emergency = "Havárie: %s", }, @@ -385,9 +389,7 @@ in_progress = "Dám Vám vědět, zdali tato osoba bude chtít jít pro Vás pracovat.", }, everyone_failed = "Všichni nedokázali splnit poslední úkol. Takže všichni budou hrát dál !", - objective_completed = "Splnili jste úkol. Blahopřejeme!", players_failed = "Následující hráč(i) nedokázal(i) splnit poslední úkol : ", - objective_failed = "Nesplnili jste úkol.", }, staff_place_advice = { only_doctors_in_room = "Pouze Doktoři mohou v %s pracovat", @@ -1092,8 +1094,8 @@ movies = "Globální kontrola videí, toto umožňuje zákaz všech videí", fractured_bones = "Kvůli špatné animaci jsou standardně zakázány pacientky se Zlomenými Kostmi. Pro povolení pacientek s touto diagnózou ve vaší nemocnici musíte toto vypnout.", volume = "Pokud tlačítko pro snížení hlasitosti zároveň také otevírá Knihu léčby pacientů, můžete toto zapnout pro změnu klávesové zkratky knihy na Shift + C", - intro = "Zapne nebo vypne úvodní video. Pokud chcete, aby video bylo přehráváno při každém spuštění CorsixTH, je třeba zapnout globální kontrolu videí.", - paused = "V Theme Hospital může hráč použít horní nabídku pouze při pozastavení hry. To samé platí v CorsixTH, ale pomocí této volby můžete při pozastavení povolit vše.", + intro = "Zapne nebo vypne úvodní video. Pokud chcete, aby video bylo přehráváno při každém spuštění CorsixTH, je třeba zapnout globální kontrolu videí.", + paused = "V Theme Hospital může hráč použít horní nabídku pouze při pozastavení hry. To samé platí v CorsixTH, ale pomocí této volby můžete při pozastavení povolit vše.", }, options_window = { language = "Vybrat %s jako jazyk", @@ -1139,6 +1141,8 @@ all_research = "Dokončí veškerý výzkum.", create_patient = "Vytvoří Pacienta na kraji mapy.", end_month = "Přeskočí na konec měsíce.", + epidemic = "Vytvoří nakažlivého pacienta, který může způsobit epidemii", + toggle_infected = "Zobrazí/Skryje ikony nakažení pro aktivní, zjištěné epidemie", }, }, buy_objects_window = { @@ -1150,8 +1154,9 @@ increase = "Koupit o jednu položku více", }, custom_game_window = { - start_game_with_name = "Načíst úroveň %s", free_build = "Toto políčko zaškrtněte, pokud chcete hrát bez peněz a podmínek pro vítězství a prohru", + load_selected_level = "Načíst a hrát zvolenou úroveň", + choose_game = "Klikněte na úroveň pro zobrazení informací o ní.", }, new_game_window = { easy = "Pokud jste začátečníci v simulačních hrách, tak toto je volba pro Vás", @@ -1287,6 +1292,8 @@ network = "Spustit hru po síti", exit = "Ne, ne, prosím neodcházejte!", quit = "Odejít", + custom_campaign = "Hrát komunitou vytvořenou kampaň", + map_edit = "Vytvořit vlastní mapu", }, queue_window = { num_expected = "Počet pacientů, u kterých Recepční očekává, že se brzy připojí do fronty", @@ -1588,6 +1595,14 @@ swing_door1 = "52 OB_DOUBLE_DOOR1", skeleton = "Kostlivec: používán ke cvičebním účelům a na Halloween.", }, + custom_campaign_window = { + choose_campaign = "Zvolte kampaň pro zobrazení informací o ní.", + start_selected_campaign = "Načte první úroveň kampaně", + }, + save_map_window = { + map = "Přepsat mapu %s", + new_map = "Zadejte název uložené hry s mapou", + }, } humanoid_name_ends = { [1] = "KOVÁŘ", @@ -2595,6 +2610,9 @@ alien_dna = "POZNÁMKA: Pro animaci s Mimozemskou DNA neexistují animace pro sednutí, otevírání nebo klepání na dveře atd. Proto se při těchto činnostech, stejně jako v Theme Hospital, dočasně změní na normálně vypadající pacienty a pak se změní zpět. Tyto pacienti se v nemocnici objeví pouze při nastavení v souboru úrovně", fractured_bones = "POZNÁMKA: Animace ženských pacientů se Zlomenými kostmi není dokonalá", load_quick_save = "Chyba! Rychle uloženou pozici nelze načíst, protože neexistuje. Není třeba se obávat, hned jsme jednu pro Vás vytvořili!", + no_games_to_contine = "Žádné uložené hry.", + could_not_load_campaign = "Nelze načíst kampaň: %s", + could_not_find_first_campaign_level = "Nelze načíst první úroveň této kampaně: %s", } menu = { charts = " GRAFY ", @@ -2602,6 +2620,7 @@ file = " SOUBOR ", display = " ZOBRAZENÍ ", debug = " LADĚNÍ ", + player_count = "POČET HRÁČŮ", } lua_console = { close = "Zavřít", @@ -2622,7 +2641,7 @@ jukebox = " JUKEBOX ", warmth_colors = " BARVY TEPLOTY", twentyfour_hour_clock = " 24HODINOVÝ REŽIM ", - wage_increase = " MZDOVÉ POŽADAVKY", + wage_increase = " MZDOVÉ POŽADAVKY", } menu_options_warmth_colors = { choice_2 = " MODRÁ ZELENÁ ČERVENÁ ", @@ -2671,19 +2690,24 @@ mapwho_checking = " KONTROLA MAPYKDO ", display_big_cells = " ZOBRAZIT VELKÉ BUŇKY ", porter_pagers = " PAGERY OBSLUHY ", + debug_script = " (SHIFT + D) SPUSTIT SKRIPT PRO LADĚNÍ ", + connect_debugger = " (CTRL + C) PŘIPOJIT LUA DBGp SERVER ", } save_game_window = { caption = "Uložit Hru (%1%)", new_save_game = "Nová Uložená Hra", } main_menu = { - custom_level = "Vlastní Úroveň", - load_game = "Načíst Hru", + custom_level = "Vlastní úroveň", + load_game = "Načíst hru", options = "Nastavení", savegame_version = "Verze ukládaných her: ", version = "Verze: ", exit = "Ukončit", - new_game = "Nová Hra", + new_game = "Nová hra", + continue = "Pokračovat ve hře", + custom_campaign = "Vlastní kampaň", + map_edit = "Editor map", } letter = { [1] = { @@ -2746,13 +2770,16 @@ }, [12] = { [1] = "Vážený/á %s//", - [2] = "Vaše úspěšná kariéra nejlepšího správce nemocnice od dob Mojžíše se chýli ke konci. Nicméně, Váš dopad na pohodlný svět lékařství byl tak výrazný, že by Vám Ministerstvo rádo nabídlo plat %d€ jen abyste se objevili jako náš zástupce, zahajovat slavnosti, spouštět lodě a pořádat televizní zábavný program. Celý svět po Vás volá a pro nás všechny by to byla dobrá reklama!//", + [2] = "Vaše úspěšná kariéra nejlepšího správce nemocnice od dob Mojžíše se chýlí ke konci. Nicméně, Váš dopad na pohodlný svět lékařství byl tak výrazný, že by Vám Ministerstvo rádo nabídlo plat %d€ jen abyste se objevili jako náš zástupce, zahajovat slavnosti, spouštět lodě a pořádat televizní zábavný program. Celý svět po Vás volá a pro nás všechny by to byla dobrá reklama!//", [3] = "Prosím přijměte tuto pozici. Nebude to těžká práce a poskytneme Vám auto a policejní doprovod kamkoliv se hnete.//", [4] = "", }, custom_level_completed = "Výborně! Dokončili jste všechny úkoly v této vlastní úrovni!", dear_player = "Vážený/á %s", return_to_main_menu = "Chtěli byste se vrátit do hlavního menu, nebo pokračovat v hraní?", + campaign_level_completed = "Dobrá práce! Splnili jste úroveň. Ale ještě není konec! Chtěli byste přijmout pozici v nemocnici %s?", + campaign_level_missing = "Je nám líto, ale zdá se, že následující úroveň této kampaně chybí. (Název: %s)", + campaign_completed = "Neuvěřitelné! Zvládli jste splnit všechny úrovně. Nyní si můžete oddychnout a začít sepisovat sebechválu na všech fórech na Internetu. Hodně štěstí!", } rooms_short = { dna_fixer = "Spravovač DNA", @@ -3000,135 +3027,116 @@ skill = "DOVEDNOSTI", } introduction_texts = { - level14 = { - [1] = "Je tu ještě jedna výzva - naprosto nečekaná nemocnice jako překvapení. ", - [2] = "Jestliže toto bude úspěch, bude vítěz nad všemi vítězi. ", - [3] = "Nečekejte ale, že to bude lehké, protože je to ten nejtěžší úkol, jaký jste kdy viděli. ", - [4] = "Hodně Štěstí!", - }, - level16 = { - [1] = "Jakmile jste některé pacienty vyšetřili, budete muset pro jejich léčbu postavit léčebná zařízení a oddělení - dobrý začátek ", - [2] = "je Lékárna. Budete také potřebovat Sestru k vydávání různých léků v Lékárně.", - }, - level15 = { - [1] = "Dobrá, tak toto jsou základní instrukce jak sestavit nemocnici.//", - [2] = "Vaši Doktoři budou potřebovat veškerou pomoc, kterou mohou získat k vyšetření některých pacientů. Můžete jim pomoci ", - [3] = "postavením jiného diagnostického zařízení jako např. Místnost Obecného Vyšetření.", - }, - level18 = { - }, - level12 = { - [1] = "Nyní máte matku všech výzev. ", - [2] = "Ohromeni Vašim úspěchem, Ministerstvo má pro Vás špičkovou práci; chtějí, aby někdo postavil tu nejlepší nemocnici, vydělat obrovské množství prašulí a mít neuvěřitelnou reputaci. ", - [3] = "Očekává se, že také koupíte všechny pozemky, které můžete, všechno vyléčíte (a tím myslíme všechno) a vyhrajete všechna ocenění. ", - [4] = "Myslíte, že na to máte?", - [5] = "Vydělejte 650,000€, vylečte 750 lidí, a mějte reputaci ve výši 800, abyste toto vyhráli.", - }, - level17 = { - [1] = "Malé varování - velmi si hlídejte Vaši reputaci - to je co pacienty přiláká z široko daleka do Vašeho zařízení. ", - [2] = "Pokud nezabijete příliš mnoho lidí a udržíte je rozumně šťastné, neměli byste mít v této úrovni problémy!//", - [3] = "Teď jste v tom sami. Hodně štěstí a tak dále.", - }, - level4 = { - [1] = "Udržte všechny lidi šťastné, zacházejte s nimi tak dobře jak to jen a udržte úmrtí na absolutní minimum.", - [2] = "Vaše reputace je v sázce, takže se ujistěte, že ji budete mít tak vysoko, jak je to jen možné. ", - [3] = "O peníze se moc nestarejte - ty přijdou, jak Vaše důležitá reputace poroste. ", - [4] = "Budete mít také možnost učit Doktory k rozšíření jejich schopností. ", - [5] = "Mohli by mít na starost pacienta, který se zdá být méně neprůhledný, než většina. ", - [6] = "Dosáhněte reputace přes 500.", - }, - level13 = { - [1] = "Vaše neuvěřitelné dovednosti správce nemocnice neunikly Zvláštnímu Tajnému Oddělení Zvláštní Tajné. ", - [2] = "Mají pro Vás zvláštní bonus; je tu krysami zamořená nemocnice, která potřebuje účinného Terminátora. ", - [3] = "Musíte zastřelit tolik krys, kolik můžete, než Údržbáři uklidí všechen bordel. ", - [4] = "Myslíte, že to zvládnete?", - }, - level6 = { - [1] = "Použijte všechny Vaše znalosti k zřízení bezproblémové, dobře spravované nemocnice, která má zdravý příjem a může se vypořádat s čímkoliv, co na ní nemocná veřejnost může hodit. ", - [2] = "Musíte si uvědomit, že zdejší atmosféra je zvláště vhodná k přenášení bacilů a infekcí. ", - [3] = "Pokud nebudete Vaše zařízení udržovat až puntičkářsky čisté, můžete čelit řadě epidemií mezi pacienty. ", - [4] = "Ujistěte se, že si vyděláte 150,000€ a že Vaše nemocnice má hodnotu přes 140,000€.", - }, - level5 = { - [1] = "Toto bude zaneprázdněná nemocnice, která bude řešit různé případy. ", - [2] = "Vaši Doktoři jsou všichni přímo ze zdravotnické školy, takže bude zásadní vybudovat výukovou místnost a naučit je do přípustných úrovní. ", - [3] = "Máte pouze tři Konzultanty, kteří Vám pomohou s výukou Vašich nezkušených zaměstnanců, takže je udržujte šťastné. ", - [4] = "Nezapomeňte, také, že, základy této nemocnice sedí na geologickém zlomu San Robot. ", - [5] = "Je tu vždy přítomné nebezpečí zemětřesení. ", - [6] = "Způsobí vážné poškození Vašich přístrojů a naruší hladký chod Vaší nemocnice. ", - [7] = "Dostaňte Vaši reputaci na značku 400, a uložte suprových 50,000€ abyste uspěli. Také, vylečte 200 pacientů.", - }, - level8 = { - [1] = "Je na Vás zřídit tu nejúčinnější a nákladově efektivní nemocnici, jak to jen jde. ", - [2] = "lidé v tomto okolí se mají za dobře, takže z nich vymáčkněte tolik prašulí, kolik můžete. ", - [3] = "Nezapomeňte, léčení lidí je sice hezké, ale opravdu POTŘEBUJETE peníze, které to přináší. ", - [4] = "Vezměte tyto nemocné lidi do čistírny. ", - [5] = "Nashromážděte ohromných 300,000€ k dokončení této úrovně.", - }, - level7 = { - [1] = "Zde budete pod pečlivou kontrolou z Ministerstva Zdravotnictví, takže se ujistěte, že Vaše účty ukazují, že vyděláváte hodně peněz a že Vaše reputace je ve výšinách. ", - [2] = "Nemůžeme si dovolit zbytečná úmrtí - jsou špatná pro byznys. ", - [3] = "Ujistěte se, že Vaši zaměstnanci jsou v nejlepší formě, a že máte veškeré vybavení, které potřebujete. ", - [4] = "Dostaňte reputaci ve výši 600, plus 200,000€ v bance.", - }, - level2 = { - [1] = "V této oblasti je větší škála nemocí. ", - [2] = "Postavte Vaši nemocnici, aby zvládla více pacientů a nachystejte se na vybudování Výzkumného Oddělení. ", - [3] = "Nezapomeňte udržovat Vaše zařízení čisté a zkuste dostat vaši reputaci tak vysoko, jak to jen jde - budete čelit nemocem jako je Ochablý Jazyk, takže potřebujete Oddělení Ochablého Jazyka. ", - [4] = "Můžete také postavit Kardiogram, aby Vám pomohl vyšetřit nové nemoci. ", - [5] = "Obě tyto místnosti musí být vyzkoumány předtím, než je budete moci postavit. Nyní si také můžete zakoupit dodatečné parcely pozemků k rozšíření Vaší nemocnice - pro toto použijte Mapu Města. ", - [6] = "Miřte k reputaci 300 a bankovní bilance 10,000€ a 40 vyléčeným lidem.", - }, - level9 = { - [1] = "Když jste naplnili bankovní účet Ministerstva a zaplatili a novou limuzínu pro samotného Ministra, nyní se můžete vrátit zpět k vytváření pečující, dobře zřízené nemocnice ve prospěch nemocných a potřebných. ", - [2] = "Můžete očekávat, že se zde objeví spousta rozdílných problémů.", - [3] = "Pokud máte dostatek dobře vyškolených zaměstnanců a místností, měli byste mít všechno pokryto. ", - [4] = "Vaše nemocnice musí mít hodnotu 200,000€ a budete potřebovat 400,000€ v bance. ", - [5] = "Cokoliv méně a nebudete moct dokončit úroveň.", - }, - demo = { - [1] = "Vítejte v demo nemocnici!", - [2] = "Bohužel, demo verze obsahuje pouze tuto úroveň. Nicméně je toho více než dost, abyste se na chvilku zabavili!", - [3] = "Setkáte se s různými nemocemi, které potřebují různé místnosti k léčbě. Čas od času se můžou stát havárie. A budete potřebovat vyzkoumat dodatečné místnosti pomocí výzkumného oddělení.", - [4] = "Vaším úkolem je vydělat 100,000€, mít hodnotu nemocnice ve výši 70,000€ a reputaci 700, přičemž musíte vyléčit alespoň 75% Vašich pacientů.", - [5] = "Ujistěte se, že Vaše reputace nespadne 300 a že nezabijete více než 40% Vašich pacientů, nebo prohrajete.", - [6] = "Hodně štěstí!", - }, - level10 = { - [1] = "Stejně jako zvládnutí všech nemocí, které se v této oblasti vyskytují, Ministerstvo žádá, abyste strávil nějaký čas soustředěním se na účinnost Vašich léků. ", - [2] = "Z ČasNemoci, Hlídacího Psa Zdravotnictví, se ozívají jisté stížnosti, takže abyste vypadali dobře, musíte zajistit, že Vaše léky jsou mimořádně účinné. ", - [3] = "Také zajistěte, aby Vaše nemocnice nemusela být kárána. Ať ty úmrtí nejsou vysoká. ", - [4] = "Jako nápověda, možná byste měli vyhradit prostor pro Želé Nádrž. ", - [5] = "Zdokonalte všechny Vaše léky na alespoň 80 procentní účinnost, mějte reputaci 650 a ukryjte 500,000€ v bance, abyste vyhráli. ", - }, - level11 = { - [1] = "Byla Vám dána šance vybudovat to nejlepší z nemocnic. ", - [2] = "Toto je mimořádně prestižní oblast a Ministerstvo by rádo chtělo vidět tu nejlepší možnou nemocnici. ", - [3] = "Očekáváme, že budete vydělávat velké peníze, mít skvostně vysokou reputaci a zvládat všechny možné případy. ", - [4] = "Toto je důležitá práce. ", - [5] = "Budete muset být něco zvláštního, abyste toto zvládli. ", - [6] = "Nezapomeňte, také, že v oblasti byla zpozorována UFO. Ujistěte se, že Vaši zaměstnanci jsou připraveni na nečekané návštěvníky. ", - [7] = "Vaše nemocnice potřebuje mít hodnotu 240,000€, v bance potřebujete 500,000€ a Vaše reputace bude potřeba být na 700.", - }, - level3 = { - [1] = "Tentokrát budete zřizovat nemocnici v zámožné oblasti. ", - [2] = "Ministerstvo Zdravotnictví očekává od Vás, že zde zajistíte zdravý příjem. ", - [3] = "Především budete muset získat dobrou reputaci, ale jakmile nemocnice běží naprázdno, soustřeďte se co nejvíce na vydělávání peněz. ", - [4] = "Je tu také možnost výskytu Havárií. ", - [5] = "To je tehdy, když velký počet lidí přijde najednou a všichni mají stejnou nemoc. ", - [6] = "Vyléčení všech v časovém limitu Vám přidá lepší reputaci a velký bonus. ", - [7] = "Nemoci jako Králův Komplex se mohou objevit a měli byste dát do rozpočtu výstavbu Operačního Sálu a Nemocničního Pokoje poblíž. ", - [8] = "Vydělejte si 20,000€ abyste dosáhli další úrovně.", - }, - level1 = { - [1] = "Vítejte ve Vaší první nemocnici!//", - [2] = "Rozchoďte to tu umístěním Recepce, vybudováním Kanceláře Praktického Lékaře a najmutím Recepční a Doktora. ", - [3] = "Pak počkejte, až přijde nějaký byznys.", - [4] = "Je dobrý nápad postavit Odd. Psychiatrie a najmout Doktora s Psychiatrickými kvalifikacemi. ", - [5] = "Lékárna a Sestra jsou také nutné k léčbě Vašich pacientů. ", - [6] = "Dejte si pozor na ničemné případy Nafouknuté Hlavy - Nafukovárna je brzy spraví. ", - [7] = "Budete chtít vyléčit 10 lidí a zajistit, že Vaše reputace nespadne pod 200.", - }, + level14 = + "Je tu ještě jedna výzva - naprosto nečekaná nemocnice jako překvapení. " .. + "Jestliže toto bude úspěch, bude vítěz nad všemi vítězi. " .. + "Nečekejte ale, že to bude lehké, protože je to ten nejtěžší úkol, jaký jste kdy viděli. " .. + "Hodně Štěstí!", + level16 = + "Jakmile jste některé pacienty vyšetřili, budete muset pro jejich léčbu postavit léčebná zařízení a oddělení - dobrý začátek " .. + "je Lékárna. Budete také potřebovat Sestru k vydávání různých léků v Lékárně.", + level15 = + "Dobrá, tak toto jsou základní instrukce jak sestavit nemocnici.//" .. + "Vaši Doktoři budou potřebovat veškerou pomoc, kterou mohou získat k vyšetření některých pacientů. Můžete jim pomoci " .. + "postavením jiného diagnostického zařízení jako např. Místnost Obecného Vyšetření.", + level18 = "", + level12 = + "Nyní máte matku všech výzev. " .. + "Ohromeni Vašim úspěchem, Ministerstvo má pro Vás špičkovou práci; chtějí, aby někdo postavil tu nejlepší nemocnici, vydělat obrovské množství prašulí a mít neuvěřitelnou reputaci. " .. + "Očekává se, že také koupíte všechny pozemky, které můžete, všechno vyléčíte (a tím myslíme všechno) a vyhrajete všechna ocenění. " .. + "Myslíte, že na to máte?" .. + "Vydělejte 650,000€, vylečte 750 lidí, a mějte reputaci ve výši 800, abyste toto vyhráli.", + level17 = + "Malé varování - velmi si hlídejte Vaši reputaci - to je co pacienty přiláká z široko daleka do Vašeho zařízení. " .. + "Pokud nezabijete příliš mnoho lidí a udržíte je rozumně šťastné, neměli byste mít v této úrovni problémy!//" .. + "Teď jste v tom sami. Hodně štěstí a tak dále.", + level4 = + "Udržte všechny lidi šťastné, zacházejte s nimi tak dobře jak to jen a udržte úmrtí na absolutní minimum." .. + "Vaše reputace je v sázce, takže se ujistěte, že ji budete mít tak vysoko, jak je to jen možné. " .. + "O peníze se moc nestarejte - ty přijdou, jak Vaše důležitá reputace poroste. " .. + "Budete mít také možnost učit Doktory k rozšíření jejich schopností. " .. + "Mohli by mít na starost pacienta, který se zdá být méně neprůhledný, než většina. " .. + "Dosáhněte reputace přes 500.", + level13 = + "Vaše neuvěřitelné dovednosti správce nemocnice neunikly Zvláštnímu Tajnému Oddělení Zvláštní Tajné. " .. + "Mají pro Vás zvláštní bonus; je tu krysami zamořená nemocnice, která potřebuje účinného Terminátora. " .. + "Musíte zastřelit tolik krys, kolik můžete, než Údržbáři uklidí všechen bordel. " .. + "Myslíte, že to zvládnete?", + level6 = + "Použijte všechny Vaše znalosti k zřízení bezproblémové, dobře spravované nemocnice, která má zdravý příjem a může se vypořádat s čímkoliv, co na ní nemocná veřejnost může hodit. " .. + "Musíte si uvědomit, že zdejší atmosféra je zvláště vhodná k přenášení bacilů a infekcí. " .. + "Pokud nebudete Vaše zařízení udržovat až puntičkářsky čisté, můžete čelit řadě epidemií mezi pacienty. " .. + "Ujistěte se, že si vyděláte 150,000€ a že Vaše nemocnice má hodnotu přes 140,000€.", + level5 = + "Toto bude zaneprázdněná nemocnice, která bude řešit různé případy. " .. + "Vaši Doktoři jsou všichni přímo ze zdravotnické školy, takže bude zásadní vybudovat výukovou místnost a naučit je do přípustných úrovní. " .. + "Máte pouze tři Konzultanty, kteří Vám pomohou s výukou Vašich nezkušených zaměstnanců, takže je udržujte šťastné. " .. + "Nezapomeňte, také, že, základy této nemocnice sedí na geologickém zlomu San Robot. " .. + "Je tu vždy přítomné nebezpečí zemětřesení. " .. + "Způsobí vážné poškození Vašich přístrojů a naruší hladký chod Vaší nemocnice. " .. + "Dostaňte Vaši reputaci na značku 400, a uložte suprových 50,000€ abyste uspěli. Také, vylečte 200 pacientů.", + level8 = + "Je na Vás zřídit tu nejúčinnější a nákladově efektivní nemocnici, jak to jen jde. " .. + "lidé v tomto okolí se mají za dobře, takže z nich vymáčkněte tolik prašulí, kolik můžete. " .. + "Nezapomeňte, léčení lidí je sice hezké, ale opravdu POTŘEBUJETE peníze, které to přináší. " .. + "Vezměte tyto nemocné lidi do čistírny. " .. + "Nashromážděte ohromných 300,000€ k dokončení této úrovně.", + level7 = + "Zde budete pod pečlivou kontrolou z Ministerstva Zdravotnictví, takže se ujistěte, že Vaše účty ukazují, že vyděláváte hodně peněz a že Vaše reputace je ve výšinách. " .. + "Nemůžeme si dovolit zbytečná úmrtí - jsou špatná pro byznys. " .. + "Ujistěte se, že Vaši zaměstnanci jsou v nejlepší formě, a že máte veškeré vybavení, které potřebujete. " .. + "Dostaňte reputaci ve výši 600, plus 200,000€ v bance.", + level2 = + "V této oblasti je větší škála nemocí. " .. + "Postavte Vaši nemocnici, aby zvládla více pacientů a nachystejte se na vybudování Výzkumného Oddělení. " .. + "Nezapomeňte udržovat Vaše zařízení čisté a zkuste dostat vaši reputaci tak vysoko, jak to jen jde - budete čelit nemocem jako je Ochablý Jazyk, takže potřebujete Oddělení Ochablého Jazyka. " .. + "Můžete také postavit Kardiogram, aby Vám pomohl vyšetřit nové nemoci. " .. + "Obě tyto místnosti musí být vyzkoumány předtím, než je budete moci postavit. Nyní si také můžete zakoupit dodatečné parcely pozemků k rozšíření Vaší nemocnice - pro toto použijte Mapu Města. " .. + "Miřte k reputaci 300 a bankovní bilance 10,000€ a 40 vyléčeným lidem.", + level9 = + "Když jste naplnili bankovní účet Ministerstva a zaplatili a novou limuzínu pro samotného Ministra, nyní se můžete vrátit zpět k vytváření pečující, dobře zřízené nemocnice ve prospěch nemocných a potřebných. " .. + "Můžete očekávat, že se zde objeví spousta rozdílných problémů." .. + "Pokud máte dostatek dobře vyškolených zaměstnanců a místností, měli byste mít všechno pokryto. " .. + "Vaše nemocnice musí mít hodnotu 200,000€ a budete potřebovat 400,000€ v bance. " .. + "Cokoliv méně a nebudete moct dokončit úroveň.", + demo = + "Vítejte v demo nemocnici!//" .. + "Bohužel, demo verze obsahuje pouze tuto úroveň. Nicméně je toho více než dost, abyste se na chvilku zabavili! " .. + "Setkáte se s různými nemocemi, které potřebují různé místnosti k léčbě. Čas od času se můžou stát havárie. A budete potřebovat vyzkoumat dodatečné místnosti pomocí výzkumného oddělení. " .. + "Vaším úkolem je vydělat 100,000€, mít hodnotu nemocnice ve výši 70,000€ a reputaci 700, přičemž musíte vyléčit alespoň 75% Vašich pacientů. " .. + "Ujistěte se, že Vaše reputace nespadne 300 a že nezabijete více než 40% Vašich pacientů, nebo prohrajete.//" .. + "Hodně štěstí!", + level10 = + "Stejně jako zvládnutí všech nemocí, které se v této oblasti vyskytují, Ministerstvo žádá, abyste strávil nějaký čas soustředěním se na účinnost Vašich léků. " .. + "Z ČasNemoci, Hlídacího Psa Zdravotnictví, se ozívají jisté stížnosti, takže abyste vypadali dobře, musíte zajistit, že Vaše léky jsou mimořádně účinné. " .. + "Také zajistěte, aby Vaše nemocnice nemusela být kárána. Ať ty úmrtí nejsou vysoká. " .. + "Jako nápověda, možná byste měli vyhradit prostor pro Želé Nádrž. " .. + "Zdokonalte všechny Vaše léky na alespoň 80 procentní účinnost, mějte reputaci 650 a ukryjte 500,000€ v bance, abyste vyhráli. ", + level11 = + "Byla Vám dána šance vybudovat to nejlepší z nemocnic. " .. + "Toto je mimořádně prestižní oblast a Ministerstvo by rádo chtělo vidět tu nejlepší možnou nemocnici. " .. + "Očekáváme, že budete vydělávat velké peníze, mít skvostně vysokou reputaci a zvládat všechny možné případy. " .. + "Toto je důležitá práce. " .. + "Budete muset být něco zvláštního, abyste toto zvládli. " .. + "Nezapomeňte, také, že v oblasti byla zpozorována UFO. Ujistěte se, že Vaši zaměstnanci jsou připraveni na nečekané návštěvníky. " .. + "Vaše nemocnice potřebuje mít hodnotu 240,000€, v bance potřebujete 500,000€ a Vaše reputace bude potřeba být na 700.", + level3 = + "Tentokrát budete zřizovat nemocnici v zámožné oblasti. " .. + "Ministerstvo Zdravotnictví očekává od Vás, že zde zajistíte zdravý příjem. " .. + "Především budete muset získat dobrou reputaci, ale jakmile nemocnice běží naprázdno, soustřeďte se co nejvíce na vydělávání peněz. " .. + "Je tu také možnost výskytu Havárií. " .. + "To je tehdy, když velký počet lidí přijde najednou a všichni mají stejnou nemoc. " .. + "Vyléčení všech v časovém limitu Vám přidá lepší reputaci a velký bonus. " .. + "Nemoci jako Králův Komplex se mohou objevit a měli byste dát do rozpočtu výstavbu Operačního Sálu a Nemocničního Pokoje poblíž. " .. + "Vydělejte si 20,000€ abyste dosáhli další úrovně.", + level1 = + "Vítejte ve Vaší první nemocnici!//" .. + "Rozchoďte to tu umístěním Recepce, vybudováním Kanceláře Praktického Lékaře a najmutím Recepční a Doktora. " .. + "Pak počkejte, až přijde nějaký byznys." .. + "Je dobrý nápad postavit Odd. Psychiatrie a najmout Doktora s Psychiatrickými kvalifikacemi. " .. + "Lékárna a Sestra jsou také nutné k léčbě Vašich pacientů. " .. + "Dejte si pozor na ničemné případy Nafouknuté Hlavy - Nafukovárna je brzy spraví. " .. + "Budete chtít vyléčit 10 lidí a zajistit, že Vaše reputace nespadne pod 200.", } install = { th_directory = "CorsixTH potřebuje kopii datových souborů z původní hry Theme Hospital (nebo demoverze), aby mohla běžet. Prosím použijte okno níže k nalezení instalační složky Theme Hospital.", @@ -3233,5 +3241,54 @@ aliens = "PAcienti s mimozemskou DNA", fractured_bones = "Zlomené kosti", } - +custom_campaign_window = { + caption = "Vlastní kampaň", + start_selected_campaign = "Spustit kampaň", +} +warnings = { + levelfile_variable_is_deprecated = "Upozornění: Úroveň '%s' ve svém souboru obsahuje zastaralé určení proměnné.'%LevelFile' bylo přejmenováno na '%MapFile'. Pro aktualizaci úrovně prosím použijte editor map.", +} +map_editor_window = { + pages = { + paste = "Vložit oblast", + camera_3 = "Kamera 3", + hedgerow = "Živý plot", + delete_wall = "Smazat zdi", + road = "Silnice", + parcel_7 = "Parcela 7", + pond = "Rybníky", + heliport_3 = "Heliport 3", + outside = "Vnější prostory", + parcel_3 = "Parcela 3", + helipad = "Přistávací plocha", + parcel_1 = "Parcela 1", + heliport_4 = "Heliport 4", + parcel_6 = "Parcela 6", + foliage = "Rostliny", + parcel_2 = "Parcela 2", + parcel_5 = "Parcela 5", + parcel_4 = "Parcela 4", + parcel_0 = "Parcela 0", + north_wall = "Severní zeď", + inside = "Vnitřní prostory", + parcel_9 = "Parcela 9", + heliport_2 = "Heliport 2", + parcel_8 = "Parcela 8", + camera_4 = "Kamera 4", + camera_1 = "Kamera 1", + camera_2 = "Kamera 2", + west_wall = "Západní zeď", + heliport_1 = "Heliport 1", + }, +} +save_map_window = { + new_map = "Nová mapa", + caption = "Uložit mapu (%1%)", +} +menu_player_count = { + players_1 = " 1 HRÁČ ", + players_2 = " 2 HRÁČI ", + players_3 = " 3 HRÁČI ", + players_4 = " 4 HRÁČI ", +} diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/danish.lua corsix-th-0.62/CorsixTH/Lua/languages/danish.lua --- corsix-th-0.30/CorsixTH/Lua/languages/danish.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/danish.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ +--[[ Copyright (c) 2010 Robin Madsen (RobseRob) Copyright (c) 2010-2011 Ole Frandsen (Froksen) Copyright (c) 2011 Rene Bergfort (Kleeze) @@ -2445,129 +2445,111 @@ } - introduction_texts = { - level17 = { - [1] = "Dette er sidste advarsel - hold öje med dit omdömme - det er det, som tiltrækker patienter til dit hospital. ", - [2] = "Hvis der ikke dör for mange patienter og du samtidig holder resten af patienterne i nogenlunde godt humör, skulle denne bane ikke være noget problem.//", - [3] = "Nu må du klare dig selv. Held og lykke!", - }, - level1 = { - [1] = "Velkommen til dit förste hospital!//", - [2] = "Du kan komme godt fra start ved at ved at få placeret en reception, bygge en lægekonsultation og ansætte en læge og en receptionist. ", - [3] = "Derefter kan du åbne hospitalet, og de første patienter vil derefter begynde at ankomme til hospitalet.", - [4] = "Det vil være fornuftigt at bygge en psykiatri rimelig hurtigt og ansætte en læge med speciale i psykiatri. ", - [5] = "Et apotek og en sygeplejerske er essentielle for at helbrede dine patienter. Mange sygdomme behandles nemlig med medicin. ", - [6] = "Læg mærke til hvis der er mange tilfælde af opsvulmet hoved - et pumperum kan klare opgaven. ", - [7] = "For at gennemföre banen skal du helbrede mindst 10 patienter og sörge for, at dit omdömme ikke dykker under 200. ", - }, - level9 = { - [1] = "Efter du har fyldt ministerens bankkonto op og betalt for hans nye limousine, kan du nu koncentrere dig om at lave et omsorgsfuldt, velfungerende hospital for de trængende. ", - [2] = "Du må forvente at möde en række problemer her.", - [3] = "Hvis du har nok lokaler og flinke ansatte, vil du sikkert få styr på banens udfordringer. ", - [4] = "Dit hospital skal have en værdi af 200,000, og du skal have mindst 400,000 i banken. ", - [5] = "Mindre kan ikke göre det.", - }, - level2 = { - [1] = "Der er store problemer med sygdomme i dette område. ", - [2] = "Byg hospitalet med henblik på at behandle flere patienter og anlæg en forskningsafdeling. ", - [3] = "Husk at holde hospitalet rent og stræb efter at få så höjt et omdömme som muligt - hvis du vil kunne håndtere sygdomme som slap tunge, bliver det nödvendigt at bygge en tungeklinik. ", - [4] = "Du kan også bygge et löbebånd for at forbedre diagnosticeringen. Disse rum er först tilgængelige, når du har forsket i området i din forskningsafdeling. ", - [5] = "Du kan udvide hospitalet så du får mere plads at bygge på - brug oversigtskortet til dette ", - [6] = "Stræb efter at få et omdömme på 300 og en banksaldo på 10,000, samt helbrede mindst 40 patienter. ", - }, - level7 = { - [1] = "Her vil du være under overvågning af sundhedsmyndighederne, så husk at få det til at se ud som om du tjener kassen samtidig med at du opbygger et godt omdömme. ", - [2] = "Vi kan ikke holde til unödvendige dödsfald - de er dårlige for virksomheden. ", - [3] = "Vær sikker på at dit personale er i tip-top form, og at du har alt det udstyr, de har brug for. ", - [4] = "Opbyg dit omdömme til 600, og få 200,000 ind på din bankkonto.", - }, - level5 = { - [1] = "Dette bliver et travlt hospital, hvor du skal håndtere en lang række sager. ", - [2] = "Alle læger kommer direkte fra fakultetet, så det er vitalt, at du får bygget et undervisningsrum og uddanner lægerne så de bliver dygtigere, hurtigere og gerne så de får et speciale eller to. ", - [3] = "Du har kun tre konsulenter til at undervise dit uerfarende personale med, så hold dem glade. ", - [4] = "Hold for öje, at hospitalet er bygget på San Androids geologiske undergrund. ", - [5] = "Der er derfor en evig risiko for, at der kommer jordskælv. ", - [6] = "Jordskælv kan forårsage betydlig skade på dine maskiner og påvirke effektiviteten på dit hospital. ", - [7] = "Få dit omdömme op på 400 og din bankbalance op på 50,000 for at gennemföre banen. Du skal også helbrede 200 patienter.", - }, - level4 = { - [1] = "Hold alle dine patienter glade, få dem hurtigt igennem systemet og hold dödstallet så lavt som muligt.", - [2] = "Dit omdömme er på spil, sörg for at have et så godt omdömme som muligt.", - [3] = "Lad være med at fokusere for meget på pengene - de skal nok rulle ind i takt med dit stigende omdömme. ", - [4] = "Det vil være muligt for dig at undervise dine læger, så de kan udvikle deres evner og blive endnu hurtigere. ", - [5] = "Undervisningen varetages af konsulenter. Hvis de har særlige færdigheder som psykiater eller kirurg, vil deres elever med tiden også blive oplært i disse færdigheder. Og det kan de hurtigt få brug for, når patienter med mere krævende sygdomme begynder at ankomme. ", - [6] = "Opnå et omdömme på mere end 500.", - }, - level14 = { - [1] = "Der er lige en udfordring mere - det fuldstændigt uregerlige hospital. ", - [2] = "Hvis det lykkedes for dig at göre dette hospital til en succes, vil du være en mester af mestrene. ", - [3] = "Men forvent ikke, at du kan tage den på rutinen, for dette er den stöste udfordring, du nogensinde vil möde. ", - [4] = "Held og lykke!", - }, - level15 = { - [1] = "Sådan, det er det mest basale, som holder et hospital sammen.//", - [2] = "Dine læger får brug for al den hjælp de kan få til at diagosticere patienterne. Du kan hjælpe dig ved at", - [3] = "bygge andre diagnose faciliteter, så som et generel diagnoserum.", - }, - level8 = { - [1] = "Det er op til dig at skabe det mest effektive og produktive hospital som muligt. ", - [2] = "Folk fra dette område er ret velhavende, så pres dem for så mange penge som muligt. ", - [3] = "Husk: At helbrede folk er meget rart, men du har VIRKELIG BRUG FOR de penge det giver.", - [4] = "Flå disse patienter indtil selv Stein Bagger ville få moralske skrubler! ", - [5] = "Opnå et massivt overskud på 300,000 for at gennemföre denne bane.", - }, - level13 = { - [1] = "Dine fantastiske evner til at administrere et hospital, er blevet bemærket af en speciel hemmelig afdeling under hemmelige specielle afdelinger. ", - [2] = "De har en speciel bonus til dig; der er et rotteproblem på et hospital, som mangler en kærlig hånd. ", - [3] = "Du skal skyde så mange rotter som muligt för pedellerne kan rydde op i skidtet. ", - [4] = "Tror du, at du kan klare opgaven?", - }, - level16 = { - [1] = "Når du har diagnosticeret nogle af patienterne, bliver du nödt til at bygge behandlingsfaciliteter og klinikker til at helbrede dem - en godt sted at begynde med", - [2] = "er et apotek. Du skal bruge en sygeplejerske til at udlevere medicinen.", - }, - level6 = { - [1] = "Brug al din viden til at udvikle et velfungerende og komfortabelt hospital, som kan skabe et sundt overskud og håndtere alle former for sygdomme, som samfundet smider efter det. ", - [2] = "Du skal være opmærksom på, at atmosfæren i dette område er perfekt til at bære infektioner og sygdomme. ", - [3] = "Med mindre du holder dit hospital helt rent, risikerer du, at der udbryder epidemier blandt patienterne. ", - [4] = "Tjen 150,000 og forög hospitalets samlede værdi til 140,000.", - }, - level12 = { - [1] = "Du möder nu udfordringen over dem alle. ", - [2] = "Ministeriet er imponeret over dine succeser og har derfor et top-job til dig: De vil have dig til at bygge det ultimative hospital, hvor du skal tjene en pokkers masse penge og have et skyhöjt omdömme. ", - [3] = "Det forventes, at du köber alle bygninger, helbreder alle sygdomme (og vi mener alle!) og opnår banens mål og priser. ", - [4] = "Klar til udfordringen?", - [5] = "Tjen 650,000, helbred 750 personer, og få et omdömme på 800 for at gennemföre banen.", - }, - level3 = { - [1] = "Du vil denne gang skulle bygge dit hospital i et velhavende kvarter. ", - [2] = "Sundhedsmyndighederne holder öje med dig for at sikre, at du skaber et overskud her. ", - [3] = "Du begynder med et godt omdömme, men så snart hospitalet er åbent, skal du fokusere på at få tjent så mange penge som muligt. ", - [4] = "Der er også stor sandsynlighed for akuttilfælde. ", - [5] = "Disse indeholder et stort antal patienter, som ankommer samtidig og som alle har den samme sygdom. ", - [6] = "Hvis du helbreder dem indenfor tidsgrænsen, forbedrer det dit omdömme og modtager en stor bonus. Når du ikke at helbrede dem inden tiden löber ud, dör patienterne og dit omdömme falder. ", - [7] = "Sygdomme som kongekomplekset kan forekomme, og du bör bygge en operationsstue samt et sengeafsnit i nærheden af operationsstuen. ", - [8] = "Tjen 20,000 for at gennemföre banen.", - }, - level10 = { - [1] = "Såvel som at kunne behandle alle former for sygdomme, vil Sundhedsmyndighederne gerne have, at du bruger noget tid på at forske i effektiviteten af din medicin. ", - [2] = "Der har været nogle klager fra Foreningen af Syge, de syges vagthund. Så for at holde dit omdömme höjt skal du sörge for, at din medicin er effektiv. ", - [3] = "Du skal også sikre dig, at dit hospital er over gennemsnittet. Hold dödstallet så lavt som muligt", - [4] = "Et lille tip er at du holder lidt plads fri til et gelérör. ", - [5] = "Udvikl al din medicin til mindst 80% i effektivitet og få et omdömme på 650 og en bankbeholdning på 500,000 for at gennemföre banen. ", - }, - level11 = { - [1] = "Du har nu fået chancen for at bygge det ultimative hospital. ", - [2] = "Dette er et ekstremt velhavende område, hvor Sundhedsmyndighederne gerne vil sig, at der opföres det bedst mulige hospital. ", - [3] = "Vi forventer, at du tjener kassen, har et skyhöjt omdömme og håndterer alle uventede situationer. ", - [4] = "Dette er en vigtig opgave.", - [5] = "Du skal være lavet af noget specielt for at dette skal lykkedes. ", - [6] = "Bemærk, at en UFO er set i området. Så forbered dit personale på uventet besög. ", - [7] = "Dit hospital skal være mindst 240,000 værd, og du skal have mindst 500,000 i banken samt et omdömme på 700 för syndhedsmyndighederne er tilfredse.", - }, - level18 = { - }, - } +introduction_texts = { + level17 = + "Dette er sidste advarsel - hold öje med dit omdömme - det er det, som tiltrækker patienter til dit hospital. " .. + "Hvis der ikke dör for mange patienter og du samtidig holder resten af patienterne i nogenlunde godt humör, skulle denne bane ikke være noget problem.//" .. + "Nu må du klare dig selv. Held og lykke!", + level1 = + "Velkommen til dit förste hospital!//" .. + "Du kan komme godt fra start ved at ved at få placeret en reception, bygge en lægekonsultation og ansætte en læge og en receptionist. " .. + "Derefter kan du åbne hospitalet, og de første patienter vil derefter begynde at ankomme til hospitalet." .. + "Det vil være fornuftigt at bygge en psykiatri rimelig hurtigt og ansætte en læge med speciale i psykiatri. " .. + "Et apotek og en sygeplejerske er essentielle for at helbrede dine patienter. Mange sygdomme behandles nemlig med medicin. " .. + "Læg mærke til hvis der er mange tilfælde af opsvulmet hoved - et pumperum kan klare opgaven. " .. + "For at gennemföre banen skal du helbrede mindst 10 patienter og sörge for, at dit omdömme ikke dykker under 200. ", + level9 = + "Efter du har fyldt ministerens bankkonto op og betalt for hans nye limousine, kan du nu koncentrere dig om at lave et omsorgsfuldt, velfungerende hospital for de trængende. " .. + "Du må forvente at möde en række problemer her." .. + "Hvis du har nok lokaler og flinke ansatte, vil du sikkert få styr på banens udfordringer. " .. + "Dit hospital skal have en værdi af 200,000, og du skal have mindst 400,000 i banken. " .. + "Mindre kan ikke göre det.", + level2 = + "Der er store problemer med sygdomme i dette område. " .. + "Byg hospitalet med henblik på at behandle flere patienter og anlæg en forskningsafdeling. " .. + "Husk at holde hospitalet rent og stræb efter at få så höjt et omdömme som muligt - hvis du vil kunne håndtere sygdomme som slap tunge, bliver det nödvendigt at bygge en tungeklinik. " .. + "Du kan også bygge et löbebånd for at forbedre diagnosticeringen. Disse rum er först tilgængelige, når du har forsket i området i din forskningsafdeling. " .. + "Du kan udvide hospitalet så du får mere plads at bygge på - brug oversigtskortet til dette " .. + "Stræb efter at få et omdömme på 300 og en banksaldo på 10,000, samt helbrede mindst 40 patienter. ", + level7 = + "Her vil du være under overvågning af sundhedsmyndighederne, så husk at få det til at se ud som om du tjener kassen samtidig med at du opbygger et godt omdömme. " .. + "Vi kan ikke holde til unödvendige dödsfald - de er dårlige for virksomheden. " .. + "Vær sikker på at dit personale er i tip-top form, og at du har alt det udstyr, de har brug for. " .. + "Opbyg dit omdömme til 600, og få 200,000 ind på din bankkonto.", + level5 = + "Dette bliver et travlt hospital, hvor du skal håndtere en lang række sager. " .. + "Alle læger kommer direkte fra fakultetet, så det er vitalt, at du får bygget et undervisningsrum og uddanner lægerne så de bliver dygtigere, hurtigere og gerne så de får et speciale eller to. " .. + "Du har kun tre konsulenter til at undervise dit uerfarende personale med, så hold dem glade. " .. + "Hold for öje, at hospitalet er bygget på San Androids geologiske undergrund. " .. + "Der er derfor en evig risiko for, at der kommer jordskælv. " .. + "Jordskælv kan forårsage betydlig skade på dine maskiner og påvirke effektiviteten på dit hospital. " .. + "Få dit omdömme op på 400 og din bankbalance op på 50,000 for at gennemföre banen. Du skal også helbrede 200 patienter.", + level4 = + "Hold alle dine patienter glade, få dem hurtigt igennem systemet og hold dödstallet så lavt som muligt." .. + "Dit omdömme er på spil, sörg for at have et så godt omdömme som muligt." .. + "Lad være med at fokusere for meget på pengene - de skal nok rulle ind i takt med dit stigende omdömme. " .. + "Det vil være muligt for dig at undervise dine læger, så de kan udvikle deres evner og blive endnu hurtigere. " .. + "Undervisningen varetages af konsulenter. Hvis de har særlige færdigheder som psykiater eller kirurg, vil deres elever med tiden også blive oplært i disse færdigheder. Og det kan de hurtigt få brug for, når patienter med mere krævende sygdomme begynder at ankomme. " .. + "Opnå et omdömme på mere end 500.", + level14 = + "Der er lige en udfordring mere - det fuldstændigt uregerlige hospital. " .. + "Hvis det lykkedes for dig at göre dette hospital til en succes, vil du være en mester af mestrene. " .. + "Men forvent ikke, at du kan tage den på rutinen, for dette er den stöste udfordring, du nogensinde vil möde. " .. + "Held og lykke!", + level15 = + "Sådan, det er det mest basale, som holder et hospital sammen.//" .. + "Dine læger får brug for al den hjælp de kan få til at diagosticere patienterne. Du kan hjælpe dig ved at" .. + "bygge andre diagnose faciliteter, så som et generel diagnoserum.", + level8 = + "Det er op til dig at skabe det mest effektive og produktive hospital som muligt. " .. + "Folk fra dette område er ret velhavende, så pres dem for så mange penge som muligt. " .. + "Husk: At helbrede folk er meget rart, men du har VIRKELIG BRUG FOR de penge det giver." .. + "Flå disse patienter indtil selv Stein Bagger ville få moralske skrubler! " .. + "Opnå et massivt overskud på 300,000 for at gennemföre denne bane.", + level13 = + "Dine fantastiske evner til at administrere et hospital, er blevet bemærket af en speciel hemmelig afdeling under hemmelige specielle afdelinger. " .. + "De har en speciel bonus til dig; der er et rotteproblem på et hospital, som mangler en kærlig hånd. " .. + "Du skal skyde så mange rotter som muligt för pedellerne kan rydde op i skidtet. " .. + "Tror du, at du kan klare opgaven?", + level16 = + "Når du har diagnosticeret nogle af patienterne, bliver du nödt til at bygge behandlingsfaciliteter og klinikker til at helbrede dem - en godt sted at begynde med" .. + "er et apotek. Du skal bruge en sygeplejerske til at udlevere medicinen.", + level6 = + "Brug al din viden til at udvikle et velfungerende og komfortabelt hospital, som kan skabe et sundt overskud og håndtere alle former for sygdomme, som samfundet smider efter det. " .. + "Du skal være opmærksom på, at atmosfæren i dette område er perfekt til at bære infektioner og sygdomme. " .. + "Med mindre du holder dit hospital helt rent, risikerer du, at der udbryder epidemier blandt patienterne. " .. + "Tjen 150,000 og forög hospitalets samlede værdi til 140,000.", + level12 = + "Du möder nu udfordringen over dem alle. " .. + "Ministeriet er imponeret over dine succeser og har derfor et top-job til dig: De vil have dig til at bygge det ultimative hospital, hvor du skal tjene en pokkers masse penge og have et skyhöjt omdömme. " .. + "Det forventes, at du köber alle bygninger, helbreder alle sygdomme (og vi mener alle!) og opnår banens mål og priser. " .. + "Klar til udfordringen?" .. + "Tjen 650,000, helbred 750 personer, og få et omdömme på 800 for at gennemföre banen.", + level3 = + "Du vil denne gang skulle bygge dit hospital i et velhavende kvarter. " .. + "Sundhedsmyndighederne holder öje med dig for at sikre, at du skaber et overskud her. " .. + "Du begynder med et godt omdömme, men så snart hospitalet er åbent, skal du fokusere på at få tjent så mange penge som muligt. " .. + "Der er også stor sandsynlighed for akuttilfælde. " .. + "Disse indeholder et stort antal patienter, som ankommer samtidig og som alle har den samme sygdom. " .. + "Hvis du helbreder dem indenfor tidsgrænsen, forbedrer det dit omdömme og modtager en stor bonus. Når du ikke at helbrede dem inden tiden löber ud, dör patienterne og dit omdömme falder. " .. + "Sygdomme som kongekomplekset kan forekomme, og du bör bygge en operationsstue samt et sengeafsnit i nærheden af operationsstuen. " .. + "Tjen 20,000 for at gennemföre banen.", + level10 = + "Såvel som at kunne behandle alle former for sygdomme, vil Sundhedsmyndighederne gerne have, at du bruger noget tid på at forske i effektiviteten af din medicin. " .. + "Der har været nogle klager fra Foreningen af Syge, de syges vagthund. Så for at holde dit omdömme höjt skal du sörge for, at din medicin er effektiv. " .. + "Du skal også sikre dig, at dit hospital er over gennemsnittet. Hold dödstallet så lavt som muligt" .. + "Et lille tip er at du holder lidt plads fri til et gelérör. " .. + "Udvikl al din medicin til mindst 80% i effektivitet og få et omdömme på 650 og en bankbeholdning på 500,000 for at gennemföre banen. ", + level11 = + "Du har nu fået chancen for at bygge det ultimative hospital. " .. + "Dette er et ekstremt velhavende område, hvor Sundhedsmyndighederne gerne vil sig, at der opföres det bedst mulige hospital. " .. + "Vi forventer, at du tjener kassen, har et skyhöjt omdömme og håndterer alle uventede situationer. " .. + "Dette er en vigtig opgave." .. + "Du skal være lavet af noget specielt for at dette skal lykkedes. " .. + "Bemærk, at en UFO er set i området. Så forbered dit personale på uventet besög. " .. + "Dit hospital skal være mindst 240,000 værd, og du skal have mindst 500,000 i banken samt et omdömme på 700 för syndhedsmyndighederne er tilfredse.", + level18 = "", +} -- Miscellangelous -- Category of strings that fit nowhere else or we are not sure where they belong. @@ -2656,3 +2638,67 @@ adviser.room_requirements.op_need_two_surgeons = "Ansæt to kirurger for at kunne udföre operationer." adviser.room_requirements.training_room_need_consultant = "Du skal ansætte en konsulent til at undervise i undervisningslokalet." adviser.room_requirements.gps_office_need_doctor = "Du skal ansætte en læge til at arbejde i lægekonsultationen." + +confirmation.maximum_screen_size = "Skærmopløsningen du har valgt er større end 3000 x 2000. Større opløsninger kan bruges men vil kræve bedre hardware for at køre med en spilbar FPS. Er du sikker på du vil fortsætte?" +confirmation.music_warning = "Før du vælger at bruge mp3'er til musikken i spillet, har du brug for smpeg.dll eller lignende til dit styresystem, ellers vil du ikke have musik i spillet. Vil du fortsætte?" +menu_options_wage_increase.deny = " AFVIS " +menu_options_wage_increase.grant = " TILLAD " +tooltip.options_window.audio_button = "Slå alle lyde til og fra i spillet " +tooltip.options_window.audio_toggle = "Slå til og fra" +tooltip.options_window.folder_button = "Mappeindstillinger" +tooltip.options_window.customise_button = "Flere indstillinger som du kan ændre for at tilpasse din spiloplevelse." +tooltip.update_window.download = "Gå til downloadsiden for den nyeste version af CorsixTH" +tooltip.update_window.ignore = "Ignorer denne opdatering for nu. Du vil blive påmindet igen næste gang du åbner CorsixTH" +tooltip.folders_window.browse_font = "Led efter en anden skrifttype fil ( nuværende placering: %1% )" +tooltip.folders_window.screenshots_location = "Normalt er skærmbilleder gemt i samme mappe som konfigurationsfilen. Hvis du gerne vil have skærmbilleder gemt et andet sted, skal du blot navigere til den pågældende mappe." +tooltip.folders_window.reset_to_default = "Gendan biblioteket til standard placeringen" +tooltip.folders_window.back = "Luk denne menu og gå tilbage til indstillinger" +tooltip.folders_window.browse = "Find placering af mappe" +tooltip.folders_window.browse_screenshots = "Find en anden mappe til dine skærmbilleder ( nuværende placering: %1% ) " +tooltip.folders_window.browse_music = "Find en anden mappe til dine lydfiler ( nuværende placering: %1% ) " +tooltip.folders_window.no_font_specified = "Du har ikke valgt en skrifttype-placering endnu!" +tooltip.folders_window.not_specified = "Du har ikke valgt en mappeplacering endnu!" +tooltip.folders_window.browse_saves = "Find en anden mappe til din gemte spil ( nuværende placering %1% ) " +tooltip.folders_window.default = "Standard lokation" +tooltip.folders_window.data_location = "Placeringen af den originale Theme Hospital installation som kræves for at køre CorsixTH" +tooltip.customise_window.back = "Luk denne menu og gå tilbage til indstillinger" +tooltip.customise_window.movies = "Global film kontrol, dette vil tillade dig at deaktivere alle film" +update_window.caption = "Ny opdatering klar!" +update_window.new_version = "Ny Version:" +update_window.current_version = "Nuværende Version:" +update_window.download = "Gå til downloadsiden" +update_window.ignore = "Spring over og gå til hovedmenu" +errors.fractured_bones = "NOTE: Animationen for kvindelige patienter med brækkede knogler er ikke perfekt" +folders_window.data_label = "TH Data" +folders_window.music_location = "Vælg mappen du vil bruge til dit musik" +folders_window.music_label = "MP3'er" +folders_window.caption = "Mappe placeringer" +folders_window.screenshots_label = "Skærmbilleder" +folders_window.font_label = "Skrifttype" +folders_window.savegames_label = "Gemte spil" +folders_window.back = "Tilbage" +folders_window.savegames_location = "Vælg mappen du vil bruge til dine gemte spil" +folders_window.screenshots_location = "Vælg mappen du vil bruge til dine skærmbilleder" +customise_window.average_contents = "Average contents" +customise_window.option_on = "Til" +customise_window.paused = "Byggeproces sat på pause" +customise_window.option_off = "Fra" +customise_window.intro = "Afspil Introfilmen" +customise_window.caption = "Brugerdefineret indstillinger" +customise_window.back = "Tilbage" +customise_window.movies = "Global film kontrol" +customise_window.volume = "Volume ned tast" +customise_window.aliens = "Fremmede patienter" +customise_window.fractured_bones = "Brækkede knogler" +options_window.folder = "Mapper" +options_window.customise = "Tilpasse" +options_window.audio = "Global Lyd" +menu_options.twentyfour_hour_clock = " 24-TIMERS UR " +menu_options.wage_increase = " LØN ANMODNING" +install.ok = "OK" +install.cancel = "Anullér" +adviser.research.drug_improved_1 = "%s medicin er blevet forbædret af din forskningsafdeling." +adviser.warnings.researcher_needs_desk_1 = "En Forsker har brug for et bord til at arbejde ved." +adviser.warnings.nurse_needs_desk_1 = "Hver Sygeplejerske har brug sit eget bord til at arbejde fra." +adviser.warnings.no_desk_5 = "Nu er det ved at være på tide, du burde snart se patienter ankomme!" +adviser.warnings.no_desk_4 = "En receptionist skal have sit eget bord for at tage imod nye patienter" diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/developer.lua corsix-th-0.62/CorsixTH/Lua/languages/developer.lua --- corsix-th-0.30/CorsixTH/Lua/languages/developer.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/developer.lua 2018-07-21 11:13:17.000000000 +0000 @@ -26,9 +26,10 @@ Inherit("english") -local function fixup(t, name) +--! Construct a 'translation' with the string names as text value. +local function fixup(t, str_name) for k, v in pairs(t) do - local name = name .. "." .. k + local name = str_name .. "." .. k if type(v) == "string" then t[k] = name else diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/dutch.lua corsix-th-0.62/CorsixTH/Lua/languages/dutch.lua --- corsix-th-0.30/CorsixTH/Lua/languages/dutch.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/dutch.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010 RAS +--[[ Copyright (c) 2010 RAS 2011 FlyingBastard, L_konings, Nossah, KasperVld 2012-2013 Omni, Maarten @@ -815,6 +815,8 @@ all_research = "Voltooi al het onderzoek", end_year = "Spring naar het einde van het jaar.", earthquake = "Creëer een aardbeving", + epidemic = "Maakt een besmette patient aan die mogelijk een epidemie veroorzaakt", + toggle_infected = "Aan/uit zetten van weergave van geïnfecteerden van de ontdekte epidemie", }, }, new_game_window = { @@ -1372,6 +1374,7 @@ no_treatment_available = "Geen behandeling beschikbaar; ik ga naar huis", on_my_way_to = "Onderweg naar %s", queueing_for = "In de rij voor %s", + epidemic_vaccinated = "Ik ben niet langer besmettelijk", }, diagnosed = "Diagnose: %s ", }, @@ -1841,141 +1844,122 @@ }, } introduction_texts = { - level17 = { - [1] = "Nog een laatste waarschuwing: hou een oogje op je reputatie. Je reputatie is namelijk iets wat patiënten van heinde en verre naar je ziekenhuis laat komen. ", - [2] = "Als je niet teveel mensen doodt en ze redelijk gelukkig houdt, zou je niet al teveel problemen moeten hebben met dit level!//", - [3] = "En nu mag je het zelf opknappen. Veel succes ermee!", - }, - level1 = { - [1] = "Welkom in je eerste ziekenhuis!", - [2] = "Zorg dat de boel op gang komt door een receptie te plaatsen en een spreekkamer te bouwen. Neem ook een receptioniste en een arts in dienst. ", - [3] = "Wacht dan tot er mensen langskomen.", - [4] = "Het is een goed idee om een psychiatrische afdeling te bouwen en een arts in te huren met de benodigde kwalificaties. ", - [5] = "Een apotheek en een zuster zijn essentieel voor het genezen van je patiënten. ", - [6] = "Kijk uit voor ernstige gevallen van plofkop. Een inflatiekliniek lost deze probleempjes op. ", - [7] = "Genees, om de spits af te bijten, 10 mensen en hou je reputatie boven de 200.", - }, - level9 = { - [1] = "Nu je de kas van het ministerie flink hebt gespekt en de minister dankzij jouw donaties vrolijk in zijn splinternieuwe limousine rondrijdt, kun je nu weer terug naar je echte taak: het bouwen van een ziekenhuis dat niet alleen goed draait maar ook duidelijk om haar arme en zieke patiënten geeft.", - [2] = "Verwacht dat er een boel problemen de kop opsteken.", - [3] = "Als je genoeg kamers en een goed getrainde staf hebt, zal je die problemen makkelijk het hoofd moeten kunnen bieden. ", - [4] = "Je ziekenhuis moet uiteindelijk $200,000 waard zijn. Verzamel ook een comfortabele $400.000 op je bankrekening. ", - [5] = "Met minder dan dat kun je het level niet uitspelen.", - }, - level2 = { - [1] = "Er zijn hier in de omgeving een stuk meer ziektes. ", - [2] = "Zet je ziekenhuis zo op dat je de grotere hoeveelheid patiënten kunt behapstukken en bouw ook nog een laboratorium. ", - [3] = "Hou je ziekenhuis schoon en je reputatie zo hoog mogelijk. Je zult te maken krijgen met ziektes zoals lamme tong, dus je hebt een lamme tongkliniek nodig. ", - [4] = "Je hebt ook een cardio nodig zodat je betere diagnoses kunt stellen en nieuwe ziektes kunt ontdekken. ", - [5] = "Beide kamers moeten worden onderzocht voor je ze kunt bouwen. Je kunt nu ook extra gebouwen kopen om je ziekenhuis uit te breiden. Gebruik hier het kaartscherm voor. ", - [6] = "Probeer een reputatie van 300 te behalen, een saldo van 10,000 op de teller te hebben staan en 40 mensen te genezen.", - }, - level7 = { - [1] = "Je wordt in de gaten gehouden door het Ministerie van Volksgezondheid, dus zorg ervoor dat je flinke winst draait en dat je reputatie constant hoog blijft. ", - [2] = "We kunnen ons geen doden veroorloven; dat is slecht voor zaken. ", - [3] = "Zorg dat je personeel in vorm is en dat je alle apparatuur hebt die nodig is. ", - [4] = "Zorg voor een reputatie van 600 en een saldo $200.000.", - }, - level5 = { - [1] = "Dit wordt een druk ziekenhuis met een grote variatie aan ziektebeelden. ", - [2] = "Je artsen komen allemaal net van school af, dus bouw een klaslokaal en geef ze een opleiding tot een acceptabel niveau. ", - [3] = "Je hebt maar drie specialisten om de rest van je personeel op te leiden, dus hou ze tevreden. ", - [4] = "Daarbij is je ziekenhuis gebouwd op de San Androïde-breuk. ", - [5] = "Aardbevingen kunnen dus elk moment toeslaan. ", - [6] = "Deze zullen je machines beschadigen en je goedlopende ziekenhuis flink verstoren. ", - [7] = "Bouw je reputatie op tot boven de 400 en zorg voor een nette $50.000 op je bankrekening. Zorg daarnaast dat je 200 patiënten geneest.", - }, - level4 = { - [1] = "Hou al je patiënten tevreden en werk ze zo efficiënt mogelijk af. Voorkom sterfgevallen zoveel mogelijk.", - [2] = "Je reputatie staat op het spel, dus hou die zo hoog mogelijk. ", - [3] = "Maak je niet al teveel zorgen over geld; dat komt wel als die o zo belangrijke reputatie groeit. ", - [4] = "Je kunt nu je ook artsen trainen, zodat ze beter gekwalificeerd zullen zijn. ", - [5] = "Waarschijnlijk zal je heel wat patiënten tegenkomen die nogal doorzichtig zijn. ", - [6] = "Bouw je reputatie op tot deze de 500 heeft bereikt.", - }, + level17 = + "Nog een laatste waarschuwing: hou een oogje op je reputatie. Je reputatie is namelijk iets wat patiënten van heinde en verre naar je ziekenhuis laat komen. " .. + "Als je niet teveel mensen doodt en ze redelijk gelukkig houdt, zou je niet al teveel problemen moeten hebben met dit level!//" .. + "En nu mag je het zelf opknappen. Veel succes ermee!", + level1 = + "Welkom in je eerste ziekenhuis!//" .. + "Zorg dat de boel op gang komt door een receptie te plaatsen en een spreekkamer te bouwen. Neem ook een receptioniste en een arts in dienst. " .. + "Wacht dan tot er mensen langskomen. " .. + "Het is een goed idee om een psychiatrische afdeling te bouwen en een arts in te huren met de benodigde kwalificaties. " .. + "Een apotheek en een zuster zijn essentieel voor het genezen van je patiënten. " .. + "Kijk uit voor ernstige gevallen van plofkop. Een inflatiekliniek lost deze probleempjes op. " .. + "Genees, om de spits af te bijten, 10 mensen en hou je reputatie boven de 200.", + level9 = + "Nu je de kas van het ministerie flink hebt gespekt en de minister dankzij jouw donaties vrolijk in zijn splinternieuwe limousine rondrijdt, kun je nu weer terug naar je echte taak: het bouwen van een ziekenhuis dat niet alleen goed draait maar ook duidelijk om haar arme en zieke patiënten geeft. " .. + "Verwacht dat er een boel problemen de kop opsteken. " .. + "Als je genoeg kamers en een goed getrainde staf hebt, zal je die problemen makkelijk het hoofd moeten kunnen bieden. " .. + "Je ziekenhuis moet uiteindelijk $200,000 waard zijn. Verzamel ook een comfortabele $400.000 op je bankrekening. " .. + "Met minder dan dat kun je het level niet uitspelen.", + level2 = + "Er zijn hier in de omgeving een stuk meer ziektes. " .. + "Zet je ziekenhuis zo op dat je de grotere hoeveelheid patiënten kunt behapstukken en bouw ook nog een laboratorium. " .. + "Hou je ziekenhuis schoon en je reputatie zo hoog mogelijk. Je zult te maken krijgen met ziektes zoals lamme tong, dus je hebt een lamme tongkliniek nodig. " .. + "Je hebt ook een cardio nodig zodat je betere diagnoses kunt stellen en nieuwe ziektes kunt ontdekken. " .. + "Beide kamers moeten worden onderzocht voor je ze kunt bouwen. Je kunt nu ook extra gebouwen kopen om je ziekenhuis uit te breiden. Gebruik hier het kaartscherm voor. " .. + "Probeer een reputatie van 300 te behalen, een saldo van 10,000 op de teller te hebben staan en 40 mensen te genezen.", + level7 = + "Je wordt in de gaten gehouden door het Ministerie van Volksgezondheid, dus zorg ervoor dat je flinke winst draait en dat je reputatie constant hoog blijft. " .. + "We kunnen ons geen doden veroorloven; dat is slecht voor zaken. " .. + "Zorg dat je personeel in vorm is en dat je alle apparatuur hebt die nodig is. " .. + "Zorg voor een reputatie van 600 en een saldo $200.000.", + level5 = + "Dit wordt een druk ziekenhuis met een grote variatie aan ziektebeelden. " .. + "Je artsen komen allemaal net van school af, dus bouw een klaslokaal en geef ze een opleiding tot een acceptabel niveau. " .. + "Je hebt maar drie specialisten om de rest van je personeel op te leiden, dus hou ze tevreden. " .. + "Daarbij is je ziekenhuis gebouwd op de San Androïde-breuk. " .. + "Aardbevingen kunnen dus elk moment toeslaan. " .. + "Deze zullen je machines beschadigen en je goedlopende ziekenhuis flink verstoren. " .. + "Bouw je reputatie op tot boven de 400 en zorg voor een nette $50.000 op je bankrekening. Zorg daarnaast dat je 200 patiënten geneest.", + level4 = + "Hou al je patiënten tevreden en werk ze zo efficiënt mogelijk af. Voorkom sterfgevallen zoveel mogelijk." .. + "Je reputatie staat op het spel, dus hou die zo hoog mogelijk. " .. + "Maak je niet al teveel zorgen over geld; dat komt wel als die o zo belangrijke reputatie groeit. " .. + "Je kunt nu je ook artsen trainen, zodat ze beter gekwalificeerd zullen zijn. " .. + "Waarschijnlijk zal je heel wat patiënten tegenkomen die nogal doorzichtig zijn. " .. + "Bouw je reputatie op tot deze de 500 heeft bereikt.", --[[ Level 13 and 14 are rat shooting galleries and are thus not available through the File menu as of yet. --]] - level14 = { - [1] = "Je hebt nog een uitdaging gekregen; een compleet onverwacht verrassingsziekenhuis! ", - [2] = "Als je hier een succes van kunt maken ben je de winnaar van alle winnaars. ", - [3] = "Maar denk niet dat het een eitje is. Het is de moeilijkste opdracht die je ooit zult aannemen. ", - [4] = "Veel succes!", - }, + level14 = + "Je hebt nog een uitdaging gekregen; een compleet onverwacht verrassingsziekenhuis! " .. + "Als je hier een succes van kunt maken ben je de winnaar van alle winnaars. " .. + "Maar denk niet dat het een eitje is. Het is de moeilijkste opdracht die je ooit zult aannemen. " .. + "Veel succes!", --[[ Level 15 is most likely just removed content. I translated it as usual just in case the team finds something to do with it. --]] - level15 = { - [1] = "Goed, dat is dus de basis van een ziekenhuis bouwen.//", - [2] = "Je artsen zullen alle hulp nodig hebben die ze kunnen gebruiken bij het stellen van diagnoses. Je kunt ze helpen ", - [3] = "door meerdere diagnostische kamers te bouwen, zoals de algemene diagnose.", - }, - level8 = { - [1] = "Het is aan jou om het meeste efficiënte ziekenhuis op te zetten voor zo weinig mogelijk geld. ", - [2] = "De mensen zitten hier goed in de slappe was, dus pers zoveel mogelijk geld uit ze als mogelijk is. ", - [3] = "Ja, mensen genezen is heel leuk, maar je hebt het geld dat ze binnenbrengen echt NODIG. ", - [4] = "Schudt die zieke mensen dus maar flink uit. ", - [5] = "Verzamel een fortuin van $300.000 om dit level uit te spelen.", - }, - level13 = { - [1] = "Je fantastische werk als directeur is ondertussen bij de Speciale Geheime Divisie van de Geheime Speciale Dienst bekend. ", - [2] = "Ze hebben een bonus voor je; er is een ziekenhuis geïnfecteerd met ratten en ze hebben een echte Terminator nodig. ", - [3] = "Vermorzel zoveel mogelijk ratten voordat de conciërges de boel hebben opgeruimd. ", - [4] = "Denk je dat je die taak aankunt?", - }, - level16 = { - [1] = "Zodra je wat diagnoses hebt gesteld zal je behandelkamers en klinieken moeten bouwen om voor de mensen te zorgen. Een goede om mee te beginnen is de apotheek. ", - [2] = "Je moet ook een zuster inhuren zodat ze de verschillende medicijnen kan toedienen.", - }, - level6 = { - [1] = "Gebruik al je kennis om je ziekenhuis soepel te laten draaien, een gezonde winst te maken en alle ziektes te genezen die de mensen met zich meedragen. ", - [2] = "Wees je ervan bewust dat de atmosfeer hier erg geschikt is voor het overdragen van bacteriën en infecties. ", - [3] = "Hou je ziekenhuis dus schoon, tenzij je een lange rits van epidemieën onder je patiënten wilt brengen. ", - [4] = "Zorg ervoor dat je $150.000 verdient en dat je ziekenhuis meer dan $140.000 waard is.", - }, - level12 = { - [1] = "Dit is de moeder van alle uitdagingen. ", - [2] = "Het ministerie is zo onder de indruk van je succes, dat ze je de hoogste positie hebben aangeboden. Ze willen iemand hebben die nog een ultiem ziekenhuis kan bouwen, veel geld kan verdienen en een fantastische reputatie kan opbouwen. ", - [3] = "Je wordt verwacht alle, maar dan ook echt alle ziektes te kunnen genezen en alle prijzen in de wacht te slepen. ", - [4] = "Denk je dat je dat aankunt?", - [5] = "Verdien $650.000, genees 750 mensen en verdien krijg een reputatie van 800 om dit te winnen.", - }, - level3 = { - [1] = "Dit keer bouw je een ziekenhuis in een rijke buurt. ", - [2] = "Het Ministerie van Volksgezondheid vraagt een gezonde winst van je. ", - [3] = "Je zult eerst een goede reputatie moeten opbouwen, maar schakel zodra je ziekenhuis volloopt over op zoveel mogelijk geld binnenhalen. ", - [4] = "Er kunnen zich ook noodgevallen voordoen. ", - [5] = "Dit zijn gevallen waarin er meerdere patiënten binnenkomen met dezelfde ziekte. ", - [6] = "Als je ze allemaal binnen een bepaalde tijd geneest, zit er een vette bonus aan vast en gaat je reputatie erop vooruit. ", - [7] = "Ziektes als het King Complex kunnen voorkomen en er wordt aangeraden om wat geld opzij te zetten voor een operatiekamer in de buurt van een slaapzaal. ", - [8] = "Verdien $20.000 om het level te halen.", - }, - level10 = { - [1] = "Het ministerie vraagt nu niet alleen dat je alle ziektes in deze buurt aanpakt, maar ook dat je je concentreert op de efficiëntie van je medicijnen. ", - [2] = "Er zijn wat klachten binnengekomen van Ofziek, de waakhond van de gezondheidszorg, dus als je goed over wil komen, zorg je ervoor dat je medicijnen goed werken. ", - [3] = "Zorg ook dat er niets te klagen valt over je ziekenhuis zelf. Hou die sterfgevallen zeldzaam. ", - [4] = "Hint: Hou wat ruimte vrij voor een gelatinetank. ", - [5] = "Ontwikkel al je medicijnen door tot ze ten minste 80 procent effectief zijn, behaal een reputatie van 650 en behaal een saldo van $500.000. ", - }, - level11 = { - [1] = "Je hebt de kans gekregen het ultieme ziekenhuis te bouwen. ", - [2] = "Dit is een zeer prestigieuze omgeving, en het ministerie wil een zo goed mogelijk ziekenhuis zien. ", - [3] = "We verwachten dat je flink geld binnenhaalt, een fantastische reputatie hebt en elke situatie aan kunt. ", - [4] = "Dit is een belangrijke taak. ", - [5] = "Je bent heel wat als je dit lukt. ", - [6] = "Opmerkenswaardig is dat er UFO's in de omgeving gezien zijn. Zorg ervoor dat je personeel klaar is voor onverwachte bezoekers. ", - [7] = "Je ziekenhuis moet $240.000 waard zijn en je moet $500.000 op de bank hebben staan. Ook moet je reputatie minimaal 700 bedragen.", - }, - level18 = { - }, - demo = { - [1] = "Welkom in het demo ziekenhuis!", - [2] = "Jammer genoeg bevat de demo versie buiten zelfgemaakte levels alleen dit ziekenhuis, maar er is meer dan genoeg te doen om je voorlopig bezig te houden!", - [3] = "Je zult verschillende kwalen tegenkomen die verschillende ruimtes nodig hebben om genezen te worden, af en toe kunnen zich noodgevallen voordoen, en je zult nieuwe ruimtes uit moeten vinden met het laboratorium", - [4] = "Jouw doel is om $100,000 te verdienen, de waarde van je ziekenhuis te verhogen naar $70,000 en een reputatie van 700 te behalen, terwijl je 75% van je patiënten geneest", - [5] = "Zorg er voor dat je reputatie niet lager wordt dan 300 en dat je niet meer dan 40% van je patiënten vermoord, anders zal je ontslagen worden!", - [6] = "Succes!", - }, + level15 = + "Goed, dat is dus de basis van een ziekenhuis bouwen.//" .. + "Je artsen zullen alle hulp nodig hebben die ze kunnen gebruiken bij het stellen van diagnoses. Je kunt ze helpen " .. + "door meerdere diagnostische kamers te bouwen, zoals de algemene diagnose.", + level8 = + "Het is aan jou om het meeste efficiënte ziekenhuis op te zetten voor zo weinig mogelijk geld. " .. + "De mensen zitten hier goed in de slappe was, dus pers zoveel mogelijk geld uit ze als mogelijk is. " .. + "Ja, mensen genezen is heel leuk, maar je hebt het geld dat ze binnenbrengen echt NODIG. " .. + "Schudt die zieke mensen dus maar flink uit. " .. + "Verzamel een fortuin van $300.000 om dit level uit te spelen.", + level13 = + "Je fantastische werk als directeur is ondertussen bij de Speciale Geheime Divisie van de Geheime Speciale Dienst bekend. " .. + "Ze hebben een bonus voor je; er is een ziekenhuis geïnfecteerd met ratten en ze hebben een echte Terminator nodig. " .. + "Vermorzel zoveel mogelijk ratten voordat de conciërges de boel hebben opgeruimd. " .. + "Denk je dat je die taak aankunt?", + level16 = + "Zodra je wat diagnoses hebt gesteld zal je behandelkamers en klinieken moeten bouwen om voor de mensen te zorgen. Een goede om mee te beginnen is de apotheek. " .. + "Je moet ook een zuster inhuren zodat ze de verschillende medicijnen kan toedienen.", + level6 = + "Gebruik al je kennis om je ziekenhuis soepel te laten draaien, een gezonde winst te maken en alle ziektes te genezen die de mensen met zich meedragen. " .. + "Wees je ervan bewust dat de atmosfeer hier erg geschikt is voor het overdragen van bacteriën en infecties. " .. + "Hou je ziekenhuis dus schoon, tenzij je een lange rits van epidemieën onder je patiënten wilt brengen. " .. + "Zorg ervoor dat je $150.000 verdient en dat je ziekenhuis meer dan $140.000 waard is.", + level12 = + "Dit is de moeder van alle uitdagingen. " .. + "Het ministerie is zo onder de indruk van je succes, dat ze je de hoogste positie hebben aangeboden. Ze willen iemand hebben die nog een ultiem ziekenhuis kan bouwen, veel geld kan verdienen en een fantastische reputatie kan opbouwen. " .. + "Je wordt verwacht alle, maar dan ook echt alle ziektes te kunnen genezen en alle prijzen in de wacht te slepen. " .. + "Denk je dat je dat aankunt?" .. + "Verdien $650.000, genees 750 mensen en verdien krijg een reputatie van 800 om dit te winnen.", + level3 = + "Dit keer bouw je een ziekenhuis in een rijke buurt. " .. + "Het Ministerie van Volksgezondheid vraagt een gezonde winst van je. " .. + "Je zult eerst een goede reputatie moeten opbouwen, maar schakel zodra je ziekenhuis volloopt over op zoveel mogelijk geld binnenhalen. " .. + "Er kunnen zich ook noodgevallen voordoen. " .. + "Dit zijn gevallen waarin er meerdere patiënten binnenkomen met dezelfde ziekte. " .. + "Als je ze allemaal binnen een bepaalde tijd geneest, zit er een vette bonus aan vast en gaat je reputatie erop vooruit. " .. + "Ziektes als het King Complex kunnen voorkomen en er wordt aangeraden om wat geld opzij te zetten voor een operatiekamer in de buurt van een slaapzaal. " .. + "Verdien $20.000 om het level te halen.", + level10 = + "Het ministerie vraagt nu niet alleen dat je alle ziektes in deze buurt aanpakt, maar ook dat je je concentreert op de efficiëntie van je medicijnen. " .. + "Er zijn wat klachten binnengekomen van Ofziek, de waakhond van de gezondheidszorg, dus als je goed over wil komen, zorg je ervoor dat je medicijnen goed werken. " .. + "Zorg ook dat er niets te klagen valt over je ziekenhuis zelf. Hou die sterfgevallen zeldzaam. " .. + "Hint: Hou wat ruimte vrij voor een gelatinetank. " .. + "Ontwikkel al je medicijnen door tot ze ten minste 80 procent effectief zijn, behaal een reputatie van 650 en behaal een saldo van $500.000. ", + level11 = + "Je hebt de kans gekregen het ultieme ziekenhuis te bouwen. " .. + "Dit is een zeer prestigieuze omgeving, en het ministerie wil een zo goed mogelijk ziekenhuis zien. " .. + "We verwachten dat je flink geld binnenhaalt, een fantastische reputatie hebt en elke situatie aan kunt. " .. + "Dit is een belangrijke taak. " .. + "Je bent heel wat als je dit lukt. " .. + "Opmerkenswaardig is dat er UFO's in de omgeving gezien zijn. Zorg ervoor dat je personeel klaar is voor onverwachte bezoekers. " .. + "Je ziekenhuis moet $240.000 waard zijn en je moet $500.000 op de bank hebben staan. Ook moet je reputatie minimaal 700 bedragen.", + level18 = "", + demo = + "Welkom in het demo ziekenhuis!//" .. + "Jammer genoeg bevat de demo versie buiten zelfgemaakte levels alleen dit ziekenhuis, maar er is meer dan genoeg te doen om je voorlopig bezig te houden! " .. + "Je zult verschillende kwalen tegenkomen die verschillende ruimtes nodig hebben om genezen te worden, af en toe kunnen zich noodgevallen voordoen, en je zult nieuwe ruimtes uit moeten vinden met het laboratorium. " .. + "Jouw doel is om $100,000 te verdienen, de waarde van je ziekenhuis te verhogen naar $70,000 en een reputatie van 700 te behalen, terwijl je 75% van je patiënten geneest. " .. + "Zorg er voor dat je reputatie niet lager wordt dan 300 en dat je niet meer dan 40% van je patiënten vermoord, anders zal je ontslagen worden!//" .. + "Succes!", } humanoid_name_starts = { [1] = "GOUD", @@ -2202,6 +2186,7 @@ unavailable_screen_size = "De resolutie die je hebt ingevoerd is niet beschikbaar in fullscreen", alien_dna = "LET OP: Er zijn geen animaties voor alien patiënten die zitten, op deuren kloppenen, deuren openen, enz. Daarom veranderen ze naar een normaal mens als ze dit doen en veranderen dan weer terug, net als in Them Hospital. Patiënten met alien-DNA verschijnen alleen wanneer dit in het level is toegestaan.", fractured_bones = "LET OP: De animatie voor vrouwelijke patiënten met gebrokken botten is niet goed.", + no_games_to_contine = "Er zijn geen opgeslagen spellen.", } diseases = { diag_ward = { @@ -2487,6 +2472,7 @@ options = "Instellingen", version = "Versie: ", savegame_version = "Savegame versie: ", + continue = "Zet spel voort", } confirmation = { --spaces on the end make the text fit properly in text windows quit = "Weet je zeker dat je het spel wilt verlaten? ", @@ -2499,7 +2485,7 @@ abort_edit_room = "Je bent een ruimte aan het bouwen of aanpassen. Wanneer alle benodigde objecten geplaatst zijn, is de ruimte af. Zo niet, dan wordt de ruimte vernietigd. ", restart_level = "Weet je zeker dat je het level opnieuw wilt beginnen? ", maximum_screen_size = "De resolutie die je hebt ingevoerd is groter dan 3000x2000. Een hoge resolutie is mogelijk, mits je hardware goed genoeg is om een speelbare framerate te behalen. Weet je zeker dat je wilt doorgaan?", - music_warning = "Voordat je MP3's gaat gebruiken als ingame muziek, heb je smpeg.dll (of gelijkwaardig voor je systeem) nodig, anders werkt de muziek niet. Op dit moment is een dergerlijk bestand niet beschikbaar voor 64bit systemen. Wil je doorgaan?", + music_warning = "Voordat je MP3's gaat gebruiken als ingame muziek, heb je smpeg.dll (of gelijkwaardig voor je systeem) nodig, anders werkt de muziek niet. Wil je doorgaan?", } menu_display = { mcga_lo_res = " LAGE RES ", @@ -2607,6 +2593,8 @@ calls_dispatcher = " CALLS DISPATCHER ", cheats = " (F11) CHEATS ", jump_to_level = " SPRING NAAR LEVEL ", + debug_script = " (SHIFT + D) LAAT FOUTSCRIPT LOPEN ", + connect_debugger = " (CTRL + C) MAAK VERBINDING MET LUA DBGp SERVER ", } drug_companies = { @@ -2889,6 +2877,8 @@ all_research = "All research cheat", end_year = "Einde van het jaar", earthquake = "Creëer aardbeving", + epidemic = "Besmettelijke patient laten verschijnen", + toggle_infected = "Aan/uit zetten besmet iconen", }, cheated = { no = "Cheats gebruikt: Nee", diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/english.lua corsix-th-0.62/CorsixTH/Lua/languages/english.lua --- corsix-th-0.30/CorsixTH/Lua/languages/english.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/english.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010 Manuel "Roujin" Wolf +--[[ Copyright (c) 2010-2014 Manuel "Roujin" Wolf, Edvin "Lego3" Linge et al Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -55,7 +55,13 @@ } -- A small error in the introduction text of level 2 -introduction_texts.level2[6] = "Aim for a reputation of 300 a bank balance of $10,000 and 40 people cured." +introduction_texts.level2 = "There is a greater variety of ailments in this area. Set up your hospital to deal with more patients, " .. + "and plan to build a Research Department. Remember to keep your establishment clean, and try to get your " .. + "reputation as high as possible - you'll be dealing with diseases like Slack Tongue, so you'll need a Slack " .. + "Tongue Clinic. You can also build a Cardiogram to help you diagnose new illnesses. Both these rooms will " .. + "need to be researched before you can build them. Now you can also buy extra plots of land to expand your " .. + "hospital - use the Town map for this. Aim for a reputation of 300 a bank balance of $10,000 and 40 people cured." + -- An override for the squits becoming the the squits see issue 1646 adviser.research.drug_improved_1 = "%s drug has been improved by your Research Department." ------------------------------- NEW STRINGS ------------------------------- @@ -66,6 +72,9 @@ object.litter = "Litter" tooltip.objects.litter = "Litter: Left on the floor by a patient because he did not find a bin to throw it in." +object.rathole = "Rathole" +tooltip.objects.rathole = "Home of a rat family that found your hospital dirty enough to live here." + tooltip.fax.close = "Close this window without deleting the message" tooltip.message.button = "Left click to open message" tooltip.message.button_dismiss = "Left click to open message, right click to dismiss it" @@ -74,6 +83,8 @@ tooltip.research_policy.no_research = "No research is being carried out in this category at the moment" tooltip.research_policy.research_progress = "Progress towards the next discovery in this category: %1%/%2%" +menu["player_count"] = "PLAYER COUNT" + menu_file = { load = " (SHIFT+L) LOAD ", save = " (SHIFT+S) SAVE ", @@ -88,6 +99,7 @@ jukebox = " (J) JUKEBOX ", lock_windows = " LOCK WINDOWS ", edge_scrolling = " EDGE SCROLLING ", + capture_mouse = " CAPTURE MOUSE ", adviser_disabled = " (SHIFT+A) ADVISER ", warmth_colors = " WARMTH COLOURS ", wage_increase = " WAGE REQUESTS", @@ -129,6 +141,7 @@ menu_debug = { jump_to_level = " JUMP TO LEVEL ", + connect_debugger = " (CTRL + C) CONNECT LUA DBGp SERVER ", transparent_walls = " (X) TRANSPARENT WALLS ", limit_camera = " LIMIT CAMERA ", disable_salary_raise = " DISABLE SALARY RAISE ", @@ -136,6 +149,7 @@ make_debug_patient = " MAKE DEBUG PATIENT ", cheats = " (F11) CHEATS ", lua_console = " (F12) LUA CONSOLE ", + debug_script = " (SHIFT + D) RUN DEBUG SCRIPT ", calls_dispatcher = " CALLS DISPATCHER ", dump_strings = " DUMP STRINGS ", dump_gamelog = " (CTRL+D) DUMP GAME LOG ", @@ -156,6 +170,12 @@ byte_7 = " BYTE 7 ", parcel = " PARCEL ", } +menu_player_count = { + players_1 = " 1 PLAYER ", + players_2 = " 2 PLAYERS ", + players_3 = " 3 PLAYERS ", + players_4 = " 4 PLAYERS ", +} adviser = { room_forbidden_non_reachable_parts = "Placing the room in this location would result in parts of the hospital not being reachable.", warnings = { @@ -182,6 +202,10 @@ researcher_needs_desk_3 = "Each Researcher needs to have his own desk to work from.", nurse_needs_desk_1 = "Each Nurse needs to have her own desk to work from.", nurse_needs_desk_2 = "Your Nurse is pleased that you have allowed her to have a break. If you were intending to have more than one working in the ward, then you need to provide them each with a desk to work from.", + low_prices = "You're charging too little for %s. This will bring people to your hospital, but you won't make a lot of profit from each one.", + high_prices = "Your charges for %s are high. This will make big profits in the short-term, but ultimately you'll start to drive people away.", + fair_prices = "Your charges for %s seem fair and balanced.", + patient_not_paying = "A patient left without paying for %s because it's too expensive!", }, cheats = { th_cheat = "Congratulations, you have unlocked cheats!", @@ -193,6 +217,7 @@ dynamic_info.patient.actions.no_gp_available = "Waiting for you to build a GP's office" dynamic_info.staff.actions.heading_for = "Heading for %s" dynamic_info.staff.actions.fired = "Fired" +dynamic_info.patient.actions.epidemic_vaccinated = "I am no longer contagious" progress_report.free_build = "FREE BUILD" @@ -218,9 +243,12 @@ } letter = { - dear_player = "Dear %s", + dear_player = "Dear %s\n", custom_level_completed = "Well done! You've completed all goals on this custom level!", return_to_main_menu = "Would you like to return to the main menu or continue playing?", + campaign_level_completed = "Good job! You beat the level. But it's not over yet!\n Would you like a position at %s Hospital?", + campaign_completed = "Incredible! You managed to finish all the levels. You can now relax and enjoy filling forums across the Internet of your achievements. Good luck!", + campaign_level_missing = "Sorry, but the next level of this campaign seems to be missing. (Name: %s)", } install = { @@ -236,9 +264,12 @@ main_menu = { new_game = "Campaign", + custom_campaign = "Custom Campaign", custom_level = "Single Scenario", + continue = "Continue Game", load_game = "Load Game", options = "Settings", + map_edit = "Map Editor", savegame_version = "Savegame version: ", version = "Version: ", exit = "Exit", @@ -246,9 +277,12 @@ tooltip.main_menu = { new_game = "Start the first level on the campaign", + custom_campaign = "Play a campaign created by the community", custom_level = "Build your hospital in a single scenario", + continue = "Continue your latest saved game", load_game = "Load a saved game", options = "Tweak various settings", + map_edit = "Create a custom map", exit = "No, no, please don't leave!", quit = "You are about to quit from CorsixTH. Are you sure this is what you want to do?", } @@ -266,11 +300,23 @@ custom_game_window = { caption = "Custom Game", free_build = "Free Build", + load_selected_level = "Start", } tooltip.custom_game_window = { - start_game_with_name = "Information about this scenario which is using: %s Briefing: %s", + choose_game = "Click a level to read more about it", free_build = "Tick this box if you want to play without money or winning and losing conditions", + load_selected_level = "Load and play the selected level", +} + +custom_campaign_window = { + caption = "Custom Campaign", + start_selected_campaign = "Start campaign", +} + +tooltip.custom_campaign_window = { + choose_campaign = "Choose a campaign to read more about it", + start_selected_campaign = "Load the first level of this campaign", } save_game_window = { @@ -283,6 +329,16 @@ new_save_game = "Enter name for a new savegame", } +save_map_window = { + caption = "Save Map (%1%)", + new_map = "New Map", +} + +tooltip.save_map_window = { + map = "Overwrite map %s", + new_map = "Enter name for a map savegame", +} + menu_list_window = { name = "Name", save_date = "Modified", @@ -301,6 +357,7 @@ option_off = "Off", fullscreen = "Fullscreen", resolution = "Resolution", + capture_mouse = "Capture Mouse", custom_resolution = "Custom...", width = "Width", height = "Height", @@ -318,6 +375,7 @@ fullscreen_button = "Click to toggle fullscreen mode", resolution = "The resolution the game should run in", select_resolution = "Select a new resolution", + capture_mouse = "Click to toggle capturing the cursor in the game window", width = "Enter desired screen width", height = "Enter desired screen height", apply = "Apply the entered resolution", @@ -445,19 +503,27 @@ dialog_missing_graphics = "Sorry, the demo data files don't contain this dialog.", save_prefix = "Error while saving game: ", load_prefix = "Error while loading game: ", + no_games_to_contine = "There are no saved games.", load_quick_save = "Error, cannot load the quicksave as it does not exist, not to worry as we have now created one for you!", map_file_missing = "Could not find the map file %s for this level!", minimum_screen_size = "Please enter a screen size of at least 640x480.", unavailable_screen_size = "The screen size you requested is not available in fullscreen mode.", alien_dna = "NOTE: There are no animations for Alien patients for sitting down, opening or knocking on doors etc. So, like with Theme Hospital to do these things they will appear to change to normal looking and then change back. Patients with Alien DNA will only appear if they are set to in the level file", fractured_bones = "NOTE: The animation for female patients with Fractured Bones is not perfect", + could_not_load_campaign = "Failed to load the campaign: %s", + could_not_find_first_campaign_level = "Could not find the first level of this campaign: %s", +} + +warnings = { + levelfile_variable_is_deprecated = "Notice: The level '%s' contains a deprecated variable definition in the level file." .. + "'%LevelFile' has been renamed to '%MapFile'. Please advise the map creator to update the level.", } confirmation = { needs_restart = "Changing this setting requires CorsixTH to restart. Any unsaved progress will be lost. Are you sure you want to do this?", abort_edit_room = "You are currently building or editing a room. If all required objects are placed it will be finished, but otherwise it will be deleted. Continue?", maximum_screen_size = "The screen size you have entered is greater than 3000 x 2000. Larger resolutions are possible, but will require better hardware in order to maintain a playable frame rate. Are you sure you want to continue?", - music_warning = "Before choosing to use mp3's for your in game music, you will need to have smpeg.dll or the equivalent for your operating system, otherwise you will have no music in the game. Currently there is no equivalent file for 64bit systems. Do you want to continue?", + music_warning = "Note: You will need to have smpeg.dll or the equivalent for your operating system, otherwise you will hear no music in the game. Do you want to continue?", } information = { @@ -483,7 +549,7 @@ totd_window = { tips = { "Every hospital needs a reception desk and a GP's office to get going. After that, it depends on what kind of patients are visiting your hospital. A pharmacy is always a good choice, though.", - "Machines such as the Inflation need maintenance. Employ a handyman or two to repair your machines, or you'll risk your staff and patients getting hurt.", + "Machines such as the Inflator need maintenance. Employ a handyman or two to repair your machines, or you'll risk your staff and patients getting hurt.", "After a while, your staff will get tired. Be sure to build a staff room, so they can relax.", "Place enough radiators to keep your staff and patients warm, or they will become unhappy. Use the town map to locate any spots in your hospital that need more heating.", "A doctor's skill level greatly influences the quality and speed of his diagnoses. Place a skilled doctor in your GP's office, and you won't need as many additional diagnosis rooms.", @@ -528,11 +594,15 @@ emergency = "Create Emergency", vip = "Create VIP", earthquake = "Create Earthquake", + epidemic = "Spawn contagious patient", + toggle_infected = "Toggle infected icons", create_patient = "Create Patient", end_month = "End of Month", end_year = "End of Year", lose_level = "Lose Level", win_level = "Win Level", + increase_prices = "Increase prices", + decrease_prices = "Decrease prices", }, close = "Close", } @@ -545,23 +615,26 @@ emergency = "Creates an emergency.", vip = "Creates a VIP.", earthquake = "Creates an earthquake.", + epidemic = "Creates an contagious patient who may cause an epidemic to happen", + toggle_infected = "Toggle the infected icons for the active, discovered epidemic", create_patient = "Creates a Patient at the map border.", end_month = "Jumps to the end of the month.", end_year = "Jumps to the end of the year.", lose_level = "Lose the current level.", win_level = "Win the current level.", + increase_prices = "Increase all prices by 50% (max. 200%)", + decrease_prices = "Decrease all prices by 50% (min. 50%)", } } introduction_texts = { - demo = { - "Welcome to the demo hospital!", - "Unfortunately the demo version only contains this level. However, there is more than enough to do here to keep you busy for a while!", - "You will encounter various diseases that require different rooms to cure. From time to time, emergencies may occur. And you will need to research additional rooms using a research room.", - "Your goal is to earn $100,000, have a hospital value of $70,000 and a reputation of 700, while having cured at least 75% of your patients.", - "Make sure your reputation does not fall below 300 and that you don't kill off more than 40% of your patients, or you will lose.", + demo = + "Welcome to the demo hospital!//" .. + "Unfortunately the demo version only contains this level. However, there is more than enough to do here to keep you busy for a while! " .. + "You will encounter various diseases that require different rooms to cure. From time to time, emergencies may occur. And you will need to research additional rooms using a research room. " .. + "Your goal is to earn $100,000, have a hospital value of $70,000 and a reputation of 700, while having cured at least 75% of your patients. " .. + "Make sure your reputation does not fall below 300 and that you don't kill off more than 40% of your patients, or you will lose.//" .. "Good luck!", - }, } calls_dispatcher = { @@ -592,6 +665,40 @@ ignore = "Ignore this update for now. You will be notified again when you next open CorsixTH", } +map_editor_window = { + pages = { + inside = "Inside", + outside = "Outside", + foliage = "Foliage", + hedgerow = "Hedgerow", + pond = "Pond", + road = "Road", + north_wall = "North wall", + west_wall = "West wall", + helipad = "Helipad", + delete_wall = "Delete walls", + parcel_0 = "Parcel 0", + parcel_1 = "Parcel 1", + parcel_2 = "Parcel 2", + parcel_3 = "Parcel 3", + parcel_4 = "Parcel 4", + parcel_5 = "Parcel 5", + parcel_6 = "Parcel 6", + parcel_7 = "Parcel 7", + parcel_8 = "Parcel 8", + parcel_9 = "Parcel 9", + camera_1 = "Camera 1", + camera_2 = "Camera 2", + camera_3 = "Camera 3", + camera_4 = "Camera 4", + heliport_1 = "Heliport 1", + heliport_2 = "Heliport 2", + heliport_3 = "Heliport 3", + heliport_4 = "Heliport 4", + paste = "Paste area", + } +} + -------------------------------- UNUSED ----------------------------------- ------------------- (kept for backwards compatibility) ---------------------- diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/finnish.lua corsix-th-0.62/CorsixTH/Lua/languages/finnish.lua --- corsix-th-0.30/CorsixTH/Lua/languages/finnish.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/finnish.lua 2018-07-21 11:13:17.000000000 +0000 @@ -382,135 +382,116 @@ -- 9. Level introductions introduction_texts = { - demo = { - [1] = "Tervetuloa demosairaalaan!", - [2] = "Valitettavasti demoversio sisältää ainoastaan tämän tason. Täällä on kuitenkin enemmän kuin tarpeeksi tekemistä!", - [3] = "Kohtaat erilaisia sairauksia, joiden hoitaminen vaatii erilaisia huoneita. Hätätilanteita saattaa tapahtua ajoittain. Lisäksi sinun pitää kehittää lisää huoneita tutkimusosaston avulla.", - [4] = "Tavoitteesi on ansaita 100 000$, nostaa sairaalan arvo yli 70 000$:n ja maineesi yli 700:n parantaen samalla vähintään 75% potilaistasi.", - [5] = "Pidä huoli, ettei maineesi putoa alle 300:n ja ettei yli 40 prosenttia potilaistasi pääse kuolemaan, tai häviät tason.", - [6] = "Onnea!", - }, - level1 = { - [1] = "Tervetuloa ensimmäiseen sairaalaasi!//", - [2] = "Pääset alkuun rakentamalla vastaanottopöydän ja yleislääkärin toimiston sekä palkkaamalla vastaanottoapulaisen ja lääkärin. ", - [3] = "Sitten vain odotat asiakkaiden saapumista.", - [4] = "Olisi hyvä ajatus rakentaa psykiatrin vastaanotto ja palkata lääkäri, joka on erikoistunut psykiatriaan. ", - [5] = "Apteekki ja sairaanhoitaja ovat myös tärkeä yhdistelmä potilaidesi parantamiseksi. ", - [6] = "Tarkkaile pallopäisyydestä kärsiviä potilaitasi - pumppaushuone hoitaa heidät alta aikayksikön. ", - [7] = "Tavoitteenasi on parantaa kaikkiaan 10 potilasta ja varmistaa, ettei maineesi putoa alle 200:n.", - }, - level2 = { - [1] = "Tällä alueella on enemmän erilaisia sairauksia kuin edellisellä. ", - [2] = "Sairaalasi pitää selvitä suuremmasta potilasmäärästä, ja sinun kannattaa varautua tutkimusosaston rakentamiseen. ", - [3] = "Muista pitää laitoksesi puhtaana, ja yritä nostaa maineesi niin korkeaksi kuin mahdollista - alueella on liikkeellä velttokielisyyttä, joten tarvitset kieliklinikan. ", - [4] = "Voit myös rakentaa kardiogrammihuoneen auttamaan uusien sairauksien diagnosoinnissa. ", - [5] = "Molemmat näistä huoneista täytyy kehittää ennen kuin voit rakentaa niitä. Nyt voit myös ostaa lisää maata sairaalasi laajentamiseksi - Tämä tapahtuu kartta-ikkunassa. ", - [6] = "Tavoitteesi ovat 300:n maine, 10 000$ pankissa and 40 parannettua potilasta.", - }, - level3 = { - [1] = "Tällä kertaa sairaalasi sijaitsee varakkaalla alueella. ", - [2] = "Terveysministeriö odottaa sinun saavan täältä muhkeat voitot. ", - [3] = "Alussa sinun täytyy hankkia sairaalallesi hyvä maine. Kun saat sairaalan pyörimään kunnolla, keskity ansaitsemaan niin paljon rahaa kuin pystyt. ", - [4] = "Alueella saattaa myös sattua hätätapauksia. ", - [5] = "Näissä tilanteissa suuri joukko samalla tavoin loukkaantuneita potilaita saapuu sairaalaasi yhtä aikaa. ", - [6] = "Jos onnistut parantamaan heidät annetun aikarajan puitteissa saat lisää mainetta ja ison bonuksen. ", - [7] = "Kuningas-kompleksin kaltaisia sairauksia saattaa esiintyä, joten kannattaa budjetoida rahaa leikkaussalin ja vuodeosaston rakentamiseen lähelle toisiaan. ", - [8] = "Ansaitse 20 000$ päästäksesi seuraavalle tasolle.", - }, - level4 = { - [1] = "Pidä kaikki potilaasi tyytyväisinä, hoida heitä niin tehokkaasti kuin pystyt ja pidä kuolemantapaukset minimissään. ", - [2] = "Maineesi on kyseessä, joten pidä huolta, että se pysyy niin korkealla kuin mahdollista. ", - [3] = "Älä huolehdi rahasta liikaa - sitä alkaa kyllä tulla lisää maineesi kasvaessa. ", - [4] = "Voit myös kouluttaa lääkäreitäsi parantaaksesi heidän osaamistaan. ", - [5] = "He saattavat hyvinkin joutua hoitamaan tavallista läpinäkyvämpiä potilaita. ", - [6] = "Nosta maineesi yli 500:n.", - }, - level5 = { - [1] = "Tästä tulee kiireinen sairaala, joka joutuu hoitamaan laajaa kirjoa sairauksia. ", - [2] = "Kaikki lääkärisi ovat vastavalmistuneita, joten on ensiarvoisen tärkeää, että rakennat koulutushuoneen ja nostat lääkäreidesi osaamisen hyväksyttävälle tasolle. ", - [3] = "Sinulla on vain kolme konsulttia opettamassa kokematonta henkilökuntaasi, joten pidä heidät tyytyväisinä. ", - [4] = "Huomaa myös, että sairaalasi on rakennettu geologisen siirroksen läheisyyteen. ", - [5] = "Maanjäristysten riski on siis koko ajan olemassa. ", - [6] = "Ne aiheuttavat sattuessaan mittavia vahinkoja laitteillesi ja häiritsevät sairaalasi sujuvaa toimintaa. ", - [7] = "Hanki sairaalallesi 400 mainetta ja kasvata 50 000$:n pankkitili onnistuaksesi. Paranna samalla 200 potilasta.", - }, - level6 = { - [1] = "Käytä kaikkea oppimaasi ja rakenna sujuvasti toimiva sairaala, joka on taloudellisesti terveellä pohjalla ja pystyy selviytymään kaikista eteen tulevista tilanteista. ", - [2] = "Sinun on hyvä tietää, että ilmasto täällä levittää erityisen tehokkaasti bakteereja ja viruksia. ", - [3] = "Ellet onnistu pitämään sairaalaasi putipuhtaana, potilaasi voivat joutua epidemioiden kierteeseen. ", - [4] = "Pidä huolta, että ansaitset 150 000$ ja sairaalasi arvo ylittää 140 000$.", - }, - level7 = { - [1] = "Täällä joudut terveysministeriön tiukan valvonnan kohteeksi, joten pidä huolta, että tilikirjoissasi näkyy suuria voittoja ja maineesi pysyy korkealla. ", - [2] = "Meillä ei ole varaa ylimääräisiin kuolemantapauksiin - ne ovat huonoja liiketoiminnan kannalta. ", - [3] = "Varmista, että henkilökuntasi on parasta mahdollista ja heillä on kaikki tarvittavat toimitilat ja tarvikkeet. ", - [4] = "Tavoitteesi ovat 600 mainetta ja 200 000$ pankkitilillä.", - }, - level8 = { - [1] = "Sinun tehtäväsi on rakentaa tehokkain ja tuottavin mahdollinen sairaala. ", - [2] = "Ihmiset täällä ovat melko varakkaita, joten heiltä kannattaa kerätä niin paljon rahaa kuin mahdollista. ", - [3] = "Muista, että niin kivaa kuin ihmisten parantaminen onkin, tarvitset kipeästi rahaa, jota se tuottaa. ", - [4] = "Putsaa näiltä ihmisiltä tuhkatkin pesästä. ", - [5] = "Sinun tulee kerätä vaikuttavat 300 000$ läpäistäksesi tason.", - }, - level9 = { - [1] = "Täytettyäsi ministeriön pankkitilin ja kustannettuasi uuden limusiinin ministerille itselleen pääset taas luomaan huolehtivan ja hyvin hoidetun sairaalan sairaiden avuksi. ", - [2] = "Voit odottaa monia erilaisia ongelmia tällä alueella.", - [3] = "Jos sinulla on riittävästi hyvin koulutettua henkilökuntaa ja huoneita, sinulla pitäisi olla kaikki hallinnassa. ", - [4] = "Sairaalasi arvon tulee olla 200 000$ ja sinulla pitää olla 400 000$ pankissa. ", - [5] = "Pienemmillä summilla et pääse tätä tasoa läpi.", - }, - level10 = { - [1] = "Sen lisäksi, että huolehdit kaikista sairauksista, joita täällä päin ilmenee, ministeriö pyytää, että käytät aikaa lääkkeidesi tehon parantamiseen. ", - [2] = "Terveysjärjestöt ovat esittäneet joitakin valituksia, joten näyttääkseen hyvältä sairaalasi täytyy varmistaa, että kaikki käyttettävät lääkkeet ovat erittäin tehokkaita. ", - [3] = "Varmista myös, että sairaalasi on arvostelun yläpuolella. Pidä kuolemantapausten määrä kurissa. ", - [4] = "Ihan vihjeenä: saattaa olla hyvä idea säästää tilaa hyytelömuovainhuoneelle. ", - [5] = "Kehitä kaikki lääkkeesi vähintään 80%%:n tehokkuuteen, nosta maineesi vähintään 650:n ja kokoa 500 000$ pankkitilillesi voittaaksesi. ", - }, - level11 = { - [1] = "Sinulle tarjoutuu nyt mahdollisuus rakentaa yksi maailman parhaista sairaaloista. ", - [2] = "Tämä on erittäin arvostettu asuinalue ja ministeriö haluaa tänne parhaan mahdollisen sairaalan. ", - [3] = "Odotamme sinun ansaitsevan runsaasti rahaa, hankkivan erinomaisen maineen sairaalallesi ja pystyvän hoitamaan vaikeimmatkin tapaukset. ", - [4] = "Tämä on hyvin tärkeä työ. ", - [5] = "Sinun täytyy käyttää kaikkea osaamistasi selvitäksesi tästä kunnialla. ", - [6] = "Huomaa, että alueella on havaittu UFOja. Pidä huolta, että henkilökuntasi on valmiina odottamattomien vierailijoiden varalta. ", - [7] = "Sairaalasi arvon pitää olla 240 000$, pankkitililläsi pitää olla 500 000$ ja maineesi pitää olla 700.", - }, - level12 = { - [1] = "Tämä on kaikkien haasteiden äiti. ", - [2] = "Vaikuttuneena saavutuksistasi ministeriö on päättänyt antaa sinulle huipputyön; he haluavat toisen maailmanluokan sairaalan, joka tuottaa mainiosti ja jolla on erinomainen maine. ", - [3] = "Sinun odotetaan myös ostavan kaikki saatavilla olevat maa-alueet, parantavan kaikki sairaudet (ja me tosiaan tarkoitamme kaikki) ja voittavan kaikki palkinnot. ", - [4] = "Luuletko onnistuvasi?", - [5] = "Ansaitse 650 000$, paranna 750 ihmistä ja hanki 800 mainetta voittaaksesi tämän.", - }, - level13 = { - [1] = "Uskomattomat kykysi sairaalanjohtajana ovat tulleet Salaisen erityispalvelun erityisen salaosaston tietoon. ", - [2] = "Heillä on sinulle erityinen bonus: täynnä rottia oleva sairaala, joka kaipaa kipeästi tehokasta tuholaistorjuntaa. ", - [3] = "Sinun pitää ampua mahdollisimman monta rottaa ennen kuin huoltomiehet siivoavat kaikki roskat pois. ", - [4] = "Uskotko olevasi tehtävän tasalla?", - }, - level14 = { - [1] = "Vielä yksi haaste on tarjolla - täysin odottamaton yllätyssairaala. ", - [2] = "Jos onnistut saamaan tämän paikan toimimaan, olet todellinen mestareiden mestari. ", - [3] = "Älä kuvittelekkaan, että tästä tulee helppoa kuin puistossa kävely, sillä tämä on pahin haaste, jonka saat vastaasi. ", - [4] = "Paljon onnea!", - }, - level15 = { - [1] = "Nyt olemme käsitelleet perusteet sairaalan saamiseksi toimintaan.//", - [2] = "Lääkärisi tarvitsevat kaiken mahdollisen avun diagnosoidessaan osan näistä potilaista. ", - [3] = "Voit auttaa heitä rakentamalla toisen diagnoosihuoneen kuten yleislääkärin vastaanoton.", - }, - level16 = { - [1] = "Diagnosoituasi potilaita tarvitset hoitohuoneita ja klinikoita heidän parantamisekseen ", - [2] = "Apteekista on hyvä aloittaa. Toimiakseen se tarvitsee sairaanhoitajan annostelemaan lääkkeitä.", - }, - level17 = { - [1] = "Viimeinen varoituksen sana: pidä tarkasti silmällä mainettasi, sillä se houkuttelee sairaalaasi potilaita niin läheltä kuin kaukaa. ", - [2] = "Jos potilaita ei kuole liikaa ja he pysyvät kohtuullisen tyytyväisinä, sinulla ei ole mitään hätää tällä tasolla!//", - [3] = "Olet nyt omillasi. Onnea ja menestystä!.", - }, - level18 = { - }, + demo = + "Tervetuloa demosairaalaan!//" .. + "Valitettavasti demoversio sisältää ainoastaan tämän tason. Täällä on kuitenkin enemmän kuin tarpeeksi tekemistä! " .. + "Kohtaat erilaisia sairauksia, joiden hoitaminen vaatii erilaisia huoneita. Hätätilanteita saattaa tapahtua ajoittain. Lisäksi sinun pitää kehittää lisää huoneita tutkimusosaston avulla. " .. + "Tavoitteesi on ansaita 100 000$, nostaa sairaalan arvo yli 70 000$:n ja maineesi yli 700:n parantaen samalla vähintään 75% potilaistasi. " .. + "Pidä huoli, ettei maineesi putoa alle 300:n ja ettei yli 40 prosenttia potilaistasi pääse kuolemaan, tai häviät tason.//" .. + "Onnea!", + level1 = + "Tervetuloa ensimmäiseen sairaalaasi!//" .. + "Pääset alkuun rakentamalla vastaanottopöydän ja yleislääkärin toimiston sekä palkkaamalla vastaanottoapulaisen ja lääkärin. " .. + "Sitten vain odotat asiakkaiden saapumista." .. + "Olisi hyvä ajatus rakentaa psykiatrin vastaanotto ja palkata lääkäri, joka on erikoistunut psykiatriaan. " .. + "Apteekki ja sairaanhoitaja ovat myös tärkeä yhdistelmä potilaidesi parantamiseksi. " .. + "Tarkkaile pallopäisyydestä kärsiviä potilaitasi - pumppaushuone hoitaa heidät alta aikayksikön. " .. + "Tavoitteenasi on parantaa kaikkiaan 10 potilasta ja varmistaa, ettei maineesi putoa alle 200:n.", + level2 = + "Tällä alueella on enemmän erilaisia sairauksia kuin edellisellä. " .. + "Sairaalasi pitää selvitä suuremmasta potilasmäärästä, ja sinun kannattaa varautua tutkimusosaston rakentamiseen. " .. + "Muista pitää laitoksesi puhtaana, ja yritä nostaa maineesi niin korkeaksi kuin mahdollista - alueella on liikkeellä velttokielisyyttä, joten tarvitset kieliklinikan. " .. + "Voit myös rakentaa kardiogrammihuoneen auttamaan uusien sairauksien diagnosoinnissa. " .. + "Molemmat näistä huoneista täytyy kehittää ennen kuin voit rakentaa niitä. Nyt voit myös ostaa lisää maata sairaalasi laajentamiseksi - Tämä tapahtuu kartta-ikkunassa. " .. + "Tavoitteesi ovat 300:n maine, 10 000$ pankissa and 40 parannettua potilasta.", + level3 = + "Tällä kertaa sairaalasi sijaitsee varakkaalla alueella. " .. + "Terveysministeriö odottaa sinun saavan täältä muhkeat voitot. " .. + "Alussa sinun täytyy hankkia sairaalallesi hyvä maine. Kun saat sairaalan pyörimään kunnolla, keskity ansaitsemaan niin paljon rahaa kuin pystyt. " .. + "Alueella saattaa myös sattua hätätapauksia. " .. + "Näissä tilanteissa suuri joukko samalla tavoin loukkaantuneita potilaita saapuu sairaalaasi yhtä aikaa. " .. + "Jos onnistut parantamaan heidät annetun aikarajan puitteissa saat lisää mainetta ja ison bonuksen. " .. + "Kuningas-kompleksin kaltaisia sairauksia saattaa esiintyä, joten kannattaa budjetoida rahaa leikkaussalin ja vuodeosaston rakentamiseen lähelle toisiaan. " .. + "Ansaitse 20 000$ päästäksesi seuraavalle tasolle.", + level4 = + "Pidä kaikki potilaasi tyytyväisinä, hoida heitä niin tehokkaasti kuin pystyt ja pidä kuolemantapaukset minimissään. " .. + "Maineesi on kyseessä, joten pidä huolta, että se pysyy niin korkealla kuin mahdollista. " .. + "Älä huolehdi rahasta liikaa - sitä alkaa kyllä tulla lisää maineesi kasvaessa. " .. + "Voit myös kouluttaa lääkäreitäsi parantaaksesi heidän osaamistaan. " .. + "He saattavat hyvinkin joutua hoitamaan tavallista läpinäkyvämpiä potilaita. " .. + "Nosta maineesi yli 500:n.", + level5 = + "Tästä tulee kiireinen sairaala, joka joutuu hoitamaan laajaa kirjoa sairauksia. " .. + "Kaikki lääkärisi ovat vastavalmistuneita, joten on ensiarvoisen tärkeää, että rakennat koulutushuoneen ja nostat lääkäreidesi osaamisen hyväksyttävälle tasolle. " .. + "Sinulla on vain kolme konsulttia opettamassa kokematonta henkilökuntaasi, joten pidä heidät tyytyväisinä. " .. + "Huomaa myös, että sairaalasi on rakennettu geologisen siirroksen läheisyyteen. " .. + "Maanjäristysten riski on siis koko ajan olemassa. " .. + "Ne aiheuttavat sattuessaan mittavia vahinkoja laitteillesi ja häiritsevät sairaalasi sujuvaa toimintaa. " .. + "Hanki sairaalallesi 400 mainetta ja kasvata 50 000$:n pankkitili onnistuaksesi. Paranna samalla 200 potilasta.", + level6 = + "Käytä kaikkea oppimaasi ja rakenna sujuvasti toimiva sairaala, joka on taloudellisesti terveellä pohjalla ja pystyy selviytymään kaikista eteen tulevista tilanteista. " .. + "Sinun on hyvä tietää, että ilmasto täällä levittää erityisen tehokkaasti bakteereja ja viruksia. " .. + "Ellet onnistu pitämään sairaalaasi putipuhtaana, potilaasi voivat joutua epidemioiden kierteeseen. " .. + "Pidä huolta, että ansaitset 150 000$ ja sairaalasi arvo ylittää 140 000$.", + level7 = + "Täällä joudut terveysministeriön tiukan valvonnan kohteeksi, joten pidä huolta, että tilikirjoissasi näkyy suuria voittoja ja maineesi pysyy korkealla. " .. + "Meillä ei ole varaa ylimääräisiin kuolemantapauksiin - ne ovat huonoja liiketoiminnan kannalta. " .. + "Varmista, että henkilökuntasi on parasta mahdollista ja heillä on kaikki tarvittavat toimitilat ja tarvikkeet. " .. + "Tavoitteesi ovat 600 mainetta ja 200 000$ pankkitilillä.", + level8 = + "Sinun tehtäväsi on rakentaa tehokkain ja tuottavin mahdollinen sairaala. " .. + "Ihmiset täällä ovat melko varakkaita, joten heiltä kannattaa kerätä niin paljon rahaa kuin mahdollista. " .. + "Muista, että niin kivaa kuin ihmisten parantaminen onkin, tarvitset kipeästi rahaa, jota se tuottaa. " .. + "Putsaa näiltä ihmisiltä tuhkatkin pesästä. " .. + "Sinun tulee kerätä vaikuttavat 300 000$ läpäistäksesi tason.", + level9 = + "Täytettyäsi ministeriön pankkitilin ja kustannettuasi uuden limusiinin ministerille itselleen pääset taas luomaan huolehtivan ja hyvin hoidetun sairaalan sairaiden avuksi. " .. + "Voit odottaa monia erilaisia ongelmia tällä alueella." .. + "Jos sinulla on riittävästi hyvin koulutettua henkilökuntaa ja huoneita, sinulla pitäisi olla kaikki hallinnassa. " .. + "Sairaalasi arvon tulee olla 200 000$ ja sinulla pitää olla 400 000$ pankissa. " .. + "Pienemmillä summilla et pääse tätä tasoa läpi.", + level10 = + "Sen lisäksi, että huolehdit kaikista sairauksista, joita täällä päin ilmenee, ministeriö pyytää, että käytät aikaa lääkkeidesi tehon parantamiseen. " .. + "Terveysjärjestöt ovat esittäneet joitakin valituksia, joten näyttääkseen hyvältä sairaalasi täytyy varmistaa, että kaikki käyttettävät lääkkeet ovat erittäin tehokkaita. " .. + "Varmista myös, että sairaalasi on arvostelun yläpuolella. Pidä kuolemantapausten määrä kurissa. " .. + "Ihan vihjeenä: saattaa olla hyvä idea säästää tilaa hyytelömuovainhuoneelle. " .. + "Kehitä kaikki lääkkeesi vähintään 80%%:n tehokkuuteen, nosta maineesi vähintään 650:n ja kokoa 500 000$ pankkitilillesi voittaaksesi. ", + level11 = + "Sinulle tarjoutuu nyt mahdollisuus rakentaa yksi maailman parhaista sairaaloista. " .. + "Tämä on erittäin arvostettu asuinalue ja ministeriö haluaa tänne parhaan mahdollisen sairaalan. " .. + "Odotamme sinun ansaitsevan runsaasti rahaa, hankkivan erinomaisen maineen sairaalallesi ja pystyvän hoitamaan vaikeimmatkin tapaukset. " .. + "Tämä on hyvin tärkeä työ. " .. + "Sinun täytyy käyttää kaikkea osaamistasi selvitäksesi tästä kunnialla. " .. + "Huomaa, että alueella on havaittu UFOja. Pidä huolta, että henkilökuntasi on valmiina odottamattomien vierailijoiden varalta. " .. + "Sairaalasi arvon pitää olla 240 000$, pankkitililläsi pitää olla 500 000$ ja maineesi pitää olla 700.", + level12 = + "Tämä on kaikkien haasteiden äiti. " .. + "Vaikuttuneena saavutuksistasi ministeriö on päättänyt antaa sinulle huipputyön; he haluavat toisen maailmanluokan sairaalan, joka tuottaa mainiosti ja jolla on erinomainen maine. " .. + "Sinun odotetaan myös ostavan kaikki saatavilla olevat maa-alueet, parantavan kaikki sairaudet (ja me tosiaan tarkoitamme kaikki) ja voittavan kaikki palkinnot. " .. + "Luuletko onnistuvasi?" .. + "Ansaitse 650 000$, paranna 750 ihmistä ja hanki 800 mainetta voittaaksesi tämän.", + level13 = + "Uskomattomat kykysi sairaalanjohtajana ovat tulleet Salaisen erityispalvelun erityisen salaosaston tietoon. " .. + "Heillä on sinulle erityinen bonus: täynnä rottia oleva sairaala, joka kaipaa kipeästi tehokasta tuholaistorjuntaa. " .. + "Sinun pitää ampua mahdollisimman monta rottaa ennen kuin huoltomiehet siivoavat kaikki roskat pois. " .. + "Uskotko olevasi tehtävän tasalla?", + level14 = + "Vielä yksi haaste on tarjolla - täysin odottamaton yllätyssairaala. " .. + "Jos onnistut saamaan tämän paikan toimimaan, olet todellinen mestareiden mestari. " .. + "Älä kuvittelekkaan, että tästä tulee helppoa kuin puistossa kävely, sillä tämä on pahin haaste, jonka saat vastaasi. " .. + "Paljon onnea!", + level15 = + "Nyt olemme käsitelleet perusteet sairaalan saamiseksi toimintaan.//" .. + "Lääkärisi tarvitsevat kaiken mahdollisen avun diagnosoidessaan osan näistä potilaista. " .. + "Voit auttaa heitä rakentamalla toisen diagnoosihuoneen kuten yleislääkärin vastaanoton.", + level16 = + "Diagnosoituasi potilaita tarvitset hoitohuoneita ja klinikoita heidän parantamisekseen " .. + "Apteekista on hyvä aloittaa. Toimiakseen se tarvitsee sairaanhoitajan annostelemaan lääkkeitä.", + level17 = + "Viimeinen varoituksen sana: pidä tarkasti silmällä mainettasi, sillä se houkuttelee sairaalaasi potilaita niin läheltä kuin kaukaa. " .. + "Jos potilaita ei kuole liikaa ja he pysyvät kohtuullisen tyytyväisinä, sinulla ei ole mitään hätää tällä tasolla!//" .. + "Olet nyt omillasi. Onnea ja menestystä!.", + level18 = "", } -- 10. Tips diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/french.lua corsix-th-0.62/CorsixTH/Lua/languages/french.lua --- corsix-th-0.30/CorsixTH/Lua/languages/french.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/french.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010-2011 Nicolas "MeV" Elie +--[[ Copyright (c) 2010-2015 Nicolas "MeV" Elie Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -23,16 +23,15 @@ Inherit("original_strings", 1) ----------------------------------------------------------- Override ----------------------------------------------------------- -adviser.information.promotion_to_specialist = "L'un de vos INTERNES est devenu MEDECIN." -- Fix the famous "Level 5 bug" misc.save_failed = "ERREUR : partie non sauvegardée." -- Much more french tooltip.policy.diag_termination = "L'auscultation d'un patient continuera jusqu'à ce que les médecins soient sûrs à hauteur du pourcentage FIN PROCEDURE ou jusqu'à ce que toutes les machines de diagnostic aient été essayées. " -- Remove a superfluous word -room_descriptions.gp[2] = "C'est une salle de diagnostic fondamentale pour votre hôpital. Elle accueille les nouveaux patients pour les ausculter. Ils sont ensuite orientés vers une autre salle soit pour un autre diagnostic soit pour Etre soignés. Vous devriez construire un autre cabinet de médecine générale au cas où celui-ci serait débordé. Plus l'endroit est grand et plus vous pouvez y placer des équipements, sans compter que c'est bon pour le prestige du médecin. C'est valable pour toutes les salles, en fait." -room_descriptions.staff_room[2] = "Votre équipe finit par se fatiguer et a besoin de cette salle pour se remettre. Une équipe fatiguée est lente, revendicatrice et peut même envisager de démissionner. De plus, elle risque de commettre des erreurs. Il est avisé de construire une salle de repos bien aménagée et de prévoir assez de place pour plusieurs membres à la fois." -adviser.goals.win = { -- Why are this strings upcase? - reputation = "Portez votre réputation à %d pour pouvoir gagner.", - value = "Portez la valeur de votre hôpital à %d.", +adviser.goals = { + win = { -- Why are these strings uppercase? + reputation = "Portez votre réputation à %d pour pouvoir gagner.", + value = "Portez la valeur de votre hôpital à %d.", + } } -adviser.warnings.handymen_tired = "Les agents de maintenance sont très fatigués. Laissez-les se reposer." -- Add a missing letter +adviser.goals.lose.kill = "Tuez encore %d patients pour perdre !" -- tooltip.staff_list.next_person, prev_person is rather next/prev page (also in german, maybe more languages?) tooltip.staff_list.next_person = "Voir la page suivante" @@ -40,7 +39,7 @@ -- Improve tooltips in staff window to mention hidden features tooltip.staff_window.face = "Visage - cliquez pour ouvrir la fenêtre de gestion" -tooltip.staff_window.center_view = "Clic gauche pour focaliser sur la personne, pour faire défiler les membres du personnel" +tooltip.staff_window.center_view = "clic gauche pour focaliser sur la personne, pour faire défiler les membres du personnel" -- Fix Winning texts letter = { @@ -106,13 +105,13 @@ }, } --- The originals of these string lacks space before punctuation marks and or between words +-- The originals of some of these string lack a space before punctuation marks and or between words misc.balance = "Ajustage :" tooltip.pay_rise_window.decline = "Ne payez pas, licenciez !" tooltip.watch = { emergency = "Urgence : temps qui reste pour soigner les patients entrés en urgence.", hospital_opening = "Délai : ceci est le temps qui reste avant que votre hôpital soit ouvert. Cliquez sur GO pour l'ouvrir tout de suite.", - epidemic = "Epidémie : temps qui reste pour arrêter l'épidémie. Si ce délai expire OU si un malade contagieux quitte l'hôpital, un inspecteur sanitaire viendra... Le bouton active ou désactive la vaccination. Cliquez sur un patient pour lancer la vaccination par une infermière.", + epidemic = "Épidémie : temps qui reste pour arrêter l'épidémie. Si ce délai expire OU si un malade contagieux quitte l'hôpital, un inspecteur sanitaire viendra... Le bouton active ou désactive la vaccination. Cliquez sur un patient pour lancer la vaccination par une infirmière.", } tooltip.objects = { chair = "Chaise : le patient s'y assied pour parler de ses symptômes.", @@ -128,7 +127,7 @@ desk = "Bureau : essentiel pour poser un ordinateur.", pool_table = "Billard : pour la relaxation du personnel.", bed = "Lit : les cas graves ont besoin de rester couchés.", - bookcase = "Etagère : pour les ouvrages de référence.", + bookcase = "Étagère : pour les ouvrages de référence.", drinks_machine = "Distributeurs : contre la soif et pour ramasser des gros sous.", skeleton = "Squelette : utile pour l'enseignement et pour Halloween.", computer = "Ordinateur : une composante essentielle de la recherche.", @@ -143,12 +142,36 @@ toilet_sink = "Lavabo : s'il n'y en a pas assez, les patients qui apprécient l'hygiène seront mécontents.", cabinet = "Placard : dossiers des patients, notes de recherche.", } -room_descriptions.fracture_clinic[2] = "Les patients dont les os étaient en morceaux se rendront dans cette salle. Le déplâtreur dégagera les membres en ne causant qu'une faible douleur." -room_descriptions.inflation[2] = "Les patients souffrant de l'affreuse-mais-si-drôle encéphalantiasis sont soignés à la salle de gonflage, où leur tête démesurée sera dégonflée puis regonflée à la bonne taille." -room_descriptions.hair_restoration[2] = "Les patients souffrant de sévère calvitie se rendront dans cette salle équipée d'un moumouteur. Un médecin utilisera la machine pour donner aux patients une nouvelle chevelure." -room_descriptions.electrolysis[2] = "Les patients souffrant de pilose viennent dans cette salle où une machine arrache les poils et scelle les pores selon un procédé qui n'est pas sans rappeler la cimentation." + +room_descriptions = { + gp = { + [2] = "C'est une salle de diagnostic fondamentale pour votre hôpital. Elle accueille les nouveaux patients pour les ausculter. Ils sont ensuite orientés vers une autre salle, soit pour un autre diagnostic soit pour être soignés. Vous devriez construire un autre cabinet de médecine générale au cas où celui-ci serait débordé. Plus l'endroit est grand et plus vous pouvez y placer des équipements, sans compter que c'est bon pour le prestige du médecin. C'est valable pour toutes les salles, en fait.", + }, + pharmacy = { + [2] = "Les patients dont le mal a été diagnostiqué et dont le traitement est un médicament peuvent se rendre à la pharmacie. Comme la recherche découvre toujours de nouveaux traitements, l'activité de cette salle est en constante évolution. Vous aurez à construire une autre pharmacie plus tard.", + }, + general_diag = { + [3] = "La salle de diagnostic nécessite un médecin. Il faut également un agent de maintenance pour un entretien périodique. ", + }, + fracture_clinic = { + [2] = "Les patients dont les os étaient en morceaux se rendront dans cette salle. Le déplâtreur dégagera les membres en ne causant qu'une faible douleur.", + }, + inflation = { + [2] = "Les patients souffrant de l'affreuse-mais-si-drôle encéphalantiasis sont soignés à la salle de gonflage, où leur tête démesurée sera dégonflée puis regonflée à la bonne taille.", + }, + hair_restoration = { + [2] = "Les patients souffrant de sévère calvitie se rendront dans cette salle équipée d'un moumouteur. Un médecin utilisera la machine pour donner aux patients une nouvelle chevelure.", + }, + electrolysis = { + [2] = "Les patients souffrant de pilose viennent dans cette salle où une machine arrache les poils et scelle les pores selon un procédé qui n'est pas sans rappeler la cimentation.", + }, + staff_room = { + [2] = "Votre équipe finit par se fatiguer et a besoin de cette salle pour se remettre. Une équipe fatiguée est lente, revendicatrice et peut même envisager de démissionner. De plus, elle risque de commettre des erreurs. Il est avisé de construire une salle de repos bien aménagée et de prévoir assez de place pour plusieurs membres à la fois.", + } +} + progress_report.too_hot = "Réglez le chauffage : on étouffe." -adviser.tutorial.build_pharmacy = "Félicitations ! Construisez maintenant une pharmacie et embauchez une infermière." +adviser.tutorial.build_pharmacy = "Félicitations ! Construisez maintenant une pharmacie et embauchez une infirmière." adviser.epidemic.serious_warning = "Cette maladie contagieuse est dangereuse. Vous devez prendre des mesures d'urgence !" adviser.staff_advice.too_many_doctors = "Il y a trop de médecins. Certains n'ont rien à faire !" adviser.earthquake.ended = "Ouh là ! J'ai cru que c'était la fin ! C'était du %d sur l'échelle de Richter." @@ -158,7 +181,7 @@ } adviser.vomit_wave.ended = "Ouf ! On dirait que le virus qui provoquait des nausées est enfin enrayé. Gardez l'hôpital propre, à l'avenir." adviser.research.new_available = "Nouveau : un(e) %s est disponible." -adviser.goals.lose.kill = "Tuez encore %d patients pour perdre !" +adviser.research.drug_improved_1 = "Le traitement contre la %s a été amélioré par votre département de recherche." adviser.warnings = { money_low = "Les fonds sont en baisse !", no_patients_last_month = "Pas de nouveaux patients le mois dernier. Honteux !", @@ -167,13 +190,14 @@ too_many_plants = "Il y a bien trop de plantes. C'est la jungle, ici !", many_killed = "Vous avez laissé mourir %d personnes. Idiot ! Vous êtes censé les soigner.", falling_1 = "Hé ! Ce n'est pas drôle, regardez ou vous cliquez, quelqu'un pourrait être blessé !", - falling_2 = "Arrêtez de faire n'importe quoi, vous en pensez quoi ?", + falling_2 = "Arrêtez de faire n'importe quoi, qu'en penseriez-vous à leur place ?", falling_3 = "Aïe, ça doit faire mal, qu'on appelle un médecin !", falling_4 = "C'est un hôpital, pas un parc d'attraction !", falling_5 = "Ce n'est pas un endroit pour bousculer les gens, ils sont malades vous savez ?", falling_6 = "Ce n'est pas un bowling, les gens malades ne devraient pas être traités comme ça !", + handymen_tired = "Les agents de maintenance sont très fatigués. Laissez-les se reposer.", -- Add a missing letter } -adviser.placement_info.object_cannot_place = "Hé ! Vous ne pouvez pas mettre cet objet ici." +adviser.placement_info.object_cannot_place = "Hé ! Vous ne pouvez pas placer cet objet ici." adviser.information = { epidemic = "Une maladie contagieuse sévit dans votre hôpital. Vous devez l'enrayer immédiatement !", emergency = "C'est une urgence ! Vite ! Vite ! VITE !", @@ -183,6 +207,7 @@ patient_leaving_too_expensive = "Un patient part sans payer la facture pour %s. Sacrée perte !", vip_arrived = "Attention ! %s arrive pour visiter votre hôpital ! Faites en sorte de lui faire bonne impression.", first_death = "Vous venez de tuer votre premier patient. Alors, heureux ?", + promotion_to_specialist = "L'un de vos MÉDECIN est devenu un SPÉCIALISTE.", -- Fix the famous "Level 5 bug" } buy_objects_window = { price = "Prix : ", @@ -190,9 +215,9 @@ } fax = { epidemic_result = { - close_text = "Hourrah !", - rep_loss_fine_amount = "Les journaux vont s'en donner à coeur joie avec cette affaire. Votre réputation va en prendre un coup ! Sans oublier l'amende de %d.", - }, + close_text = "Hourra !", + rep_loss_fine_amount = "Les journaux vont s'en donner à cœur joie avec cette affaire. Votre réputation va en prendre un coup ! Sans oublier l'amende de %d.", + }, vip_visit_result = { telegram = "Télégramme !", vip_remarked_name = "Après avoir visité votre hôpital, %s a dit : ", @@ -216,8 +241,12 @@ }, diagnosis_failed = { what_to_do_question = "Que faire du patient ?", + partial_diagnosis_percentage_name = "Il y a %d pour cent de chances que la maladie soit %s." }, } +fax.epidemic.declare_explanation_fine = "Si vous déclarez l'épidémie, vous aurez une amende de %d, un changement de réputation et tous les patients seront vaccinés automatiquement." +fax.emergency.num_disease = "Il y a %d personnes atteintes de %s qui ont besoin de soins immédiats." + dynamic_info = { patient = { actions = { @@ -229,28 +258,7 @@ diagnosed = "Ausculté : %s", } } -introduction_texts = { - level1 = { - [1] = "Bienvenue dans votre premier hôpital !", - }, - level8 = { - [4] = "Ratissez tous ces malades !", - }, - level12 = { - [1] = "Côté défi, vous allez être servi !", - [4] = "Alors, heureux ?", - }, - level13 = { - [4] = "Vous pensez y arriver ?", - }, - level14 = { - [1] = "Et encore un défi ! Eh oui, voici l'hôpital-surprise !", - [4] = "Bonne chance !", - }, - level17 = { - [3] = "A vous de jouer, maintenant. Bonne chance et tout ça, quoi !", - } -} + transactions = { cure_colon = "Guérison :", final_treat_colon = "Trait final :", @@ -379,7 +387,7 @@ gastric_ejections = { cause = "Cause : nourriture mexicaine ou indienne très épicée.", cure = "Traitement : administration par voie orale d'une solution spéciale pour endiguer les rejets.", - name = "Ejections gastriques", + name = "Éjections gastriques", symptoms = "Symptômes : le patient rejette par accès des bribes de nourriture mal digérée.", }, uncommon_cold = { @@ -396,7 +404,7 @@ }, sleeping_illness = { cause = "Cause : hypertrophie de la glande palatale de Morphée.", - cure = "Traitement : une infermière administre une forte dose d'un puissant stimulant.", + cure = "Traitement : une infirmière administre une forte dose d'un puissant stimulant.", name = "Roupillance", symptoms = "Symptômes : tendance irrépressible à tomber de sommeil.", }, @@ -420,7 +428,7 @@ }, gut_rot = { cause = "Cause : la Bonne Vieille Bibine de la Mère Sam.", - cure = "Traitement : une infermière doit administrer diverses substances chimiques pour tenter de colmater le tout.", + cure = "Traitement : une infirmière doit administrer diverses substances chimiques pour tenter de colmater le tout.", name = "Tripurulente", symptoms = "Symptômes : aucun microbe mais plus de paroi intestinale non plus.", }, @@ -480,7 +488,7 @@ }, chronic_nosehair = { cause = "Cause : avoir reniflé avec dédain à la vue de plus malheureux que soi.", - cure = "Traitement : une épouvantable potion dépilatoire est administrée par une infermière à la pharmacie.", + cure = "Traitement : une épouvantable potion dépilatoire est administrée par une infirmière à la pharmacie.", name = "Poilonisme", symptoms = "Symptômes : poils au nez si drus qu'un oiseau pourrait y nicher.", }, @@ -498,22 +506,14 @@ -- The originals of these strings contain one space too much trophy_room.sold_drinks.trophies[2] = "Vous recevez le prix Bubulles du Syndicat des Vendeurs de Limonade pour récompenser la quantité de sodas vendus dans votre hôpital au cours de l'année écoulée. " -fax.epidemic.declare_explanation_fine = "Si vous déclarez l'épidémie, vous aurez une amende de %d, un changement de réputation et tous les patients seront vaccinés automatiquement." -fax.diagnosis_failed.partial_diagnosis_percentage_name = "Il y a %d pour cent de chances que la maladie soit %s." + tooltip.status.percentage_cured = "Vous devez soigner %d%% des visiteurs de l'hôpital. Actuellement, vous en avez soigné %d%%" tooltip.status.num_cured = "L'objectif est de soigner %d personnes. Pour le moment, vous en avez soigné %d" dynamic_info.staff.actions.going_to_repair = "Pour réparer %s" adviser.staff_place_advice.only_doctors_in_room = "Seuls les médecins peuvent travailler en %s" adviser.staff_place_advice.nurses_cannot_work_in_room = "Les infirmières ne peuvent travailler en %s" -room_descriptions.gp[2] = "C'est une salle de diagnostic fondamentale pour votre hôpital. Elle accueille les nouveaux patients pour les ausculter. Ils sont ensuite orientés vers une autre salle soit pour un autre diagnostic soit pour Etre soignés. Vous devriez construire un autre cabinet de médecine générale au cas où celui-ci serait débordé. Plus l'endroit est grand et plus vous pouvez y placer des équipements, sans compter que c'est bon pour le prestige du médecin. C'est valable pour toutes les salles, en fait." -room_descriptions.pharmacy[2] = "Les patients dont le mal a été diagnostiqué et dont le traitement est un médicament peuvent se rendre à la pharmacie. Comme la recherche découvre toujours de nouveaux traitements, l'activité de cette salle est en constante évolution. Vous aurez à construire une autre pharmacie plus tard." -room_descriptions.general_diag[3] = "La salle de diagnostic nécessite un médecin. Il faut également un agent de maintenance pour un entretien périodique. " pay_rise.definite_quit = "Rien ne me fera rester ici. J'en ai assez." place_objects_window.confirm_or_buy_objects = "Vous pouvez valider ainsi ou bien soit acheter soit déplacer des objets." -fax.emergency.num_disease = "Il y a %d personnes atteintes de %s qui ont besoin de soins immédiats." - --- The demo does not contain this string -menu_file.restart = " RELANCER " ----------------------------------------------------------- New strings ----------------------------------------------------------- @@ -525,58 +525,29 @@ object.litter = "Déchet" tooltip.objects.litter = "Déchet : laissé sur le sol par un patient car il n'a pas trouvé de poubelle où le jeter." --- Adviser -adviser = { - room_forbidden_non_reachable_parts = "Placer la pièce à cet endroit va empêcher des parties de l'hôpital d'être atteintes.", +tooltip.fax.close = "Fermer cette fenêtre sans supprimer le message" +tooltip.message.button = "clic gauche pour ouvrir le message" +tooltip.message.button_dismiss = "clic gauche pour ouvrir le message, clic droit pour le rejeter" +tooltip.casebook.cure_requirement.hire_staff = "Vous devez embaucher du personnel pour gérer ce traitement" +tooltip.casebook.cure_type.unknown = "Vous ne savez pas encore comment traiter cette maladie" +tooltip.research_policy.no_research = "Aucune recherche n'est actuellement effectuée dans cette catégorie" +tooltip.research_policy.research_progress = "Progrès vers la prochaine découverte dans cette catégorie : %1%/%2%" - warnings = { - no_desk = "Vous devriez construire un bureau de réception et engager une réceptionniste un de ces jours !", - no_desk_1 = "Si vous voulez que des patients viennent dans votre hôpital, vous devez embaucher une réceptionniste et lui construire un bureau pour travailler !", - no_desk_2 = "Bien joué, ça doit être un record : presque un an et pas de patient ! Si vous voulez continuer comme directeur de cet hôpital, vous devez embaucher une réceptionniste et lui construire un bureau pour travailler !", - no_desk_3 = "C'est tout simplement génial, presque un an et vous n'avez pas embauché de réceptionniste ! Comment espérez obtenir le moindre patient ? Arrangez-ça et arrêtez de perdre votre temps !", - cannot_afford = "Vous n'avez pas assez d'argent à la banque pour embaucher cette personne !",-- I can't see anything like this in the original strings - research_screen_open_1 = "Vous devez construire une salle de recherche avant de pouvoir accéder à l'écran des recherches.", - research_screen_open_2 = "La recherche est désactivée pour le niveau en cours." - }, - cheats = { - th_cheat = "Félicitations, vous avez débloqué les triches !", - crazy_on_cheat = "Oh non ! Tous les médecins sont devenus fous !", - crazy_off_cheat = "Ouf... les médecins ont retrouvé leur santé mentale.", - roujin_on_cheat = "Défi de Roujin activé ! Bonne chance...", - roujin_off_cheat = "Défi de Roujin désactivé.", - hairyitis_cheat = "Triche Pilose activée !", - hairyitis_off_cheat = "Triche Pilose désactivée.", - bloaty_cheat = "Triche Encéphalantiasis activée !", - bloaty_off_cheat = "Triche Encéphalantiasis désactivée.", - }, +menu_file = { + load = " (SHIFT+L) CHARGER ", + save = " (SHIFT+S) ENREGISTRER ", + restart = " (SHIFT+R) RELANCER", + quit = " (SHIFT+Q) QUITTER ", } - --- Dynamic information -dynamic_info.patient.actions.no_gp_available = "Attente d'un cabinet de médecine générale" -dynamic_info.staff.actions.heading_for = "Va vers %s" -dynamic_info.staff.actions.fired = "Renvoyé" - --- Progress report -progress_report.free_build = "CONSTRUCTION LIBRE" - --- Misc -misc.not_yet_implemented = "(pas encore implémenté)" -misc.no_heliport = "Aucune maladie n'a été découverte pour l'instant, ou il n'y a pas d'héliport sur cette carte." - -- Options menu menu_options = { lock_windows = " FIGER LES FENETRES ", edge_scrolling = " DEFILEMENT PAR BORD ", - settings = " PARAMETRES ", adviser_disabled = " ASSISTANT ", warmth_colors = " COULEURS CHAUDES ", - } - - menu_options_warmth_colors = { - choice_1 = " ROUGE ", - choice_2 = " BLEU VERT ROUGE ", - choice_3 = " JAUNE ORANGE ROUGE ", + wage_increase = " AUGMENTATION DE SALAIRE ", + twentyfour_hour_clock = " HORLOGE 24 HEURES ", } menu_options_game_speed = { @@ -587,7 +558,17 @@ max_speed = " (4) VITESSE MAXI ", and_then_some_more = " (5) ET ENCORE PLUS ", } -menu_options_game_speed.pause = " PAUSE " + +menu_options_warmth_colors = { + choice_1 = " ROUGE ", + choice_2 = " BLEU VERT ROUGE ", + choice_3 = " JAUNE ORANGE ROUGE ", +} + +menu_options_wage_increase = { + grant = " ACCORDER ", + deny = " REFUSER ", +} -- Charts Menu ' Temporary; must see in-game for correct translation menu_charts = { @@ -595,7 +576,7 @@ statement = " (F2) DECLARATION ", staff_listing = " (F3) LISTE DU PERSONNEL ", town_map = " (F4) CARTE DE LA VILLE ", - casebook = " (F5) MALETTE ", + casebook = " (F5) MALLETTE ", research = " (F6) RECHERCHE ", status = " (F7) STATUTS ", graphs = " (F8) GRAPHIQUES ", @@ -605,24 +586,27 @@ -- Debug menu menu_debug = { jump_to_level = " ALLER AU NIVEAU ", + connect_debugger = " (CTRL + C) CONNECTER AU SERVEUR DE DÉBOGUAGE ", transparent_walls = " (X) MURS TRANSPARENTS ", limit_camera = " LIMITER LA CAMERA ", - disable_salary_raise = " DESACTIVER LES AUGMENTATIONS DE SALAIRE ", - make_debug_fax = " CREER UN FAX DE TEST ", - make_debug_patient = " CREER UN PATIENT DE TEST ", + disable_salary_raise = " DÉSACTIVER LES AUGMENTATIONS DE SALAIRE ", + make_debug_fax = " CRÉER UN FAX DE TEST ", + make_debug_patient = " CRÉER UN PATIENT DE TEST ", cheats = " (F11) TRICHES ", lua_console = " (F12) CONSOLE LUA ", - calls_dispatcher = " REPARTITION DES TACHES ", + debug_script = " (MAJ + DS) ACTIVER LE DÉBOGUAGE PAR SCRIPT ", + calls_dispatcher = " RÉPARTITION DES TÂCHES ", dump_strings = " EXTRAIRE LES TEXTES ", dump_gamelog = " (CTRL+D) EXTRAIRE LE JOURNAL DE JEU ", map_overlay = " INCRUSTATIONS DE CARTE ", sprite_viewer = " VISIONNEUSE DE SPRITES ", } + menu_debug_overlay = { none = " AUCUN ", flags = " DRAPEAUX ", positions = " POSITIONS ", - heat = " TEMPERATURE ", + heat = " TEMPÉRATURE ", byte_0_1 = " OCTETS 0 & 1 ", byte_floor = " OCTET SOL ", byte_n_wall = " OCTET MUR N ", @@ -633,49 +617,124 @@ parcel = " PARCELLE ", } +menu_player_count = { + players_1 = " 1 JOUEUR ", + players_2 = " 2 JOUEURS ", + players_3 = " 3 JOUEURS ", + players_4 = " 4 JOUEURS ", +} + +-- Adviser +adviser = { + room_forbidden_non_reachable_parts = "Placer la pièce à cet endroit rendrait inaccessibles certaines parties de l'hôpital", + + warnings = { + no_desk = "Vous devriez construire un bureau de réception et engager une réceptionniste un de ces jours !", + no_desk_1 = "Si vous voulez que des patients viennent dans votre hôpital, vous devez embaucher une réceptionniste et lui construire un bureau pour travailler !", + no_desk_2 = "Bien joué, ça doit être un record : presque un an et pas de patient ! Si vous voulez continuer comme directeur de cet hôpital, vous devez embaucher une réceptionniste et lui construire un bureau pour travailler !", + no_desk_3 = "C'est tout simplement génial, presque un an et vous n'avez pas embauché de réceptionniste ! Comment espérez obtenir le moindre patient ? Arrangez-ça et arrêtez de perdre votre temps !", + no_desk_4 = "Une réceptionniste aura besoin d'un bureau pour accueillir des patients", + no_desk_5 = "Il était temps, maintenant les patients devraient commencer à arriver bientôt !", + no_desk_6 = "Vous avez une réceptionniste, peut-être il est temps de construire un bureau où elle peut travailler ?", + no_desk_7 = "Maintenant, que vous avez une réception, que diriez-vous d'embaucher une réceptionniste également ? Vous n'aurez pas de patients avant de l'avoir fait !", + cannot_afford = "Vous n'avez pas assez d'argent à la banque pour embaucher cette personne !",-- I can't see anything like this in the original strings + cannot_afford_2 = "Vous n'avez pas assez d'argent à la banque pour effectuer l'achat !", + research_screen_open_1 = "Vous devez construire une salle de recherche avant de pouvoir accéder à l'écran des recherches.", + research_screen_open_2 = "La recherche est désactivée pour le niveau en cours.", + researcher_needs_desk_1 = "Chaque chercheur a besoin d'un bureau pour travailler.", + researcher_needs_desk_2 = "Vos chercheurs sont heureux d'obtenir une pause bien méritée. Si vous voulez que plusieurs chercheurs puissent travailler en même temps.", + researcher_needs_desk_3 = "Un chercheur a toujours besoin d'un bureau.", + nurse_needs_desk_1 = "Chaque infirmière a besoin de son propre bureau.", + nurse_needs_desk_2 = "Votre infirmière est heureuse d'avoir une pause. Si vous comptez y faire travailler plusieurs personnes en même temps, vous devez leur construire un bureau à chacune.", + low_prices = "Vous facturez trop peu pour %s. Ça va amener des gens dans votre hôpital, mais vous ne ferez pas beaucoup de profit sur chacun d'eux.", + high_prices = "Votre tarif pour %s est trop élevé. Ça va générer plus de profit sur le court-terme, mais à la longue les gens vont fuir.", + fair_prices = "Le prix pour %s semble juste et équilibré.", + patient_not_paying = "Un patient est parti sans payer pour %s parce que c'est trop cher !", + }, + cheats = { + th_cheat = "Félicitations, vous avez débloqué les triches !", + roujin_on_cheat = "Défi de Roujin activé ! Bonne chance...", + roujin_off_cheat = "Défi de Roujin désactivé.", + }, +} + +-- Dynamic information +dynamic_info.patient.actions.no_gp_available = "Attente d'un cabinet de médecine générale" +dynamic_info.staff.actions.heading_for = "Va vers %s" +dynamic_info.staff.actions.fired = "Renvoyé" +dynamic_info.patient.actions.epidemic_vaccinated = "Je ne suis plus contagieux" + +-- Progress report +progress_report.free_build = "CONSTRUCTION LIBRE" + +-- Fax messages +fax = { + choices = { + return_to_main_menu = "Retourner au menu principal", + accept_new_level = "Aller au niveau suivant", + decline_new_level = "Continuer la partie encore un peu", + }, + emergency = { + num_disease_singular = "Il y a 1 personne atteinte de %s qui a besoin de soins immédiats.", + free_build = "Si vous réussissez votre réputation augmentera mais si vous échouez votre réputation sera sérieusement entachée.", + }, + vip_visit_result = { + remarks = { + free_build = { + "C'est vraiment un bel hôpital que vous avez là ! Pas trop difficile d'y arriver sans limite d'argent, hein ?", + "Je ne suis pas économiste, mais je pense que je pourrais faire tourner cet hôpital aussi si vous voyez ce que je veux dire...", + "Un hôpital très bien tenu. Cependant, attention à la récession ! Ah oui... vous n'avez pas à vous soucier de cela.", + }, + }, + }, +} + +-- Winning texts +letter = { + dear_player = "Cher %s", + custom_level_completed = "Félicitations ! Vous avez réussi tous les objectifs de ce niveau personnalisé !", + return_to_main_menu = "Voulez-vous retourner au menu principal ou continuer la partie ?", + campaign_completed = "Incroyable ! Vous avez réussi à terminer tous les niveaux. Vous pouvez maintenant vous détendre et profiter de remplir des forums sur Internet de vos réalisations. Bonne chance !", + campaign_level_missing = "Désolé, mais le prochain niveau de cette campagne semble manquer. (Nom: %s)", + campaign_level_completed = "Bon travail ! Vous avez battu le niveau. Mais ce n'est pas fini !\n Aimeriez-vous un poste à l'hôpital %s ?", +} + +-- Installation +install = { + title = "----------------------------- Installation de CorsixTH -----------------------------", + th_directory = "CorsixTH nécessite une copie des données du jeu Theme Hospital originel (ou la démo) pour fonctionner. Veuillez utiliser le sélecteur ci-dessous pour indiquer le dossier d'installation de Theme Hospital.", + ok = "OK", + exit = "Quitter", + cancel = "Annuler", +} + +-- Misc +misc.not_yet_implemented = "(pas encore implémenté)" +misc.no_heliport = "Aucune maladie n'a été découverte pour l'instant, ou il n'y a pas d'héliport sur cette carte." + -- Main menu main_menu = { new_game = "Nouvelle partie", custom_level = "Niveau personnalisé", + continue = "Continuer la partie", load_game = "Charger une partie", options = "Options", savegame_version = "Version de la sauvegarde : ", version = "Version : ", exit = "Quitter", + map_edit = "Éditeur de carte", + custom_campaign = "Campagne personnalisée", } tooltip.main_menu = { - new_game = "Commencer une partie totalement nouvelle", + new_game = "Commencer une nouvelle partie", custom_level = "Construire votre hôpital dans un niveau personnalisé", + continue = "Continuer la partie", load_game = "Charger une partie sauvegardée", options = "Modifier quelques paramètres", exit = "Non, non, SVP, ne quittez pas !", -} - ---- New game window -new_game_window = { - easy = "Interne (Facile)", - medium = "Médecin (Moyen)", - hard = "Consultant (Difficile)", - tutorial = "Tutoriel", - cancel = "Annuler", - option_on = "Marche", - option_off = "Arrêt", - difficulty = "Difficulté", - caption = "Campagne", - player_name = "Nom du joueur", - start = "Démarrer", -} - -tooltip.new_game_window = { - easy = "Si vous jouez pour la première fois à un jeu de simulation, cette option est pour vous", - medium = "C'est la voie du milieu à prendre si vous ne savez pas quoi choisir", - hard = "Si vous êtes habitué à ce genre de jeu et que vous souhaitez plus d'un défi, choisissez cette option", - tutorial = "Si vous voulez un peu d'aide pour démarrer une fois dans le jeu, cochez cette case", - cancel = "Oh, je n'avais pas vraiment l'intention de commencer une nouvelle partie !", - difficulty = "Sélectionnez le niveau de difficulté que vous voulez dans le jeu", - start = "Démarrer le jeu avec les paramètres sélectionnés", - player_name = "Entrez le nom avec lequel vous voulez être appelé dans le jeu", + map_edit = "Créer une carte personnalisée", + custom_campaign = "Jouer une campagne créée par la communauté", } -- Load game window @@ -696,8 +755,20 @@ } tooltip.custom_game_window = { - start_game_with_name = "Charger le niveau %s", free_build = "Cochez cette case si vous souhaitez jouer sans limite d'argent et sans conditions de victoire ou de défaite", + choose_game = "Cliquez sur un niveau pour en savoir plus", + load_selected_level = "Charger et jouer le niveau sélectionné", +} + +-- Custom campaign window +custom_campaign_window = { + caption = "Campagne personnalisée", + start_selected_campaign = "Démarrer la campagne", +} + +tooltip.custom_campaign_window = { + choose_campaign = "Choisissez une campagne pour en savoir plus à son sujet", + start_selected_campaign = "Charger le premier niveau de cette campagne", } -- Save game window @@ -711,6 +782,16 @@ new_save_game = "Entrez un nom pour la sauvegarde", } +save_map_window = { + caption = "Sauvegarder la carte (%1%)", + new_map = "Nouvelle carte", +} + +tooltip.save_map_window = { + map = "Ecraser la carte %s", + new_map = "Entrez le nom pour une sauvegarde de la carte", +} + -- Menu list window menu_list_window = { back = "Précédent", @@ -726,48 +807,106 @@ -- Options window options_window = { - fullscreen = "Plein écran", + fullscreen = "Plein Écran", width = "Largeur", height = "Hauteur", change_resolution = "Changer la résolution", - browse = "Parcourir...", - new_th_directory = "Ici, vous pouvez spécifier un nouveau dossier d'installation de Theme Hospital. Dès que vous aurez changé le répertoire, le jeu sera redémarré.", cancel = "Annuler", back = "Précédent", custom_resolution = "Personnaliser...", - option_on = "Marche", - option_off = "Arrêt", + option_on = "Activer", + option_off = "Désactiver", caption = "Paramètres", language = "Langue du jeu", apply = "Appliquer", - data_location = "Emplacement des données", - font_location = "Emplacement de la police", resolution = "Résolution", + audio = "Audio Global", + folder = "Dossier", + customise = "Personnaliser", } tooltip.options_window = { + fullscreen = "Mode plein écran ou mode fenêtré", fullscreen_button = "Basculer en mode plein écran/fenêtré", + resolution = "La résolution vidéo pour le jeu", + select_resolution = "Sélectionner une nouvelle résolution", width = "Entrez la largeur désirée", height = "Entrez la hauteur désirée", change_resolution = "Changer la résolution pour les dimensions entrées à gauche", language = "Utiliser la langue %s", - original_path = "Le dossier d'installation du Theme Hospital originel qui est actuellement sélectionné", - browse = "Choisir un autre emplacement d'installation de Theme Hospital %1%", back = "Fermer la fenêtre des options", - fullscreen = "Mode plein écran ou mode fenêtré", cancel = "Retour sans changement de résolution", - font_location = "Emplacement d'un fichier de police capable d'afficher des caractères Unicodes requis par votre langue. Si rien n'est spécifié, vous ne serez pas capable de sélectionner une langue qui nécessite plus de caractères que ne peut en fournir le jeu original. Par exemple : Russe et Chinois", apply = "Appliquer la résolution choisie", - browse_font = "Parcourir les dossiers pour un autre fichier de police (Emplacement actuel : ù1ù)", - data_location = "Le dossier d'installation du jeu original Theme Hospital, requis pour lancer CorsixTH", language_dropdown_item = "Choisir %s comme langue", select_language = "Sélectionner la langue du jeu", - select_resolution = "Sélectionner une nouvelle résolution", - resolution = "La résolution vidéo pour le jeu", - no_font_specified = "Aucun emplacement spécifié !", + audio_button = "Activer ou désactiver le système audio dans le jeu", + audio_toggle = "Activer ou désactiver", + folder_button = "Dossier des paramètres", + customise_button = "Paramètres supplémentaires qui peuvent être modifiés pour personnaliser votre expérience de jeu", +} + +customise_window = { + caption = "Paramètres Supplémentaires", + option_on = "Activer", + option_off = "Désactiver", + back = "Retour", + movies = "Contrôle des cinématiques", + intro = "Jouer la cinématique d'intro", + paused = "Construction en pause", + volume = "Touche de raccourci pour diminuer le volume", + aliens = "Extraterrestres", + fractured_bones = "Fractures", + average_contents = "Achats mémorisés", +} + +tooltip.customise_window = { + movies = "Sélectionnez si les cinématiques doivent être joués.", + intro = "Passer la cinématique d'introduction lorsque vous démarrez le jeu. Le contrôle des cinématiques doit être activé si vous jouez la cinématique d'introduction à chaque fois que vous chargez CorsixTH", + paused = "Dans Theme Hospital le joueur ne sera autorisé à utiliser le menu principal que si le jeu est en pause. C'est le paramètre par défaut dans CorsixTH aussi, mais en l'activant tout est permis pendant que le jeu est en pause", + volume = "Si la touche de réduction du volume ouvre également le journal de médecine, activer cette option pour modifier le raccourci des dossiers médicaux à Maj + C", + aliens = "Comme il y a des animations appropriées, nous avons fait de sorte que les patients avec l'ADN extraterrestre montrent seulement comme des situations d'urgence. Désactivez cette option pour obtenir cas de l'ADN extraterrestre visites régulières", + fractured_bones = "En raison de la qualité faible de l'animation il n'y a pas de patientes avec des fractures. Désactivez cette option si vous désirez avoir des femmes avec des fractures.", + average_contents = "Si vous voulez que le jeu se rappelle des articles supplémentaires que vous avez tendance à normalement magasiner pour une nouvelle salle, activer cette option", + back = "Fermer ce menu et revenir au menu d'options", +} + +folders_window = { + caption = "Paramètres de dossier", + data_label = "Données de TH", + font_label = "Police", + music_label = "MP3", + savegames_label = "Sauvegarde", + screenshots_label = "Captures d'écran", + -- next four are the captions for the browser window, which are called from the folder setting menu + new_th_location = "Ici vous pouvez spécifier un nouveau répertoire d'installation de Theme Hospital. Dès que vous choisissez le nouveau répertoire, le jeu sera redémarré.", + savegames_location = "Sélectionner le répertoire que vous voulez utiliser pour les sauvegardes", + music_location = "Sélectionner le répertoire que vous voulez utiliser pour la musique", + screenshots_location = "Sélectionner le répertoire que vous voulez utiliser pour les captures d'écran", + back = "Retour", +} + +tooltip.folders_window = { + browse = "Parcourir l'emplacement du dossier", + data_location = "Le répertoire d'origine de l'installation de Theme Hospital, qui est requis pour faire fonctionner CorsixTH", + font_location = "Emplacement d'un fichier de police qui est capable d'afficher des caractères Unicode requises par votre langue. Si aucun emplacement n'est spécifié vous ne serez pas en mesure de choisir des langues qui ont des caractères que le jeu original ne peut pas fournir. Exemple : Russe et Chinois", + savegames_location = "Par défaut, le répertoire de sauvegardes est à côté du fichier de configuration et sera utilisé pour stocker les sauvegardes. Si cela n'est pas approprié vous pouvez modifier ce répertoire.", + screenshots_location = "Par défaut, les captures d'écran sont stockés dans un dossier avec le fichier de configuration. Si cela ne convient pas vous pouvez choisir votre propre dossier.", + music_location = "Sélectionnez un emplacement pour vos fichiers MP3.", + browse_data = "Parcourir un autre emplacement d'une installation de Theme Hospital (emplacement actuel : %1%)", + browse_font = "Parcourir un autre fichier de police (emplacement actuel : %1%)", + browse_saves = "Parcourir un autre répertoire de sauvegardes (emplacement actuel : %1%)", + browse_screenshots = "Parcourir un autre répertoire de captures d'écrans (emplacement actuel : %1%)", + browse_music = "Parcourir un autre répertoire de musique (emplacement actuel : %1%)", + no_font_specified = "Aucun répertoire de police spécifié !", + not_specified = "Aucun répertoire spécifié !", + default = "Emplacement par défaut", + reset_to_default = "Réinitialiser le répertoire à son emplacement par défaut", + back = "Fermer ce menu et revenir au menu Paramètres", } -font_location_window.caption = "Choisir une police (%1%)" +font_location_window = { + caption = "Choisir une police (%1%)", +} -- Handyman window handyman_window = { @@ -779,48 +918,87 @@ parcel_select = "Les parcelles où les agents de maintenance peuvent travailler : cliquez pour changer le paramètre.", } --- Debug patient window -debug_patient_window = { - caption = "Patient de test", +--- New game window +new_game_window = { + easy = "Interne (Facile)", + medium = "Médecin (Moyen)", + hard = "Consultant (Difficile)", + tutorial = "Tutoriel", + cancel = "Annuler", + option_on = "Activer", + option_off = "Désactiver", + difficulty = "Difficulté", + caption = "Campagne", + player_name = "Nom du joueur", + start = "Démarrer", } --- Cheats window -cheats_window = { - caption = "Triches", - warning = "Attention : vous n'aurez aucun point de bonus à la fin du niveau si vous trichez !", - cheated = { - no = "Triches utilisées : non", - yes = "Triches utilisées : oui", - }, - cheats = { - money = "Plus d'argent", - all_research = "Toutes les recherches", - emergency = "Créer une urgence", - vip = "Créer un VIP", - earthquake = "Créer un tremblement de terre", - create_patient = "Créer un patient", - end_month = "Fin du mois", - end_year = "Fin de l'année", - lose_level = "Perdre le niveau", - win_level = "Gagner le niveau", - }, +tooltip.new_game_window = { + easy = "Si vous jouez pour la première fois à un jeu de simulation, cette option est pour vous", + medium = "C'est la voie du milieu à prendre si vous ne savez pas quoi choisir", + hard = "Si vous êtes habitué à ce genre de jeu et que vous souhaitez plus d'un défi, choisissez cette option", + tutorial = "Si vous voulez un peu d'aide pour démarrer une fois dans le jeu, cochez cette case", + cancel = "Oh, je n'avais pas vraiment l'intention de commencer une nouvelle partie !", + difficulty = "Sélectionnez le niveau de difficulté que vous voulez dans le jeu", + start = "Démarrer le jeu avec les paramètres sélectionnés", + player_name = "Entrez le nom par lequel vous voulez être appelé dans le jeu", +} + +-- Lua Console +lua_console = { + execute_code = "Exécuter", close = "Fermer", } -tooltip.cheats_window = { - close = "Fermer le dialogue de triches", - cheats = { - money = "Ajoute $10.000 à votre solde bancaire.", - all_research = "Termine toutes les recherches.", - emergency = "Crée une urgence.", - vip = "Crée un VIP.", - earthquake = "Crée un tremblement de terre.", - create_patient = "Crée un patient au bord de la carte.", - end_month = "Va directement à la fin du mois.", - end_year = "Va directement à la fin de l'année.", - lose_level = "Vous fait perdre le niveau actuel.", - win_level = "Vous fait gagner le niveau actuel.", - } +tooltip.lua_console = { + textbox = "Entrez du code Lua à exécuter ici", + execute_code = "Exécuter le code que vous avez entré", + close = "Fermer la console", +} + +-- Errors +errors = { + dialog_missing_graphics = "Désolé, les données de démo ne contiennent pas cette boîte de dialogue.", + save_prefix = "Erreur lors de la sauvegarde de la partie : ", + load_prefix = "Erreur lors du chargement de la partie : ", + no_games_to_contine = "Pas de parties sauvegardées.", + map_file_missing = "Impossible de trouver le fichier de carte %s pour ce niveau !", + minimum_screen_size = "Veuillez entrer une résolution supérieure à 640x480.", + unavailable_screen_size = "La résolution que vous avez demandée n'est pas disponible en plein écran.", + alien_dna = "NOTE : Il n'y a pas d'animations pour les patients étrangers pour s'asseoir, ouvrir ou de frapper aux portes, etc. Donc, comme avec Theme Hospital pour faire ces choses, ils semblent changer à la normale et ensuite changer de nouveau. Les patients avec l'ADN Alien apparaîtront seulement s'ils sont définis dans le fichier de niveau.", + fractured_bones = "NOTE : L'animation pour les patients de sexe féminin avec des os fracturés n'est pas parfaite.", + load_quick_save = "Erreur, impossible de charger la sauvegarde rapide car elle n'existe pas, ne vous inquiétez pas nous avons créé une pour vous !", +} + +-- Confirmation dialog +confirmation = { + needs_restart = "Changer ce paramètre va nécessiter un redémarrage de CorsixTH. Tout progrès non sauvegardé sera perdu. Êtes-vous sûr de vouloir faire cela ?", + abort_edit_room = "Vous êtes actuellement en train de construire ou d'éditer une pièce. Si tous les objets requis sont placés, elle sera validée, mais sinon elle sera détruite. Continuer ?", + maximum_screen_size = "La taille de l'écran que vous avez entrée est supérieure à 3000 x 2000. Des plus hautes résolutions sont possibles, mais il faudra un meilleur matériel afin de maintenir un taux de trame jouable. Êtes-vous sûr de vouloir continuer?", + music_warning = "Avant de choisir d'utiliser des MP3 pour votre musique dans le jeu, vous aurez besoin d'avoir smpeg.dll ou l'équivalent pour votre système d'exploitation, sinon vous n'aurez pas de musique dans le jeu. Voulez-vous continuer?", + could_not_load_campaign = "Impossible de charger la campagne : %s", + could_not_find_first_campaign_level = "Impossible de trouver le premier niveau de cette campagne : %s", +} + +-- Information dialog +information = { + custom_game = "Bienvenue dans CorsixTH. Amusez-vous bien avec cette carte personnalisée !", + no_custom_game_in_demo = "Désolé, mais dans la version démo vous ne pouvez jouer avec aucune des cartes personnalisées.", + cannot_restart = "Malheureusement cette partie personnalisée a été sauvegardée avant que la fonctionnalité de redémarrage soit implémentée.", + very_old_save = "Il y a eu beaucoup de mises à jour du jeu depuis que vous avez commencé ce niveau. Pour être sûr que tout fonctionne comme prévu, pensez à recommencer le niveau.", + cheat_not_possible = "Vous ne pouvez pas utiliser ce code de triche dans ce niveau. Vous n'arrivez même pas à tricher, pas marrant hein ?", + level_lost = { + "Quelle poisse ! Vous avez raté le niveau. Vous ferez mieux la prochaine fois !", + "Voilà pourquoi vous avez perdu : ", + reputation = "Votre réputation est tombée en dessous de %d.", + balance = "Votre solde bancaire est tombé en dessous %d.", + percentage_killed = "Vous avez tué plus de %d pourcents de vos patients.", + cheat = "Étais-ce votre choix, ou bien avez-vous appuyé sur le mauvais bouton ? Vous n'arrivez même pas à tricher correctement, n'est-ce pas désolant ?" + }, +} + +tooltip.information = { + close = "Fermer cette boîte de dialogue.", } -- "Tip of the day" window @@ -830,12 +1008,12 @@ "Les machines telles que le Gonflage ont besoin de maintenance. Embauchez un ou deux agents de maintenance pour réparer vos machines, ou vous risquerez d'avoir des blessés parmi le personnel ou les patients.", "Après un certain temps, vos employés seront fatigués. Pensez à construire une salle de repos où ils pourront se détendre.", "Placez suffisamment de radiateurs pour garder vos employés et patients au chaud, ou ils deviendront mécontents. Utilisez la carte de la ville pour localiser les endroits de votre hôpital qui nécessitent plus de chauffage.", - "Le niveau de compétence d'un docteur influence beaucoup la qualité et la rapidité de ses diagnostics. Utilisez un médecin expérimenté comme généraliste et vous n'aurez plus besoin d'autant de salles de diagnostics.", + "Le niveau de compétence d'un docteur influence beaucoup la qualité et la rapidité de ses diagnostiques. Utilisez un médecin expérimenté comme généraliste et vous n'aurez plus besoin d'autant de salles de diagnostiques.", "Les internes et les médecins peuvent augmenter leurs compétences auprès d'un consultant dans la salle de formation. Si le consultant a des qualifications particulières (chirurgien, psychiatre ou chercheur), il transférera ses connaissances à ses élèves.", "Avez-vous essayé d'entrer le numéro d'urgence Européen (112) dans le fax ? Vérifiez que vous avez du son !", "Vous pouvez ajuster certains paramètres tels que la résolution et la langue dans la fenêtre d'options accessible à la fois depuis le menu principal et pendant le jeu.", "Vous avez choisi une autre langue que l'anglais, mais il y du texte en anglais partout ? Aidez-nous à traduire les textes manquants dans votre langue !", - "L'équipe de CorsixTH cherche du renfort ! Vous êtes intéressé par coder, traduire ou faire des graphismes pour CorsixTH ? Contactez-nous sur notre Forum, Liste de Diffusion ou Canal IRC (#corsix-th sur freenode).", + "L'équipe de CorsixTH cherche du renfort ! Vous êtes intéressé à coder, traduire ou faire des graphismes pour CorsixTH ? Contactez-nous sur notre Forum, Liste de Diffusion ou Canal IRC (#corsix-th sur freenode).", "Si vous avez trouvé un bug, SVP, reportez-le sur notre gestionnaire de bugs : th-issues.corsix.org.", "Chaque niveau possède des objectifs qu'il vous faudra remplir pour pouvoir passer au suivant. Vérifiez la fenêtre de statuts pour voir votre progression dans les objectifs du niveau.", "Si vous voulez éditer ou détruire une pièce, vous pouvez le faire avec le bouton d'édition situé sur la barre d'outils en bas.", @@ -855,56 +1033,94 @@ next = "Afficher l'astuce suivante", } --- Lua Console -lua_console = { - execute_code = "Exécuter", - close = "Fermer", -} - -tooltip.lua_console = { - textbox = "Entrez du code Lua à exécuter ici", - execute_code = "Exécuter le code que vous avez entré", - close = "Fermer la console", -} - --- Confirmation dialog -confirmation = { - needs_restart = "Changer ce paramètre va nécessiter un redémarrage de CorsixTH. Tout progrès non sauvegardé sera perdu. Êtes-vous sûr de vouloir faire cela ?", - abort_edit_room = "Vous êtes actuellement en train de construire ou d'éditer une pièce. Si tous les objets requis sont placés, elle sera validée, mais sinon elle sera détruite. Continuer ?", +-- Debug patient window +debug_patient_window = { + caption = "Patient de test", } --- Information dialog -information = { - custom_game = "Bienvenue dans CorsixTH. Amusez-vous bien avec cette carte personnalisée !", - no_custom_game_in_demo = "Désolé, mais dans la version démo vous ne pouvez jouer avec aucune des cartes personnalisées.", - cannot_restart = "Malheureusement cette partie personnalisée a été sauvegardée avant que la fonctionnalité de redémarrage soit implémentée.", - very_old_save = "Il y a eu beaucoup de mises à jour du jeu depuis que vous avez commencé ce niveau. Pour être sûr que tout fonctionne comme prévu, pensez à recommencer le niveau.", - cheat_not_possible = "Vous ne pouvez pas utiliser cette triche à ce niveau. Vous n'arrivez même pas à tricher, pas marrant hein ?", - level_lost = { - "Quelle poisse ! Vous avez raté le niveau. Vous ferez mieux la prochaine fois !", - "Voilà pourquoi vous avez perdu : ", - reputation = "Votre réputation est tombée en dessous de %d.", - balance = "Votre solde bancaire est tombé en dessous %d.", - percentage_killed = "Vous avez tué plus de %d pourcents de vos patients.", - cheat_not_possible = "Vous ne pouvez pas utiliser cette triche à ce niveau. Vous n'arrivez même pas à tricher, pas marrant hein ?", - cheat = "Etais-ce votre choix, ou bien avez-vous appuyé sur le mauvais bouton ? Vous n'arrivez même pas à tricher correctement, n'est-ce pas désolant ?" +-- Cheats window +cheats_window = { + caption = "Triches", + warning = "Attention : vous n'aurez aucun point de bonus à la fin du niveau si vous trichez !", + cheated = { + no = "Triches utilisées : non", + yes = "Triches utilisées : oui", + }, + cheats = { + money = "Plus d'argent", + all_research = "Toutes les recherches", + emergency = "Créer une situation d'urgence", + vip = "Créer un VIP", + earthquake = "Créer un tremblement de terre", + create_patient = "Créer un patient", + end_month = "Fin du mois", + end_year = "Fin de l'année", + lose_level = "Perdre le niveau", + win_level = "Gagner le niveau", + epidemic = "Reproduire des patients contagieux", + toggle_infected = "Faire apparaître des patients contagieux.", + increase_prices = "Augmenter les prix", + decrease_prices = "Diminuer les prix", }, + close = "Fermer", } -tooltip.information = { - close = "Fermer cette boîte de dialogue.", +tooltip.cheats_window = { + close = "Fermer le dialogue de triches", + cheats = { + money = "Ajoute $10.000 à votre solde bancaire.", + all_research = "Termine toutes les recherches.", + emergency = "Crée une situation d'urgence.", + vip = "Crée un VIP.", + earthquake = "Crée un tremblement de terre.", + create_patient = "Crée un patient au bord de la carte.", + end_month = "Va directement à la fin du mois.", + end_year = "Va directement à la fin de l'année.", + lose_level = "Vous fait perdre le niveau actuel.", + win_level = "Vous fait gagner le niveau actuel.", + epidemic = "Crée un patient contagieux qui peut causer une épidémie.", + toggle_infected = "Bascule les icônes infectés pour l'épidémie, découverte active.", + increase_prices = "Augmenter tous les prix de 50% (max. 200%)", + decrease_prices = "Diminuer tous les prix de 50% (min. 50%)", + } } -- Introduction Texts introduction_texts = { - demo = { - "Bienvenue dans l'hôpital de démonstration !", - "Malheureusement, la version démo ne contient que ce niveau. Malgré tout, il y a assez à faire ici pour vous occuper un moment !", - "Vous allez rencontrer différentes maladies qui nécessitent des salles pour les soigner. De temps en temps, des urgences peuvent se produire. Et vous aurez besoin d'une salle de recherche pour trouver des nouvelles salles.", - "Votre but est de gagner 100.000$, de faire monter la valeur de votre hôpital à 70.000$ et d'obtenir une réputation de 700, tout en ayant soigné au moins 75% de vos patients.", - "Veillez à ce que votre réputation ne tombe pas en dessous de 300 et de ne pas tuer plus de 40% de vos patients, ou vous perdrez.", + demo = + "Bienvenue dans l'hôpital de démonstration !// " .. + "Malheureusement, la version démo ne contient que ce niveau. Malgré tout, il y a assez à faire ici pour vous occuper un moment !" .. + "Vous allez rencontrer différentes maladies qui nécessitent des salles pour les soigner. De temps en temps, des urgences peuvent se produire. Et vous aurez besoin d'une salle de recherche pour trouver des nouvelles salles. " .. + "Votre but est de gagner 100,000$, de faire monter la valeur de votre hôpital à 70,000$ et d'obtenir une réputation de 700, tout en ayant soigné au moins 75% de vos patients. " .. + "Veillez à ce que votre réputation ne tombe pas en dessous de 300 et de ne pas tuer plus de 40% de vos patients, ou vous perdrez.//" .. "Bonne chance !", - }, + level1 = + "Bienvenue dans votre premier hôpital !//Démarrez l'activité en installant un bureau de réception et " .. + "en construisant un cabinet de médecine générale. Embauchez une réceptionniste et un médecin. Il vous " .. + "suffit d'attendre des admissions. Il serait bon de construire un cabinet de psychiatrie et d'embaucher " .. + "un médecin formé dans ce domaine. Une pharmacie et une infirmière sont également indispensables pour soigner " .. + "les patients. Attention aux cas d'encéphalantiasis : une salle de gonflage suffit pour traiter cette maladie. " .. + "Il vous faut soigner 10 personnes et vous assurer que votre réputation ne tombe pas en-dessous de 200", + level8 = + "A vous de gérer l'hôpital le plus efficace et le plus rentable possible.//Les gens du coin sont bien nantis alors " .. + "pompez-leur tout le fric que vous pourrez. Soigner les gens c'est bien joli mais vous avez BESOIN de l'argent que ça " .. + "rapporte. Ratissez tous ces malades ! Amassez un joli paquet de $300.000 pour terminer ce niveau.", + level12 = + "Côté défi, vous allez être servi ! Impressionné par votre succès, le Ministère veut vous assigner une mission de confiance. " .. + "Vous devrez construire un autre hôpital de pointe, gagner des sommes scandaleuses et vous faire une réputation fabuleuse. " .. + "Vous devrez également acheter tout le terrain possible, soigner toutes les maladies (nous avons bien dit TOUTES) et remporter " .. + "toutes les récompenses. Alors, heureux ? Gagnez $650.000, soignez 750 personnes et affichez une réputation de 800 pour gagner ce niveau.", + level13 = + "Votre incroyable talent en tant que directeur d'hôpital a attiré l'attention de la Division Spéciale Secrète des " .. + "Services Spéciaux Secrets. On vous propose un bonus : il y a un hôpital infesté de rats qui réclame un Nettoyeur efficace. " .. + "Vous devez descendre le plus de rats possible avant que les agents de maintenance fassent leur boulot. Vous pensez y arriver ?", + level14 = + "Et encore un défi ! Eh oui, voici l'hôpital-surprise ! Si vous réussissez cette épreuve, vous serez le gagnant des gagnants. " .. + "Mais ça ne sera pas du gâteau car vous n'aviez encore rien vu de pareil... Bonne chance !", + level17 = + "Un bon conseil : veillez à votre réputation car c'est elle qui vous garantira une clientèle. Si vous ne tuez pas trop de " .. + "gens et les gardez raisonnablement satisfaits, vous n'aurez pas trop de difficultés à ce niveau. //A vous de jouer, maintenant. " .. + "Bonne chance et tout ça, quoi !", } -- Calls Dispatcher Dialog @@ -923,57 +1139,53 @@ close = "Ferme la boîte de dialogue de répartitions des tâches", } --- Fax messages -fax = { - choices = { - return_to_main_menu = "Retourner au menu principal", - accept_new_level = "Aller au niveau suivant", - decline_new_level = "Continuer la partie encore un peu", - }, - emergency = { - num_disease_singular = "Il y a 1 personne atteinte de %s qui a besoin de soins immédiats.", - free_build = "Si vous réussissez votre réputation augmentera mais si vous échouez votre réputation sera sérieusement entachée.", - }, - vip_visit_result = { - remarks = { - free_build = { - "C'est vraiment un bel hôpital que vous avez là ! Pas trop difficile d'y arriver sans limite d'argent, hein ?", - "Je ne suis pas économiste, mais je pense que je pourrais faire tourner cet hôpital aussi si vous voyez ce que je veux dire...", - "Un hôpital très bien tenu. Cependant, attention à la récession ! Ah oui... vous n'avez pas à vous soucier de cela.", - }, - }, - }, -} - -tooltip.fax.close = "Fermer cette fenêtre sans supprimer le message" -tooltip.message.button = "Clic gauche pour ouvrir le message" -tooltip.message.button_dismiss = "Clic gauche pour ouvrir le message, clic droit pour le rejeter" -tooltip.casebook.cure_requirement.hire_staff = "Vous devez embaucher du personnel pour gérer ce traitement" -tooltip.casebook.cure_type.unknown = "Vous ne savez pas encore comment traiter cette maladie" -tooltip.research_policy.no_research = "Aucune recherche n'est actuellement effectuée dans cette catégorie" -tooltip.research_policy.research_progress = "Progrès vers la prochaine découverte dans cette catégorie : %1%/%2%" - --- Winning texts -letter = { - dear_player = "Cher %s", - custom_level_completed = "Félicitations ! Vous avez réussi tous les objectifs de ce niveau personnalisé !", - return_to_main_menu = "Voulez-vous retourner au menu principal ou continuer la partie ?", -} - --- Installation -install = { - title = "----------------------------- Installation de CorsixTH -----------------------------", - th_directory = "CorsixTH nécessite une copie des données du jeu Theme Hospital originel (ou la démo) pour fonctionner. Veuillez utiliser le sélecteur ci-dessous pour indiquer le dossier d'installation de Theme Hospital.", - exit = "Quitter", +-- Updates +update_window = { + caption = "Une mise à jour est disponible !", + new_version = "Nouvelle version :", + current_version = "Version actuelle :", + download = "Aller à la page de téléchargement", + ignore = "Sauter et aller au menu principal", +} + +tooltip.update_window = { + download = "Accédez à la page de téléchargement pour la toute dernière version de CorsixTH", + ignore = "Ignorer cette mise à jour pour l'instant. Vous serez averti à nouveau lorsque vous ouvrez CorsixTH de nouveau", +} + +map_editor_window = { + pages = { + inside = "À l'intérieur", + outside = "À l'extérieur", + foliage = "Feuillage", + hedgerow = "Haie", + pond = "Étang", + road = "Route", + north_wall = "Mur nord", + west_wall = "Mur ouest", + helipad = "Héliport", + delete_wall = "Supprimer des murs", + parcel_0 = "Parcelle 0", + parcel_1 = "Parcelle 1", + parcel_2 = "Parcelle 2", + parcel_3 = "Parcelle 3", + parcel_4 = "Parcelle 4", + parcel_5 = "Parcelle 5", + parcel_6 = "Parcelle 6", + parcel_7 = "Parcelle 7", + parcel_8 = "Parcelle 8", + parcel_9 = "Parcelle 9", + camera_1 = "Caméra 1", + camera_2 = "Caméra 2", + camera_3 = "Caméra 3", + camera_4 = "Caméra 4", + heliport_1 = "Héliport 1", + heliport_2 = "Héliport 2", + heliport_3 = "Héliport 3", + heliport_4 = "Héliport 4", + paste = "Coller la zone", + } } --- Errors -errors = { - dialog_missing_graphics = "Désolé, les données de démo ne contiennent pas cette boîte de dialogue.", - save_prefix = "Erreur lors de la sauvegarde de la partie : ", - load_prefix = "Erreur lors du chargement de la partie : ", - map_file_missing = "Impossible de trouver le fichier de carte %s pour ce niveau !", - minimum_screen_size = "Veuillez entrer une résolution supérieure à 640x480.", - maximum_screen_size = "Veuillez entrer une résolution inférieure à 3000x2000.", - unavailable_screen_size = "La résolution que vous avez demandée n'est pas disponible en plein écran.", -} +menu.player_count = "COMPTE DE JOUEURS" +warnings.levelfile_variable_is_deprecated = "Remarque: Le niveau '%s' contient une définition de variable obsolète dans le fichier de niveau. '%LevelFile' a été renommé '%MapFile'. Veuillez aviser le créateur de la carte pour mettre à jour le niveau." diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/german.lua corsix-th-0.62/CorsixTH/Lua/languages/german.lua --- corsix-th-0.30/CorsixTH/Lua/languages/german.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/german.lua 2018-07-21 11:13:17.000000000 +0000 @@ -84,7 +84,7 @@ fax.epidemic.choices.declare = "Wir melden die Epidemie und zahlen die Geldstrafe!" fax.epidemic.choices.cover_up = "Wir versuchen die Epidemie einzudämmen bevor sie das Krankenhaus verlässt!" fax.epidemic.declare_explanation_fine = "Wenn wir die Epidemie melden, zahlen wir eine Strafe von %d und unser Ruf leidet. Dafür werden die Patienten automatisch geimpft." -- extend to mention reputation hit and automatic vaccination -fax.epidemic.cover_up_explanation_1 = "Wenn wir versuchen die Epidemie zu vertuschen, müssen wir die Infizierten heilen, bevor das Gesudheitsministerium davon Wind bekommt." +fax.epidemic.cover_up_explanation_1 = "Wenn wir versuchen, die Epidemie zu vertuschen, müssen wir die Infizierten heilen, bevor das Gesundheitsministerium davon Wind bekommt." fax.epidemic.cover_up_explanation_2 = "Wenn der Gesundheitsinspektor die Vertuschungsaktion bemerkt, wird das Konsequenzen haben." fax.epidemic.disease_name = "Unser Ärzteteam hat eine hochgradig ansteckende Form von %s entdeckt!" fax.epidemic_result.close_text = "Hurra!" @@ -92,16 +92,18 @@ fax.epidemic_result.failed.part_2 = "dass sich die Epidemie in Ihrem ganzen Krankenhaus ausbreitet." fax.epidemic_result.succeeded.part_1_name = "Dem Gesundheitsinspektor ist zu Ohren gekommen, dass Sie mit einem schweren Fall von %s zu kämpfen haben." fax.epidemic_result.succeeded.part_2 = "Allerdings hat er dafür keine Beweise finden können." -fax.epidemic_result.compensation_amount = "Die Behörden haben beschlossen, Sie wegen Ihrer Lügen zu einer Geldstrafe von %d zu verurteilen." +fax.epidemic_result.compensation_amount = "Die Behörden haben beschlossen, Sie für die entstandene Rufschädigung mit %d zu entschädigen." fax.epidemic_result.fine_amount = "Die Behörden haben den nationalen Notstand ausgerufen und sie zu einer Geldstrafe von %d verurteilt." fax.epidemic_result.rep_loss_fine_amount = "Die Zeitungen haben Wind von der Epidemie bekommen und ziehen Ihren Ruf in den Dreck. Darüber hinaus hat man zu einer Geldstrafe von %d verurteilt." fax.epidemic_result.hospital_evacuated = "Die Behörden haben keine andere Wahl, als ihr Krankenhaus zu evakuieren." dynamic_info.patient.actions.dying = "Ins Jenseits befördert!" -- wrong verb case +dynamic_info.patient.actions.epidemic_vaccinated = "Ich bin nicht mehr infiziert." adviser.research.drug_fully_researched = "Sie haben die Effektivität Ihres %s-Medikaments auf 100% gesteigert." -- grammatical error in original tooltip.graphs.reputation = "Ruf ein- und ausschalten" -- original mentioned hospital value, while it's actually reputation. staff_title.researcher = "Forscher" -- one of the most annoying (since prominent) wrong strings in original bank_manager.insurance_owed = "Zahlungen von Vers." -- original was too long +graphs.deaths = "Todesfälle" -- origin was too long insurance_companies[7] = "Leben-und-Tod KG" -- %% in original string (maybe this was rendered as &) object.skeleton = "Skelett" -- second most annoying mistake in german translation tooltip.staff_list.detail = "Aufmerksamkeit" -- was translated as an imperative @@ -117,14 +119,14 @@ -- Improve tooltips in staff window to mention hidden features tooltip.staff_window.face = "Gesicht dieser Person - klicken, um das Personal-Management zu öffnen" -tooltip.staff_window.center_view = "Linksklick um zur Person zu springen, Rechtsklick um durch das Personal zu blättern" +tooltip.staff_window.center_view = "Linksklick, um zur Person zu springen, Rechtsklick um durch das Personal zu blättern" -- These strings are missing in some versions of TH (unpatched?) confirmation.restart_level = "Sind Sie sicher, dass Sie das aktuelle Level von vorne beginnen möchten?" ------------------------------- NEW STRINGS ------------------------------- date_format = { - daymonth = "%1% %2:months%", + daymonth = "%1%. %2:months%", } object.litter = "Müll" @@ -141,10 +143,17 @@ menu_options = { lock_windows = " FENSTER FESTHALTEN ", edge_scrolling = " AM BILDSCHIRMRAND SCROLLEN ", - settings = " EINSTELLUNGEN ", adviser_disabled = " BERATER ", warmth_colors = " FARBEN FÜR WÄRMEDARSTELLUNG ", + twentyfour_hour_clock = " 24-STUNDEN-UHR ", + wage_increase = " GEHALTSERHÖHUNGEN ", } + +menu_options_wage_increase = { + deny = " ABLEHNEN ", + grant = " GEWÄHREN ", +} + menu_options_game_speed = { pause = " (P) PAUSE ", slowest = " (1) AM LANGSAMSTEN ", @@ -172,6 +181,31 @@ policy = " (F9) EINSTELLUNGEN ", } +customise_window = { + option_on = "Ein", + option_off = "Aus", + average_contents = "Einrichtung merken", + paused = "In Pause bauen", + intro = "Introfilm abspielen", + caption = "Spezialeinstellungen", + back = "Zurück", + movies = "Alle Filme zeigen", + aliens = "Außerird. Patienten", + fractured_bones = "Gebrochene Knochen", + volume = "Leiser-Taste", +} + +tooltip.customise_window = { + aliens = "Aufgrund des Fehlens einer anständigen Animation haben wir standardmäßig Patienten mit außerirdischer DNA deaktiviert, damit sie nur zu einem Notfall kommen. Um Patienten mit außerirdischer DNA es zu erlauben, Ihr Krankenhaus nicht nur bei Notfällen zu besuchen, schalten Sie dies ab.", + average_contents = "Wenn Sie möchten, dass sich das Spiel merkt, welche zusätzlichen Objekte Sie üblicherweise beim Gebäudebau hinzufügen, dann schalten Sie diese Option ein.", + back = "Dieses Menü schließen und zum Einstellungsmenü zurückkehren", + movies = "Globale Filmsteuerung: Hiermit können Sie sämtliche Filme abschalten", + fractured_bones = "Aufgrund einer armseligen Animation haben wir uns entschieden, dass es standardmäßig keine weiblichen Patienten mit gebrochenen Knochen gibt. Wenn weibliche Patienten mit gebrochenen Knochen ihr Krankenhaus besuchen sollen, dann schalten Sie dies ab.", + volume = "Wenn die Leiser-Taste auch das Fallbuch öffnet, dann schalten Sie dies ein, um die Schnellzugriffstaste für das Fallbuch auf Umschalt + C zu wechseln.", + intro = "Den Introfilm abschalten. Das Intro wird nur gespielt, wenn Sie nicht auch gleichzeitig alle Filme abgeschaltet haben.", + paused = "In Theme Hospital würde es dem Spieler während der Pause nur gestattet sein, das obere Menü zu benutzen. Dies ist in CorsixTH ebenfalls die Standardeinstellung, aber wenn Sie dies einschalten, ist alles in der Pause erlaubt.", +} + -- The demo does not contain this string menu_file.restart = " NEUSTART " @@ -189,6 +223,8 @@ dump_gamelog = " (STRG+D) SPIELPROTOKOLL ABSPEICHERN ", map_overlay = " KARTEN-OVERLAY ", sprite_viewer = " SPRITE-BETRACHTER ", + connect_debugger = " (STRG + C) ZUM LUA-DEBUG-SERVER VERBINDEN ", + debug_script = " (UMSCHALT + D) DEBUG-SKRIPT STARTEN ", } menu_debug_overlay = { none = " KEIN ", @@ -212,26 +248,38 @@ no_desk_1 = "Wenn Sie wollen, dass Patienten in Ihr Krankenhaus kommen, müssen Sie eine Empfangsdame einstellen und eine Rezeption für sie bauen!", no_desk_2 = "Na Klasse, das muss ja ein Weltrekord sein: Fast ein Jahr ohne einen einzigen Patienten! Wenn Sie dieses Krankenhaus weiter leiten wollen, müssen Sie eine Empfangsdame einstellen und eine Rezeption bauen!", no_desk_3 = "Ich glaub ich spinne, fast ein Jahr ist um und Sie haben keine besetzte Rezeption! Wie denken Sie denn, dass die Patienten zu Ihnen finden? Schauen Sie mal zu, dass Sie Ihren Kram auf die Reihe bekommen!", + no_desk_4 = "Eine Empfangsdame muss ihren eigenen Arbeitsplatz haben, um die Patienten bei ihrer Ankunft zu begrüßen.", + no_desk_5 = "Na, das wurde aber auch Zeit! Sie sollten in Kürze ein paar Patienten hier eintreffen sehen!", + no_desk_6 = "Sie haben eine Empfangsdame, also sollten Sie eine Rezeption für sie bauen.", + no_desk_7 = "Sie haben die Rezeption gebaut, also wie wäre es damit, eine Empfangsdame einzustellen? Sie werden keine Patienten sehen, bis sie das geregelt haben, wissen Sie?", falling_1 = "He! Vorsicht mit dem Mauszeiger, jemand könnte sich verletzen!", falling_2 = "Hören Sie schon auf damit, wie würde das Ihnen denn gefallen?", falling_3 = "Autsch, das sah schmerzhaft aus. Ruft einen Arzt!", falling_4 = "Dies ist ein Krankenhaus, kein Vergnügungspark!", falling_5 = "Sie sind nicht hier um Leute umzustoßen. Sie sind krank, okay?", falling_6 = "Dies ist keine Bowlingbahn. Patienten sollten nicht so behandelt werden!", - cannot_afford = "Sie haben nicht genügend Geld auf dem Konto um diese Person einzustellen!", + cannot_afford = "Sie haben nicht genügend Geld auf dem Konto, um diese Person einzustellen!", + cannot_afford_2 = "Sie haben nicht genügend Geld auf dem Konto, um dies zu kaufen!", research_screen_open_1 = "Sie müssen eine Forschungseinrichtung errichten, um auf das Forschungsmenü zugreifen zu können.", research_screen_open_2 = "Forschung ist im aktuellen Level nicht verfügbar.", + researcher_needs_desk_1 = "Ein Forscher braucht einen Schreibtisch, um daran arbeiten zu können.", + researcher_needs_desk_2 = "Ihr Forscher ist froh darüber, dass Sie ihm eine Pause gegönnt haben. Falls Sie vorhatten, dass noch mehr Personal forscht, dann müssen Sie jedem Forscher einen eigenen Schreibtisch zur Verfügung stellen.", + researcher_needs_desk_3 = "Jeder Forscher braucht einen eigenen Schreibtisch, an dem er arbeiten kann.", + nurse_needs_desk_1 = "Jede Krankenschwester braucht ihren eignen Schreibtisch, an dem sie arbeiten kann.", + nurse_needs_desk_2 = "Ihre Krankenschwester ist froh darüber, dass Sie ihr eine Pause gegönnt haben. Falls Sie vorhatten, dass mehr als nur eine Krankenschwester in der Station arbeitet, dann müssen Sie jeder Krankenschwester einen eigenen Schreibtisch zur Verfügung stellen.", + low_prices = "Sie berechnen zu wenig für %s. Dadurch bekommen Sie viele Patienten, verdienen aber wenig an jedem einzelnen von ihnen.", + high_prices = "Sie berechnen zu viel für %s. Dadurch verdienen Sie kurzfristig viel Geld, aber langfristig vertreiben Sie die damit Patienten aus ihrem Krankenhaus.", + fair_prices = "Die Beandlungskosten für %s sind fair und angemessen.", + patient_not_paying = "Ein Patient ist gegangen ohne für %s zu bezahlen weil es zu teuer ist!", + }, + research = { + drug_improved = "Die Effektivität Ihres %s-Medikaments wurde von Ihrer Forschungsabteilung verbessert.", + drug_improved_1 = "Das Medikament %s wurde von Ihrer Forschungsabteilung verbessert.", }, cheats = { th_cheat = "Gratulation, Sie haben die Cheats aktiviert!", - crazy_on_cheat = "Oh nein! Alle Ärzte sind verrückt geworden!", - crazy_off_cheat = "Uff... die Ärzte haben ihre Vernunft zurückgewonnen.", - roujin_on_cheat = "Roujins Herausforderungs-Cheat aktiviert! Viel Glück...", + roujin_on_cheat = "Roujins Herausforderungs-Cheat aktiviert! Viel Glück ...", roujin_off_cheat = "Roujins Herausforderung deaktiviert.", - hairyitis_cheat = "Haarspalterei-Cheat aktiviert!", - hairyitis_off_cheat = "Haarspalterei-Cheat deaktiviert.", - bloaty_cheat = "Aufgeblasene-Cheat aktiviert!", - bloaty_off_cheat = "Aufgeblasene-Cheat deaktiviert.", }, } @@ -248,9 +296,9 @@ vip_visit_result = { remarks = { free_build = { - "Echt ein hübsches Krankenhaus haben Sie da! War aber wohl nicht so schwer zum laufen zu bekommen, so ohne finanzielle Beschränkungen, was? Haha...", - "Ich bin zwar kein BWLer, aber ich denke dieses Krankenhaus könnte ich auch führen. Sie wissen schon, was ich meine.", - "Ein gut organisiertes Krankenhaus. Aber hüten Sie sich vor der Finanzkrise! Ach ja... da müssen Sie sich ja keine Sorgen machen.", + "Echt ein hübsches Krankenhaus haben Sie da! War aber wohl nicht so schwer zum Laufen zu bekommen, so ohne finanzielle Beschränkungen, was? Haha ...", + "Ich bin zwar kein BWLer, aber ich denke, dieses Krankenhaus könnte ich auch führen. Sie wissen schon, was ich meine.", + "Ein gut organisiertes Krankenhaus. Aber hüten Sie sich vor der Finanzkrise! Ach ja ... da müssen Sie sich ja keine Sorgen machen.", }, }, }, @@ -267,9 +315,11 @@ } install = { - title = "----------------------------- CorsixTH Konfiguration -----------------------------", - th_directory = "CorsixTH benötigt einige Dateien des Originalspiels Theme Hospital (oder der Demo davon) um zu funktionieren. Bitte das Installationsverzeichnis von Theme Hospital auswählen.", + title = "----------------------------- CorsixTH-Konfiguration -----------------------------", + th_directory = "CorsixTH benötigt einige Dateien des Originalspiels Theme Hospital (oder der Demo davon), um zu funktionieren. Bitte das Installationsverzeichnis von Theme Hospital auswählen.", exit = "Beenden", + ok = "OK", + cancel = "Abbrechen", } misc.not_yet_implemented = "(noch nicht implementiert)" @@ -278,11 +328,12 @@ main_menu = { new_game = "Neues Spiel", custom_level = "Eigenes Level", - load_game = "Spiel Laden", + load_game = "Spiel laden", options = "Optionen", exit = "Verlassen", version = "Version: ", - savegame_version = "Savegame-Version: ", + savegame_version = "Spielstandsversion: ", + continue = "Spiel fortsetzen", } tooltip.main_menu = { @@ -290,11 +341,12 @@ custom_level = "Ein Krankenhaus in einem eigenen Level errichten", load_game = "Ein zuvor gespeichertes Spiel fortsetzen", options = "Diverse Einstellungen verändern", - exit = "Bitte geh nicht fort!", + exit = "Bitte lassen Sie mich nicht allein!", + quit = "Sie sind im Begriff, CorsixTH zu verlassen. Sind Sie sich sicher, dass Sie das tun wollen?", } load_game_window = { - caption = "Spiel Laden", + caption = "Spiel laden", } tooltip.load_game_window = { @@ -341,39 +393,36 @@ option_off = "Aus", fullscreen = "Vollbild", resolution = "Auflösung", - custom_resolution = "Benutzerdefiniert...", + custom_resolution = "Benutzerdefiniert ...", width = "Breite", height = "Höhe", apply = "Akzeptieren", cancel = "Abbrechen", - data_location = "Datenverzeichnis", - browse = "Durchsuchen...", - new_th_directory = "Hier kann ein neues Theme Hospital-Installationsverzeichis ausgewählt werden. Sobald ein gültiges Verzeichnis ausgewählt wurde startet das Spiel neu.", language = "Spielsprache", cancel = "Abbrechen", back = "Zurück", - font_location = "Schriftverzeichnis", + folder = "Verzeichnisse", + customise = "Spezialeinstellungen", + audio = "Globales Audio", } tooltip.options_window = { fullscreen = "Darstellung im Vollbild- oder Fenstermodus", fullscreen_button = "Klicken, um zwischen Vollbild- und Fenstermodus zu wechseln", - resolution = "Die Bildschirmauflösung in der das Spiel läuft", + resolution = "Die Bildschirmauflösung, in der das Spiel läuft", select_resolution = "Eine neue Auflösung auswählen", width = "Gewünschte Bildschirmbreite eingeben", height = "Gewünschte Bildschirmhöhe eingeben", apply = "Die eingegebene Auflösung akzeptieren", cancel = "Zurückkehren, ohne die Auflösung zu ändern", - data_location = "Das Installationsverzeichnis des Theme-Hospital-Originalspiels, welches zum Spielen von CorsixTH benötigt wird", language = "Die Sprache, in der Texte im Spiel erscheinen", select_language = "Die Spielsprache ändern", language_dropdown_item = "%s als Sprache auswählen", - original_path = "Das momentan gewählte Theme Hospital-Installationsverzeichnis", - browse = "Nach einer anderen Theme Hospital-Installation durchsuchen (aktueller Pfad: %1%)", back = "Das Optionsfenster schließen", - browse_font = "Nach einer anderen Schrift-Datei durchsuchen (aktueller Pfad: %1%)", - font_location = "Pfad einer Schrift-Datei, die Unicode Zeichen deiner Sprache unterstützt. Wenn diese Einstellung nicht vorgenommen wird, kannst du keine Sprachen auswählen, die mehr Zeichen benötigen als das Originalspiel unterstützt. Beispiel: Russisch und Chinesisch", - no_font_specified = "Bisher wurde kein Pfad angegeben!", + audio_button = "Sämtliche Toneffekte im Spiel ein- bzw. ausschalten", + audio_toggle = "Ein- oder ausschalten", + customise_button = "Weitere Einstellungen, die Sie ändern können, um Ihr Spielerlebnis anzupassen", + folder_button = "Verzeichniseinstellungen", } font_location_window.caption = "Schrift auswählen (%1%)" @@ -400,7 +449,7 @@ tutorial = "Dieses Feld abhaken, um zu Beginn des Spieles eine Einführung zu erhalten", start = "Das Spiel mit den gewählten Einstellungen starten", cancel = "Oh, eigentlich wollte ich gar kein neues Spiel starten!", - player_name = "Gib den Namen ein mit dem du im Spiel genannt werden möchtest.", + player_name = "Geben Sie den Namen ein, mit dem Sie im Spiel genannt werden möchten", } lua_console = { @@ -418,15 +467,20 @@ dialog_missing_graphics = "Entschuldigung, aber dieses Fenster ist in den Demo-Dateien nicht enthalten.", save_prefix = "Fehler beim Speichern: ", load_prefix = "Fehler beim Laden: ", - map_file_missing = "Konnte die Kartendatei %s für das Level nicht finden!", - minimum_screen_size = "Bitte eine Auflösung von mindestens 640x480 eingeben.", - maximum_screen_size = "Bitte eine Auflösung von höchstens 3000x2000 eingeben.", + map_file_missing = "Die Kartendatei %s für das Level konnte nicht gefunden werden!", + minimum_screen_size = "Bitte eine Auflösung von mindestens 640×480 eingeben.", unavailable_screen_size = "Die gewünschte Auflösung ist im Vollbildmodus nicht verfügbar.", + no_games_to_contine = "Es gibt keine Spielstände.", + fractured_bones = "BEACHTEN SIE: Die Animation für weibliche Patienten mit gebrochenen Knochen ist nicht perfekt.", + load_quick_save = "Fehler: Der Schnellspeicherspielstand konnte nicht geladen werden, weil er nicht existiert. Kein Grund zur Sorge, wir haben nun einen für Sie erzeugt!", + alien_dna = "BEACHTEN SIE: Für außerirdische Patienten gibt es keine Animationen für das Sitzen, das Öffnen von Türen, das Anklopfen, usw. Daher werden sie, wie bei Theme Hospital, normal aussehen und sich dann wieder zurückverwandeln. Patienten mit außerirdischer DNA werden nur auftauchen, wenn sie in der Leveldatei gesetzt sind.", } confirmation = { - needs_restart = "Um diese Änderung vorzunehmen muss CorsixTH neu gestartet werden. Nicht gespeicherter Fortschritt geht verloren. Sicher, dass Sie fortfahren wollen?", + needs_restart = "Um diese Änderung, vorzunehmen muss CorsixTH neu gestartet werden. Nicht gespeicherter Fortschritt geht verloren. Sicher, dass Sie fortfahren wollen?", abort_edit_room = "Sie bauen oder ändern gerade einen Raum. Wenn alle benötigten Objekte platziert sind, wird der Raum fertiggestellt, ansonsten wird er gelöscht. Fortfahren?", + maximum_screen_size = "Die von Ihnen gewählte Bildschirmauflösung ist größer als 3000×2000. Größere Auflösungen sind möglich, aber erfordern eine bessere Hardware, um eine akzeptable Bildwiederholrate zu gewährleisten. Sind Sie sich sicher, dass Sie fortfahren möchten?", + music_warning = "Bevor Sie sich dafür entscheiden, MP3s für Ihre Spielmusik verwenden, müssen Sie smpeg.dll oder eine entsprechende Datei für Ihr Betriebssystem haben, ansonsten werden Sie keine Musik im Spiel haben. Möchten Sie fortfahren?", } information = { @@ -436,7 +490,7 @@ }, level_lost = { "So ein Mist! Sie haben das Level leider nicht geschafft. Vielleicht klappts ja beim nächsten Mal!", - "Der Grund warum Sie verloren haben:", + "Der Grund, warum Sie verloren haben:", reputation = "Ihr Ruf ist unter %d gesunken.", balance = "Ihr Kontostand ist unter %d gesunken.", percentage_killed = "Sie haben mehr als %d Prozent der Patienten getötet.", @@ -444,7 +498,7 @@ }, very_old_save = "Seit dieses Level gestartet wurde, wurden einige Änderungen am Spiel durchgeführt. Sie sollten ein neues Spiel starten, damit alle Änderungen wirksam werden.", no_custom_game_in_demo = "Tut uns Leid, aber in der Demo-Version sind keine eigenen Level spielbar.", - cheat_not_possible = "Dieser Cheat ist in diesem Level nicht verfügbar. Sogar beim cheaten versagen Sie, wie armselig!", + cheat_not_possible = "Dieser Cheat ist in diesem Level nicht verfügbar. Sogar beim Cheaten versagen Sie, wie armselig!", } tooltip.information = { @@ -454,23 +508,23 @@ totd_window = { tips = { "Zu Beginn benötigt jedes Krankenhaus eine Rezeption und eine Allgemeinmedizin. Danach kommt es darauf an, was für Patienten im Krankenhaus auftauchen. Eine Pharma-Theke ist aber immer eine gute Wahl.", - "Maschinen wie die Entlüftung müssen gewartet werden. Stelle ein paar Handlanger ein, oder die Patienten und das Personal könnte verletzt werden.", - "Nach einer Weile wird das Personal müde. Baue unbedingt einen Personalraum, damit es sich ausruhen kann.", - "Platziere genug Heizkörper, um das Personal und die Patienten warm zu halten, sonst werden sie unglücklich. Benutze die Übersichtskarte, um Stellen im Krankenhaus zu finden, die noch etwas besser beheizt werden müssen.", + "Maschinen wie die Entlüftung müssen gewartet werden. Stellen Sie ein paar Handlanger ein, oder die Patienten und das Personal könnte verletzt werden.", + "Nach einer Weile wird das Personal müde. Bauen Sie unbedingt einen Personalraum, damit es sich ausruhen kann.", + "Platzieren Sie genug Heizkörper, um das Personal und die Patienten warm zu halten, sonst werden sie unglücklich. Benutzen Sie die Übersichtskarte, um Stellen im Krankenhaus zu finden, die noch etwas besser beheizt werden müssen.", "Der Fähigkeiten-Level eines Arztes beeinflusst die Qualität und Geschwindigkeit seiner Diagnosen deutlich. Ein geübter Arzt in der Allgemeinmedizin erspart so manchen zusätzlichen Diagnoseraum.", "AIPler und Ärzte können ihre Fähigkeiten verbessern, indem sie in der Ausbildung von Beratern lernen. Wenn der Berater eine zusätzliche Qualifikation (Chirurg, Psychiater oder Forscher) besitzt, gibt er dieses Wissen ebenfalls weiter.", - "Hast du schon versucht, die Europäische Notruf-Nummer (112) in das Faxgerät einzugeben? Mach vorher den Sound an!!", + "Haben Sie schon versucht, die europäische Notruf-Nummer (112) in das Faxgerät einzugeben? Schalten Sie vorher den Sound an!", "Im Options-Menü hier im Hauptmenü oder im laufenden Spiel können Einstellungen wie die Auflösung oder die Sprache geändert werden.", - "Du hast eine andere Sprache als Englisch ausgewählt, aber es erscheinen Englische Texte? Hilf uns die Übersetzung zu vervollständigen, indem du fehlende Texte in deine Sprache Übersetzt!", - "Das CorsixTH-Team sucht Verstärkung! Hast du Interesse, beim Programmieren, Übersetzen oder Grafiken erstellen zu helfen? Kontaktiere uns in unserem Forum, der Mailing List oder unserem IRC-Channel (corsix-th im freenode).", - "Wenn du einen Bug findest, bitte melde ihn in unserem Bug-Tracker: th-issues.corsix.org", - "In jedem Level müssen bestimmte Voraussetzungen erfüllt werden, bevor man zum nächsten wechseln kann. Im Status-Fenster kannst du deinen Fortschritt bezüglich der Levelziele sehen.", + "Haben Sie eine andere Sprache als Englisch ausgewählt, aber es erscheinen englische Texte? Helfen Sie uns, die Übersetzung zu vervollständigen, indem Sie fehlende Texte in Ihre Sprache übersetzten!", + "Das CorsixTH-Team sucht Verstärkung! Haben Sie Interesse, beim Programmieren, Übersetzen oder der Grafikerstellung zu helfen? Kontaktieren Sie uns in unserem Forum, der Mailing-Liste oder unserem IRC-Channel (#Corsix-TH auf Freenode).", + "Wenn Sie einen Bug finden, bitte melden Sie ihn in unserem Bug-Tracker: th-issues.corsix.org", + "In jedem Level müssen bestimmte Voraussetzungen erfüllt werden, bevor man zum Nächsten wechseln kann. Im Status-Fenster können Sie Ihren Fortschritt bezüglich der Levelziele sehen.", "Um existierende Räume zu bearbeiten oder gar zu löschen, kann man den Raum-Bearbeiten-Knopf in der unteren Werkzeugleiste verwenden.", "Um aus einer Horde wartender Patienten diejenigen zu finden, die für einen bestimmten Raum warten, einfach mit dem Mauszeiger über den entsprechenden Raum fahren.", - "Klicke auf die Tür eines Raumes, um seine Warteschlange zu sehen. Hier kann man nützliche Feineinstellungen vornehmen, wie etwa die Warteschlange umzusortieren oder einen Patienten zu einem anderen Raum zu senden.", - "Unglückliches Personal verlangt öfter Gehaltserhöhungen. Gestalte die Arbeitsumgebung deines Personals möglichst angenehm, um dies zu verhindern.", + "Klicken Sie auf die Tür eines Raumes, um seine Warteschlange zu sehen. Hier kann man nützliche Feineinstellungen vornehmen, wie etwa die Warteschlange umzusortieren oder einen Patienten zu einem anderen Raum zu senden.", + "Unglückliches Personal verlangt öfter Gehaltserhöhungen. Gestalten Sie die Arbeitsumgebung Ihres Personals möglichst angenehm, um dies zu verhindern.", "Patienten werden beim Warten durstig, besonders wenn die Heizungen aufgedreht sind! Strategisch platzierte Getränkeautomaten sind eine nette zusätzliche Einnahmequelle.", - "Du kannst die Diagnose für einen Patienten vorzeitig abbrechen und ihn direkt zur Behandlung schicken, falls seine Krankheit zuvor schon entdeckt wurde. Allerdings erhöht sich dadurch das Risiko, dass das Heilmittel falsch ist und der Patient stirbt.", + "Sie können die Diagnose für einen Patienten vorzeitig abbrechen und ihn direkt zur Behandlung schicken, falls seine Krankheit zuvor schon entdeckt wurde. Allerdings erhöht sich dadurch das Risiko, dass das Heilmittel falsch ist und der Patient stirbt.", "Notfälle können eine gute Einnahmequelle abgeben, sofern genügend Kapazitäten vorhanden sind, um die Notfallpatienten rechtzeitig zu behandeln.", }, previous = "Vorheriger Tipp", @@ -486,6 +540,19 @@ caption = "Debug-Patient", } +update_window = { + caption = "Update verfügbar!", + new_version = "Neue Version:", + current_version = "Aktuelle Version:", + download = "Zur Downloadseite gehen", + ignore = "Überspringen und zum Hauptmenü gehen", +} + +tooltip.update_window = { + download = "Zur Downloadseite für die allerneueste Version von CorsixTH gehen", + ignore = "Dieses Update im Moment ignorieren. Sie werden erneut benachrichtigt, wenn Sie CorsixTH das nächste Mal starten.", +} + cheats_window = { caption = "Cheats", warning = "Warnung: Cheater bekommen am Ende des Levels keine Bonus-Punkte!", @@ -504,6 +571,8 @@ end_year = "Ende des Jahres", lose_level = "Level verlieren", win_level = "Level gewinnen", + epidemic = "Infizierten Patienten erzeugen", + toggle_infected = "Infektions-Symbole umschalten", }, close = "Schließen", } @@ -521,18 +590,53 @@ end_year = "Zum Jahresende springen.", lose_level = "Das aktuelle Level verlieren.", win_level = "Das aktuelle Level gewinnen.", + epidemic = "Einen infizierten Patienten, der eine Epidemie auslösen kann, erzeugen.", + toggle_infected = "Die Infektions-Symbole für die aktive, entdeckte Epidemie umschalten.", } } +folders_window = { + data_label = "TH-Daten", + music_location = "Wählen Sie hier das Verzeichnis, welches Sie für Ihre Musik benutzen möchten, aus.", + music_label = "MP3s", + new_th_location = "Hier können Sie ein neues Theme-Hospital-Installationsverzeichnis auswählen. Sobald Sie das neue Verzeichnis auswählen, wird das Spiel neu gestartet.", + caption = "Verzeichnisort", + screenshots_label = "Screenshots", + font_label = "Schrift", + savegames_label = "Spielstände", + back = "Zurück", + savegames_location = "Wählen Sie das Verzeichnis, welches Sie für Spielstände benutzen möchten, aus.", + screenshots_location = "Wählen Sie das Verzeichnis, welches Sie für Screenshots benutzen möchten, aus.", +} + +tooltip.folders_window = { + browse_font = "Nach einer anderen Schriftdatei suchen (aktueller Ort: %1%)", + browse_screenshots = "Nach einem anderem Ort für ihr Screenshotverzeichnis suchen (aktueller Ort: %1%)", + reset_to_default = "Das Verzeichnis zur Standardeinstellung zurücksetzen", + back = "Dieses Menü schließen und zum Einstellungsmenü zurückkehren", + music_location = "Wählen Sie einen Ort für ihre MP3-Musikddateien aus. Sie müssen dieses Verzeichnis bereits erstellt haben, dann wählen Sie ebendieses Verzeichnis aus.", + font_location = "Pfad einer Schrift-Datei, die Unicode-Zeichen Ihrer Sprache unterstützt. Wenn diese Einstellung nicht vorgenommen wird, können Sie keine Sprachen auswählen, die mehr Zeichen benötigen, als das Originalspiel unterstützt. Beispiel: Russisch und Chinesisch.", + savegames_location = "Standardmäßig wird das Spielstandsverzeichnis im selben Verzeichnis wie die Konfigurationsdatei gespeichert und es wird benutzt, um die Spielstände darin abzuspeichern. Sollte das nicht erwünscht sein, können Sie sich ihr eigenes Verzeichnis aussuchen, wählen Sie einfach das Verzeichnis, das Sie verwenden möchten", + screenshots_location = "Standardmäßig wird das Screenshotverzeichnis im selben Verzeichnis wie die Konfigurationsdatei gespeichert. Sollte das nicht erwünscht sein, können Sie sich ihr eigenes Verzeichnis aussuchen, wählen Sie einfach das Verzeichnis, das Sie verwenden möchten", + browse_data = "Nach einem anderem Ort einer Theme-Hospital-Installation durchsuchen (aktueller Ort: %1%)", + browse = "Nach einem Verzeichnis durchsuchen", + browse_music = "Nach einem anderem Ort für Ihr Musikverzeichnis durchsuchen (aktueller Ort: %1%)", + no_font_specified = "Es wurde kein Schriftverzeichnis festgelegt!", + not_specified = "Es wurde kein Verzeichnis festgelegt!", + browse_saves = "Nach einem anderem Ort für Ihr Spielstandsverzeichnis durchsuchen (aktueller Ort: %1%)", + default = "Standardort", + data_location = "Das Verzeichnis der Original-Theme-Hospital-Installation, welche benötigt wird, um CorsixTH zu spielen", +} + introduction_texts = { - demo = { - "Willkommen im Demo-Krankenhaus!", - "Leider beinhaltet die Demo-Version nur dieses eine Level. Dafür gibt es hier aber mehr als genug zu tun um Sie eine Weile zu beschäftigen!", - "Sie werden diversen Krankheiten begegnen, die unterschiedliche Räume zur Behandlung benötigen. Ab und zu können auch Notfälle eintreffen. Und Sie werden mithilfe einer Forschungsabteilung neue Räume erforschen müssen.", - "Ihr Ziel ist es, 100.000 DM zu verdienen, einen Krankenhauswert von 70.000 DM und einen Ruf von 700 vorzuweisen, und gleichzeitig mindestens 75% der Patienten erfolgreich zu behandeln.", - "Stellen Sie sicher, dass Ihr Ruf nicht unter 300 fällt und dass Sie nicht mehr als 40% ihrer Patienten sterben lassen, oder Sie werden verlieren.", + demo = + "Willkommen im Demo-Krankenhaus!//" .. + "Leider beinhaltet die Demo-Version nur dieses eine Level. Dafür gibt es hier aber mehr als genug zu tun, um Sie eine Weile zu beschäftigen! " .. + "Sie werden diversen Krankheiten begegnen, die unterschiedliche Räume zur Behandlung benötigen. Ab und zu können auch Notfälle eintreffen. " .. + "Und Sie werden mithilfe einer Forschungsabteilung neue Räume erforschen müssen. " .. + "Ihr Ziel ist es, 100.000 DM zu verdienen, einen Krankenhauswert von 70.000 DM und einen Ruf von 700 vorzuweisen, und gleichzeitig mindestens 75% der Patienten erfolgreich zu behandeln. " .. + "Stellen Sie sicher, dass Ihr Ruf nicht unter 300 fällt und dass Sie nicht mehr als 40% ihrer Patienten sterben lassen, oder Sie werden verlieren.//" .. "Viel Glück!", - }, } calls_dispatcher = { @@ -544,8 +648,8 @@ } tooltip.calls_dispatcher = { - task = "Liste der Aufgaben - Aufgabe anklicken um das Fenster des zugewiesenen Personalmitglieds zu öffnen und zum Ort der Aufgabe zu scrollen.", - assigned = "Diese Box ist markiert wenn jemand der Aufgabe zugewiesen ist.", + task = "Liste der Aufgaben - Aufgabe anklicken, um das Fenster des zugewiesenen Personalmitglieds zu öffnen und zum Ort der Aufgabe zu scrollen.", + assigned = "Diese Box ist markiert, wenn jemand der Aufgabe zugewiesen ist.", close = "Das Aufruf-Verteiler-Fenster schließen", } diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/hungarian.lua corsix-th-0.62/CorsixTH/Lua/languages/hungarian.lua --- corsix-th-0.30/CorsixTH/Lua/languages/hungarian.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/hungarian.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1819,3 +1819,85 @@ [360] = " ", [361] = ".", } +confirmation.maximum_screen_size = "Az általad beállított képernyőfelbontás magasabb mint 3000 X 2000. Van lehetőség ilyen felbontások beállítására, viszont ezekhez erősebb hardver szükségeltetik az akadozásmentes futtatáshoz. Biztosan folytatod?" +confirmation.music_warning = "Mielőtt kiválaszthatnád az mp3-akat amelyek játék közben fognak szólni szükséged lesz az smpeg.dll nevű (vagy azzal egyenértékű) file-ra, különben nem lesz zene. Folytatod?" +menu_options_wage_increase.deny = " MEGTAGAD" +menu_options_wage_increase.grant = " ENGEDÉLYEZ" +tooltip.options_window.audio_button = "Minden hang ki/be kapcsolása" +tooltip.options_window.audio_toggle = "Ki vagy bekapcsol" +tooltip.options_window.folder_button = "Könyvtár opciók" +tooltip.options_window.customise_button = "További beállítások, hogy finomhangolhasd a játékélményt" +tooltip.update_window.download = "Látogasd meg a letöltőoldalt, hogy megszerezhesd a CorsixTH legfrissebb verzióját" +tooltip.update_window.ignore = "A frissítés kihagyása. Újra értesítést fogsz kapni róla, amikor legközelebb elindítod a CorsixTH-t" +tooltip.folders_window.browse_font = "Válassz másik betűtípusfile-t ( jelenlegi hely: %1% )" +tooltip.folders_window.screenshots_location = "Alaphelyzetben a kilopott képek a konfigurációs file-ok könyvtárába kerülnek. Amennyiben máshova szeretnéd menteni őket csak tallózd ki a számodra megfelelő célkönyvtárat." +tooltip.folders_window.reset_to_default = "Elérési út alaphelyzetbe állítása" +tooltip.folders_window.back = "Menü bezárása, és vissza a Beállításokhoz" +tooltip.folders_window.music_location = "Válaszd ki az mp3 file-jaid elérési útját. A könyvtárt először létre kell hoznod, utána pedig ki kell választanod." +tooltip.folders_window.font_location = "Szükség van egy olyan betűtípusfile elérési útjára, amely alkalmas a magyar nyelv betűit Unicode karakterek segítségével megjeleníteni. Amennyiben ezt elmulasztod nem leszel képes olyan nyelveket beállítani, amelyeknek szükségük van a játék eredeti nyelvében nem fellelhető karakterekre. Például: orosz és kínai" +tooltip.folders_window.savegames_location = "Alaphelyzetben a játék mentéseit tartalmazó file-ok a konfigurációs file-ok könyvtárába kerülnek. Amennyiben máshova szeretnéd menteni őket csak tallózd ki a számodra megfelelő célkönyvtárat." +tooltip.folders_window.browse_data = "Tallózd ki a Theme Hospital telepítési helyét (jelenlegi hely: %1%)" +tooltip.folders_window.browse = "Tallózz elérési utat" +tooltip.folders_window.browse_screenshots = "Válassz másik könyvtárat a kilopott képeidnek ( jelenlegi hely: %1% )" +tooltip.folders_window.browse_music = "Válassz másik könyvtárat a zenéidnek ( jelenlegi hely: %1% )" +tooltip.folders_window.no_font_specified = "Még nem adtál meg betűtípusfile elérési utat!" +tooltip.folders_window.not_specified = "Még nem adtál meg könyvtár elérési utat!" +tooltip.folders_window.browse_saves = "Válassz másik könyvtárat az elmentett játékállásaidnak ( jelenlegi hely: %1% )" +tooltip.folders_window.default = "Alapértelmezett elérési út" +tooltip.folders_window.data_location = "Az eredeti Theme Hospital telepítési helye (szükséges a CorsixTH futtatásához)" +tooltip.customise_window.aliens = "Mivel nincsenek megfelelő animációink az idegen DNA-val rendelkező páciensek megjelenítésére, ezért ők csak vészhelyzetek esetén jelennek meg a kórházadban. Ha szeretnéd, hogy ne csak ilyen esetekben jöjjenek, akkor ezt kapcsold ki" +tooltip.customise_window.average_contents = "Ha szeretnéd, hogy a játék megjegyezze milyen extra tárgyakkal szoktad a szobákat általában berendezni, akkor kapcsold be ezt" +tooltip.customise_window.back = "Menü bezárása, és vissza a Beállításokhoz" +tooltip.customise_window.movies = "Ezzel le tudod tiltani az összes átvezető videót" +tooltip.customise_window.fractured_bones = "Mivel csak félkész animációink van a törött csontú női páciensek megjelenítésére, ezért ők nem jelennek meg a kórházadban. Ha mégis szeretnéd, hogy érkezzenek ilyen betegek is, akkor ezt kapcsold ki" +tooltip.customise_window.volume = "Ha hangerő halkítása gomb használata megnyitja az esetleírásokat is, akkor ezt bekapcsolva átállíthatod az esetleírások gyorsbillentyű kombinációját Shift + C -re" +tooltip.customise_window.intro = "A bevezető videó (intro) ki/be kapcsolása - az átvezető videóknak engedélyezve kell lenniük, ha szeretnéd ezt bekapcsolni" +tooltip.customise_window.paused = "Az eredeti Theme Hospitalban a játékos csak a felső menüt használhatta ha a játék szüneteltetve volt. Ez az alapbeállítás a CorsixTH-ban is, de ha ezt bekapcsolod, akkor szüneteltetés alatt is elérsz minden menüt" +update_window.caption = "Frissítés elérhető!" +update_window.new_version = "Új verzió:" +update_window.current_version = "Jelenlegi verzió:" +update_window.download = "Ugrás a letöltőoldalra" +update_window.ignore = "Kihagy és tovább a főmenühöz" +errors.fractured_bones = "MEGJEGYZÉS: a törött csontú női páciens animációja nem tökéletes" +errors.alien_dna = "MEGJEGYZÉS: nincsenek megfelelő animációink az idegen DNA-val rendelkező páciensek helyes megjelenítésére (például: leülés, ajtón kopogás, stb.), ezért amikor ezeket a cselekvéseket végzik olyankor átváltoznak normális kinézetűre, majd annak végeztével vissza. Az idegen DNA-val rendelkező páciensek csak akkor jelennek meg, ha a pálya file-jában ezt beállítottad" +errors.load_quick_save = "Hiba történt: a gyorsmentés betöltése sikertelen volt, mivel nem állt rendelkezésre betölthető állás. Nincs ok az aggodalomra, ugyanis most létrehoztunk neked egyet!" +folders_window.data_label = "TH adat" +folders_window.music_location = "Válaszd ki a könyvtárat ahol a zenéidet tárolod" +folders_window.music_label = "MP3-ak" +folders_window.new_th_location = "Itt tudsz beállítani új Theme Hospital telepítési könyvtárat. Mihelyst kiválasztod a játék újra fog indulni." +folders_window.caption = "Könyvtár elérési utak" +folders_window.screenshots_label = "Kilopott képek" +folders_window.font_label = "Betűtípus" +folders_window.savegames_label = "Játékállások" +folders_window.back = "Vissza" +folders_window.savegames_location = "Válaszd ki a könyvtárat ahová a játékállásaid kerüljenek" +folders_window.screenshots_location = "Válaszd ki a könyvtárat ahová a kilopott képeid kerüljenek" +customise_window.average_contents = "Átlagos tartalmak" +customise_window.option_on = "Be" +customise_window.paused = "Építés szüneteltetés közben" +customise_window.option_off = "Ki" +customise_window.intro = "Bevezető videó lejátszása" +customise_window.caption = "Egyéni beállítások" +customise_window.back = "Vissza" +customise_window.movies = "Általános átvezető videó vezérlő" +customise_window.volume = "Halkítás gyorsbillentyű" +customise_window.aliens = "Alien páciensek" +customise_window.fractured_bones = "Törött Csontok" +options_window.folder = "Könyvtárak" +options_window.customise = "Személyre szab" +options_window.audio = "Fő hangerő" +menu_options.twentyfour_hour_clock = " 24 ÓRÁS MEGJELENÍTÉS" +menu_options.wage_increase = " FIZETÉSIGÉNYEK" +install.ok = "OK" +install.cancel = "Mégse" +adviser.research.drug_improved_1 = "A kutatórészleged feljavította a %s szer hatását." +adviser.warnings.no_desk_7 = "Most hogy leraktál egy recepciós pultot mi lenne ha felvennél egy recepcióst is? Amíg ez meg nincs nem fogsz tudni páciensekkel foglalkozni!" +adviser.warnings.researcher_needs_desk_1 = "A Kutatónak szüksége van egy íróasztalra aminél dolgozhatna." +adviser.warnings.no_desk_6 = "Már van egy recepciósod. Mi lenne, ha leraknál neki egy recepciós pultot, ahol dolgozhatna?" +adviser.warnings.nurse_needs_desk_1 = "Minden Nővérkének szüksége van egy saját íróasztalra, ahol dolgozhat." +adviser.warnings.researcher_needs_desk_2 = "A kutatód boldog, hogy megengedted neki, hogy szünetet tartson. Ha a kutatórészleg személyzetének bővítését fontolgatod ne felejtsd el, hogy mindegyiknek szüksége lesz külön asztalra." +adviser.warnings.no_desk_5 = "Éppen ideje volt már, hamarosan megérkeznek az első betegek!" +adviser.warnings.no_desk_4 = "A recepciósnak szüksége van egy saját pultra, hogy üdvözölhesse az érkező betegeket" +adviser.warnings.researcher_needs_desk_3 = "Minden Kutatónak szüksége van egy íróasztalra aminél dolgozhat." +adviser.warnings.cannot_afford_2 = "Nincs elég pénzed a számládon ehhez a vásárláshoz!" +adviser.warnings.nurse_needs_desk_2 = "A nővérke boldog, hogy megengedted neki, hogy szünetet tartson. Ha a kórtermeid személyzetének bővítését fontolgatod ne felejtsd el, hogy mindegyiknek szüksége lesz külön asztalra." diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/iberic_portuguese.lua corsix-th-0.62/CorsixTH/Lua/languages/iberic_portuguese.lua --- corsix-th-0.30/CorsixTH/Lua/languages/iberic_portuguese.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/iberic_portuguese.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010 Manuel "Roujin" Wolf, "Fabiomsouto" +--[[ Copyright (c) 2010 Manuel "Roujin" Wolf, "Fabiomsouto" Copyright (c) 2011 Sérgio "Get_It" Ribeiro Copyright (c) 2012 @@ -41,6 +41,88 @@ confirmation.restart_level = "Tem a certeza que deseja reiniciar este nível?" ------------------------------- NEW STRINGS ------------------------------- +confirmation.maximum_screen_size = "A resolução de ecrã que escolheu é maior que 3000 x 2000. Resoluções mais altas são possíveis, mas requerem melhor hardware de forma a manter uma taxa de fotogramas (FPS) jogável. De certeza que deseja continuar?" +confirmation.music_warning = "Antes de escolher usar mp3 para a música dentro do jogo, necessita de ter o smpeg.dll ou equivalente para o seu sistema operativo, caso contrário, não terá música no jogo. Deseja continuar?" +menu_options_wage_increase.deny = " NEGAR " +menu_options_wage_increase.grant = " PERMITIR " +tooltip.options_window.audio_button = "Ligar ou desligar todo o som do jogo" +tooltip.options_window.audio_toggle = "Ligar ou desligar" +tooltip.options_window.folder_button = "Opções de pastas" +tooltip.options_window.customise_button = "Mais opões que pode alterar para personalizar a sua experiência de jogo." +tooltip.update_window.download = "Vá para a página de transferências para a última versão de CorsixTH" +tooltip.update_window.ignore = "Ignorar esta actualização agora. Será notificado de novo na próxima vez que inicializar CorsixTH" +tooltip.folders_window.browse_font = "Procurar outro tipo de letra (localização actual: %1% )" +tooltip.folders_window.screenshots_location = "Por defeito, as capturas de ecrã são armazenadas numa pasta junto do ficheiro de configuração. Caso isto não seja apropriado, pode escolher a sua própria, simplesmente indique qual a pasta que deseja utilizar." +tooltip.folders_window.reset_to_default = "Reinicializar a directoria para a localização por defeito" +tooltip.folders_window.back = "Fechar este menu e voltar às definições." +tooltip.folders_window.music_location = "Escolha a localização dos seus ficheiros mp3. A pasta já deve ter sido criada, e agora escolha o directório que acabou de criar." +tooltip.folders_window.font_location = "Localização de um tipo de letra capaz de mostrar caracteres Unicode requeridos pela sua língua. Se isto não for especificado, não será capaz de escolher línguas que necessitam de mais caracteres que o jogo original consegue fornecer. Exemplo: Russo e Chinês." +tooltip.folders_window.savegames_location = "Por defeito, os jogos gravados são armazenados numa pasta junto do ficheiro de configuração. Caso isto não seja apropriado, pode escolher a sua própria, simplesmente indique qual a pasta que deseja utilizar." +tooltip.folders_window.browse_data = "Escolha outra localização da instalação do Theme Hospital (localização actual: %1% )" +tooltip.folders_window.browse = "Escolha a localização da pasta" +tooltip.folders_window.browse_screenshots = "Escolha outra localização para a pasta das capturas de ecrã (Localização actual: %1%) " +tooltip.folders_window.browse_music = "Escolha outra localização para a pasta da música (Localização actual: %1%) " +tooltip.folders_window.no_font_specified = "Nenhum tipo de letra especificado!" +tooltip.folders_window.not_specified = "Nenhuma pasta especificada!" +tooltip.folders_window.browse_saves = "Escolha outra localização para a pasta dos jogos gravados (Localização actual: %1%) " +tooltip.folders_window.default = "Localização por defeito" +tooltip.folders_window.data_location = "O directório da instalação do Theme Hospital original, que é necessário para correr o CorsixTH" +tooltip.customise_window.aliens = "Devido à falta de animações apropriadas, colocamos por defeito que pacientes com ADN Extraterrestre só possam surgir numa emergência. Para permitir que estes pacientes possam visitar o hospital de outra forma, desligue esta opção." +tooltip.customise_window.average_contents = "Se quer que o jogo lhe lembre que objectos adicionais costuma adicionar quando cria uma sala, ligue esta opção." +tooltip.customise_window.back = "Fechar este menu e voltar às definições." +tooltip.customise_window.movies = "Controle geral de vídeos, isto irá permitir desligar todos os vídeos" +tooltip.customise_window.fractured_bones = "Devido a uma má animação colocamos por defeito que não existem pacientes femininas com Ossos Partidos. De forma a permitir que pacientes femininas com Ossos Partidos visitem o hospital, desligue esta opção." +tooltip.customise_window.volume = "Se o botão para baixar o volume está a abrir também o livro médico, ligue esta opção para mudar o atalho para o livro médico para Shift + C" +tooltip.customise_window.intro = "Ligar ou desligar o vídeo de introdução, o controle geral de vídeos tem que estar ligado se quer ver a introdução cada vez que começa o CorsixTH" +tooltip.customise_window.paused = "No Theme Hospital o jogador apenas podia utilizar o menu de topo se o jogo estivesse pausado. Esta é também a opção por defeito no CorsixTH, mas ao activar esta opção, tudo é permitido com o jogo pausado." +update_window.caption = "Actualização Disponível!" +update_window.new_version = "Nova Versão:" +update_window.current_version = "Versão Actual:" +update_window.download = "Ir à página de transferências" +update_window.ignore = "Saltar e ir para o menu principal" +errors.fractured_bones = "AVISO: A animação para pacientes femininas com Ossos Partidos não é perfeita." +errors.alien_dna = "AVISO: Não existem animação para pacientes Extraterrestres a sentarem-se, abrir ou bater em portas, etc. Então, como no Theme Hospital, para executarem estas animações eles ficam com um aspecto normal, e depois voltam ao aspecto original. Pacientes com ADN Extraterrestre só irão aparecer se estiver previsto no nível." +errors.load_quick_save = "Erro, não foi possível carregar o quick save já que não existe. Nada de preocupações, já que criamos agora um para si!" +folders_window.data_label = "Dados TH" +folders_window.music_location = "Escolha a directoria que usar para a sua música" +folders_window.music_label = "MP3's" +folders_window.new_th_location = "Aqui pode especificar uma nova pasta de instalação do Theme Hospital. Assim que escolher a nova directoria, o jogo irá reiniciar." +folders_window.caption = "Localizações de pastas" +folders_window.screenshots_label = "Capturas de ecrã" +folders_window.font_label = "Tipos de letra" +folders_window.savegames_label = "Jogos gravados" +folders_window.back = "Retroceder" +folders_window.savegames_location = "Escolha a directoria que usar para jogos gravados" +folders_window.screenshots_location = "Escolha a directoria que usar para capturas de ecrã" +customise_window.average_contents = "Itens comuns" +customise_window.option_on = "Ligado" +customise_window.paused = "Construir com o jogo pausado" +customise_window.option_off = "Desligado" +customise_window.intro = "Reproduzir vídeo de introdução" +customise_window.caption = "Definições Personalizadas" +customise_window.back = "Retroceder" +customise_window.movies = "Controle Geral de Vídeos" +customise_window.volume = "Atalho para baixar o volume" +customise_window.aliens = "Pacientes Extraterrestres" +customise_window.fractured_bones = "Ossos Partidos" +options_window.folder = "Pastas" +options_window.customise = "Personalizar" +options_window.audio = "Som Geral" +menu_options.twentyfour_hour_clock = " RELÓGIO DE 24 HORAS " +menu_options.wage_increase = " EXIGÊNCIAS SALARIAIS" +install.ok = "OK" +install.cancel = "Cancelar" +adviser.research.drug_improved_1 = "A droga para %s foi melhorada pelo Departamento de Pesquisa" +adviser.warnings.no_desk_7 = "Já construiu o balcão de atendimento, então que tal contratar uma recepcionista? Não irá atender clientes até que resolva isto!" +adviser.warnings.researcher_needs_desk_1 = "Um Investigador precisa de ter uma secretária onde trabalhar." +adviser.warnings.no_desk_6 = "Já tem a recepcionista, então que tal construir uma balcão de atendimento para ela trabalhar?" +adviser.warnings.nurse_needs_desk_1 = "Cada Enfermeira necessita de uma secretária onde trabalhar." +adviser.warnings.researcher_needs_desk_2 = "O seu Investigador está satisfeito que o tenha deixado descansar um pouco. Se quer ter mais pessoal a fazer pesquisa, então precisa de dar uma secretária a cada um deles." +adviser.warnings.no_desk_5 = "Está na hora, devem estar a chegar pacientes a qualquer momento!" +adviser.warnings.no_desk_4 = "Uma recepcionista precisa de ter o seu posto de trabalho para atender os pacientes assim que chegam." +adviser.warnings.researcher_needs_desk_3 = "Cada Investigador necessita de uma secretária onde trabalhar." +adviser.warnings.cannot_afford_2 = "Não tem dinheiro suficiente no banco para fazer essa compra!" +adviser.warnings.nurse_needs_desk_2 = "A sua Enfermeira está satisfeita que a tenha deixado descansar um pouco. Se quer ter mais que uma a trabalhar na enfermaria, então precisa de dar uma secretária a cada uma delas." object.litter = "Lixo" tooltip.objects.litter = "Lixo: Deitado fora por um paciente porque não encontrou um caixote do lixo onde o colocar." @@ -448,14 +530,14 @@ -introduction_texts.demo = { - "Bem-vindo ao hospital do demo!", - "Infelizmente este demo só tem este nível.Contudo existe aqui muito trabalho para te manter ocupado!", - "Encontrarás várias doenças que requerem salas diferentes para os seus tratamentos.Ao longo do tempo irão ocorrer algumas emergências e precisarás de descobrir novos tratamentos atráves da sala de pesquisa.", - "O teu objectivo é ganhar 100,000$,ter um hospital avaliado em 70,000$,uma reputação de 700 e uma cura de 75% dos pacientes.", - "Garante que a tua reputação não cai abaixo de 300 e que não mates 40% dos teus pacientes senão perderás o nível.", - "Boa sorte!", -} +introduction_texts.demo = + "Bem-vindo ao hospital do demo!//" .. + "Infelizmente este demo só tem este nível.Contudo existe aqui muito trabalho para te manter ocupado! " .. + "Encontrarás várias doenças que requerem salas diferentes para os seus tratamentos.Ao longo do tempo " .. + "irão ocorrer algumas emergências e precisarás de descobrir novos tratamentos atráves da sala de pesquisa. " .. + "O teu objectivo é ganhar 100,000$,ter um hospital avaliado em 70,000$,uma reputação de 700 e uma cura de 75% dos pacientes. " .. + "Garante que a tua reputação não cai abaixo de 300 e que não mates 40% dos teus pacientes senão perderás o nível.//" .. + "Boa sorte!" diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/italian.lua corsix-th-0.62/CorsixTH/Lua/languages/italian.lua --- corsix-th-0.30/CorsixTH/Lua/languages/italian.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/italian.lua 2018-07-21 11:13:17.000000000 +0000 @@ -31,7 +31,10 @@ -- The originals of these two contain one space too much fax.emergency.cure_not_possible_build = "E' necessario costruire un %s" -fax.emergency.cure_not_possible_build_and_employ = "E' necessario costruire un %s e assunere un %s" +fax.emergency.cure_not_possible_build_and_employ = "E' necessario costruire un %s e assumere un %s" + +-- An override for the squits becoming the the squits see issue 1646 +adviser.research.drug_improved_1 = "Il medicinale per %s è stato migliorato dal Reparto Ricerca." ------------------------------- NEW STRINGS ------------------------------- date_format = { @@ -49,12 +52,26 @@ tooltip.research_policy.no_research = "Non c'è nessuna ricerca in corso in questa categoria al momento" tooltip.research_policy.research_progress = "Progresso verso una nuova scoperta in questa categoria: %1%/%2%" +menu["player_count"] = "CONTA GIOCATORI" + +menu_file = { + load = " (SHIFT+L) CARICA ", + save = " (SHIFT+S) SALVA ", + restart = " (SHIFT+R) RIAVVIA", + quit = " (SHIFT+Q) ESCI " +} + menu_options = { + sound = " (ALT+S) SONORO ", + announcements = " (ALT+A) ANNUNCI ", + music = " (ALT+M) MUSICA ", + jukebox = " (J) JUKEBOX ", lock_windows = " BLOCCA FINESTRE ", edge_scrolling = " SCORRIMENTO AI LATI ", - settings = " IMPOSTAZIONI ", - adviser_disabled = " CONSIGLIERE ", + adviser_disabled = " (SHIFT+A) CONSIGLIERE ", warmth_colors = " COLORI RISCALDAMENTO ", + wage_increase = " RICHIESTE STIPENDI", + twentyfour_hour_clock = " OROLOGIO 24 ORE " } menu_options_game_speed = { @@ -72,6 +89,11 @@ choice_3 = " GIALLO ARANCIONE ROSSO ", } +menu_options_wage_increase = { + grant = " CONCEDI ", + deny = " NEGA ", +} + -- Add F-keys to entries in charts menu (except briefing), also town_map was added. menu_charts = { bank_manager = " (F1) BANCA ", @@ -91,6 +113,7 @@ menu_debug = { jump_to_level = " SALTA AL LIVELLO ", + connect_debugger = " (CTRL + C) CONNETTI SERVER LUA DBGp ", transparent_walls = " (X) MURA TRASPARENTI ", limit_camera = " LIMITA TELECAMERA ", disable_salary_raise = " DISABILITA AUMENTI DI SALARIO ", @@ -98,13 +121,13 @@ make_debug_patient = " CREA UN PAZIENTE DI DEBUG ", cheats = " (F11) CHEAT ", lua_console = " (F12) CONSOLE LUA ", + debug_script = " (SHIFT + D) ESEGUI SCRIPT DI DEBUG ", calls_dispatcher = " GESTORE CHIAMATE ", dump_strings = " FAI IL DUMP DELLE STRINGHE ", dump_gamelog = " (CTRL+D) FAI IL DUMP DEL GAMELOG ", map_overlay = " MAPPA IN SOVRAPPOSIZIONE ", sprite_viewer = " VISUALIZZATORE SPRITE ", } - menu_debug_overlay = { none = " NESSUN OVERLAY ", flags = " FLAGS ", @@ -119,6 +142,12 @@ byte_7 = " BYTE 7 ", parcel = " LOTTO ", } +menu_player_count = { + players_1 = " 1 GIOCATORE ", + players_2 = " 2 GIOCATORI ", + players_3 = " 3 GIOCATORI ", + players_4 = " 4 GIOCATORI ", +} adviser = { room_forbidden_non_reachable_parts = "Mettere la stanza in questa posizione risulterebbe nel blocco dell'accesso ad alcune parti dell'ospedale.", warnings = { @@ -126,7 +155,12 @@ no_desk_1 = "Se vuoi che i pazienti vengano nel tuo ospedale dovrai assumere una receptionist e costruirle una scrivania dove farla lavorare!", no_desk_2 = "Ben fatto, deve essere un record mondiale: quasi un anno e nessun paziente! Se vuoi continuare come Manager di questo ospedale dovrai assumere una receptionist e costruire un banco di accettazione dove farla lavorare!", no_desk_3 = "Grandioso, quasi un anno e ancora non hai personale all'accettazione! Come ti aspetti di trovare pazienti, ora vedi di rimediare e di non fare più casini!", - cannot_afford = "Non hai abbastanza soldi in banca per assumere questa persona!", -- I can't see anything like this in the original strings + no_desk_4 = "Una receptionist ha bisogno della sua stazione di lavoro per accogliere i clienti quando arrivano", + no_desk_5 = "Beh, era ora, presto dovresti cominciare a vedere arrivare i pazienti!", + no_desk_6 = "Hai una receptionist, che ne dici quindi di costruirle un banco di accettazione dove poter lavorare?", + no_desk_7 = "Hai costruito il banco di accettazione, quindi che ne dici di assumere una receptionist? Non vedrai pazienti finché non risolvi questa cosa!", + cannot_afford = "Non hai abbastanza soldi in banca per assumere quella persona!", -- I can't see anything like this in the original strings + cannot_afford_2 = "Non hai abbastanza soldi in banca per fare quell'acquisto!", falling_1 = "Ehi! Non è divertente, attento a dove clicchi: qualcuno potrebbe farsi male!", falling_2 = "Basta fare casini, a te piacerebbe?", falling_3 = "Ahi, deve far male, qualcuno chiami un dottore!", @@ -135,23 +169,27 @@ falling_6 = "Non è una sala da bowling, i malati non dovrebbero essere trattati così!", research_screen_open_1 = "Devi costruire un Reparto Ricerca prima di poter accedere alla schermata Ricerca.", research_screen_open_2 = "La Ricerca è disabilitata in questo livello.", + researcher_needs_desk_1 = "Un ricercatore ha bisogno di una scrivania su cui lavorare.", + researcher_needs_desk_2 = "Al tuo ricercatore ha fatto piacere tu gli abbia concesso una pausa. Se invece volevi assegnare più personale alla ricerca devi procurare a ognuno di loro una scrivania sulla quale lavorare.", + researcher_needs_desk_3 = "Ogni ricercatore ha bisogno della propria scrivania su cui poter lavorare.", + nurse_needs_desk_1 = "Ogni infermiera ha bisogno della propria scrivania su cui poter lavorare.", + nurse_needs_desk_2 = "Alla tua infermiera ha fatto piacere tu le abbia concesso una pausa. Se invece volevi assegnare più personale al reparto devi procurare a ognuna di loro una scrivania sulla quale lavorare.", + low_prices = "I tuoi prezzi per %s sono troppo bassi. Questo attirerà più persone nel tuo ospedale, ma non guadagnerai molto da ognuno di loro.", + high_prices = "I tuoi prezzi per %s sono alti. In questo modo vedrai buoni guadagni sul breve periodo, ma a lungo andare spingerai molte persone ad andarsene.", + fair_prices = "I tuoi prezzi per %s sembrano giusti ed equilibrati.", + patient_not_paying = "Un paziente è andato via senza pagare %s perché è troppo costosa!", }, cheats = { th_cheat = "Congratulazioni, hai sbloccato i cheat!", - crazy_on_cheat = "Oh no! Tutti i dottori sono impazziti!", - crazy_off_cheat = "Phew... i dottori sono di nuovo sani.", roujin_on_cheat = "Sfida di Roujin attivata! Buona fortuna...", roujin_off_cheat = "Sfida di Roujin disattivata.", - hairyitis_cheat = "Cheat Cespuglite attivato!", - hairyitis_off_cheat = "Cheat Cespuglite disattivato.", - bloaty_cheat = "Cheat Testa Gonfia attivato!!", - bloaty_off_cheat = "Cheat Testa Gonfia disattivato.", }, } dynamic_info.patient.actions.no_gp_available = "Aspettando che venga costruito un ambulatorio" dynamic_info.staff.actions.heading_for = "Andando verso %s" dynamic_info.staff.actions.fired = "Licenziato" +dynamic_info.patient.actions.epidemic_vaccinated = "Non sono più infetto" progress_report.free_build = "COSTRUZIONE LIBERA" @@ -177,15 +215,20 @@ } letter = { - dear_player = "Caro %s", + dear_player = "Caro %s\n", custom_level_completed = "Ben fatto! Hai completato tutti gli obiettivi di questo livello personalizzato!", return_to_main_menu = "Vuoi tornare al menu principale o vuoi continuare a giocare?", + campaign_level_completed = "Ottimo lavoro! Hai battuto il livello. Ma non è ancora finita!\n Saresti interessato a una posizione nell'ospedale %s?", + campaign_completed = "Incredibile! Sei riuscito a completare tutti i livelli. Ora puoi rilassarti e divertirti a riempire i forum su internet con i tuoi fantastici risultati. Buona fortuna!", + campaign_level_missing = "Mi dispiace, ma sembra che il livello successivo di questa campagna non sia presente. (Nome: %s)", } install = { title = "----------------------------- Installazione CorsixTH -----------------------------", th_directory = "CorsixTH ha bisogno di una copia dei file dati di Theme Hospital (o della demo) per essere eseguito. Per favore indica la posizione della cartella di installazione di Theme Hospital.", + ok = "Ok", exit = "Esci", + cancel = "Annulla", } misc.not_yet_implemented = "(non ancora implementato)" @@ -193,9 +236,12 @@ main_menu = { new_game = "Nuova partita", + custom_campaign = "Campagna personalizzata", custom_level = "Livello personalizzato", + continue = "Continua partita", load_game = "Carica partita", options = "Opzioni", + map_edit = "Editor mappe", savegame_version = "Versione salvataggi: ", version = "Versione: ", exit = "Esci", @@ -203,9 +249,11 @@ tooltip.main_menu = { new_game = "Inizia una nuova partita", + custom_campaign = "Gioca una campagna creata dalla comunità", custom_level = "Costruisci il tuo ospedale in un livello personalizzato", load_game = "Carica una partita salvata in precedenza", options = "Modifica le impostazioni", + map_edit = "Crea una mappa personalizzata", exit = "No, per favore non andartene!", } @@ -222,11 +270,23 @@ custom_game_window = { caption = "Partita personalizzata", free_build = "Costruzione Libera", + load_selected_level = "Inizia", } tooltip.custom_game_window = { - start_game_with_name = "Carica il livello %s", + choose_game = "Clicca su un livello per avere più informazioni", free_build = "Spunta questa casella per giocare senza soldi, né vittoria o sconfitta", + load_selected_level = "Carica e gioca il livello selezionato", +} + +custom_campaign_window = { + caption = "Campagna personalizzata", + start_selected_campaign = "Inizia campagna", +} + +tooltip.custom_campaign_window = { + choose_campaign = "Seleziona una campagna per avere più informazioni", + start_selected_campaign = "Carica il primo livello di questa campagna", } save_game_window = { @@ -239,6 +299,16 @@ new_save_game = "Inserisci il nome per un nuovo salvataggio", } +save_map_window = { + caption = "Salva mappa (%1%)", + new_map = "Nuova mappa", +} + +tooltip.save_map_window = { + map = "Sovrascrivi mappa %s", + new_map = "Inserisci il nome per salvataggio mappa", +} + menu_list_window = { name = "Nome", save_date = "Modificata", @@ -261,12 +331,11 @@ custom_resolution = "Personalizzata...", width = "Largh", height = "Alt", - apply = "Applica", - data_location = "Posizione dati", - font_location = "Posizione font", - browse = "Sfoglia...", - new_th_directory = "Qui puoi specificare una nuova cartella di installazione di Theme Hospital. Appena scegli la nuova cartella il gioco verrà riavviato.", + audio = "Audio globale", + customise = "Personalizza", + folder = "Cartelle", language = "Lingua del gioco", + apply = "Applica", cancel = "Cancella", back = "Indietro", } @@ -280,18 +349,76 @@ height = "Inserisci l'altezza dello schermo desiderata", apply = "Applica la risoluzione inserita", cancel = "Esci senza cambiare la risoluzione", - data_location = "La cartella dove è installato il Theme Hospital originale, che è richiesto per eseguire CorsixTH", - font_location = "La posizione di un font che è in grado di mostrare caratteri Unicode richiesti dalla tua lingua. Se non specificata, non potrai scegliere lingue che hanno bisogno di più caratteri rispetto a quelli di cui dispone il gioco originale. Esempio: Russo e Cinese", + audio_button = "Attiva o disattiva tutti i suoni del gioco", + audio_toggle = "Audio on o off", + customise_button = "Altre impostazioni che puoi cambiare per personalizzare la tua esperienza di gioco", + folder_button = "Opzioni cartelle", language = "La lingua in cui verrà mostrato il testo", select_language = "Seleziona la lingua del gioco", language_dropdown_item = "Seleziona %s come lingua", - original_path = "La cartella dell'installazione di Theme Hospital originale attualmente selezionata", - browse = "Seleziona un'altra cartella di installazione di Theme Hospital (posizione corrente: %1%)", - browse_font = "Seleziona un altro file font (posizione corrente: %1%)", - no_font_specified = "Non hai ancora specificato alcuna posizione!", back = "Chiudi la finestra delle opzioni", } +customise_window = { + caption = "Impostazioni personalizzate", + option_on = "On", + option_off = "Off", + back = "Indietro", + movies = "Controllo filmati globale", + intro = "Riproduci filmato introduttivo", + paused = "Costruzione durante la pausa", + volume = "Scorciatoia volume basso", + aliens = "Pazienti alieni", + fractured_bones = "Ossa Rotte", + average_contents = "Oggetti frequenti", +} + +tooltip.customise_window = { + movies = "Controllo filmati globale, questo ti permette di disattivare tutti i filmati", + intro = "Disattiva o attiva la riproduzione del filmato introduttivo. I filmati globali devono essere attivati se vuoi che il filmato introduttiva venga riprodotto ogni volta che avvii CorsixTH", + paused = "In Theme Hospital il giocatore può usare il menù superiore solo quando il gioco era in pausa. Questa è l'impostazione predefinita anche in CorsixTH, ma attivando questa opzione non ci saranno limiti di utilizzo mentre il gioco è in pausa", + volume = "Se il pulsante per abbassare il volume ti fa aprire anche il Registro Cure, attiva questa opzione per impostare Shift + C come scorciatoia per il Registro Cure", + aliens = "A causa dell'assenza delle giuste animazioni abbiamo fatto sì che i pazienti con DNA Alieno possano arrivare solo con un'emergenza. Per permettere ai pazienti con DNA Alieno di visitare il tuo ospedale anche al di fuori delle emergenze disattiva questa opzione", + fractured_bones = "A causa della scarsa qualità di alcune animazioni abbiamo fatto sì che non ci siano pazienti donne con Ossa Rotte. Per far sì che donne con Ossa Rotte visitino il tuo ospedale, disattiva questa opzione", + average_contents = "Se vuoi che il gioco ricordi quali oggetti extra aggiungi di solito quando crei una stanza attiva questa opzione", + back = "Chiudi questo menù e torna al menù delle impostazioni", +} + +folders_window = { + caption = "Posizione cartelle", + data_label = "Posizione TH", + font_label = "Font", + music_label = "MP3", + savegames_label = "Salvataggi", + screenshots_label = "Screenshot", + -- next four are the captions for the browser window, which are called from the folder setting menu + new_th_location = "Qui puoi specificare una nuova cartella dell'installazione di Theme Hospital. Appena selezionerai una nuova cartella il gioco verrà riavviato.", + savegames_location = "Seleziona la cartella che vuoi usare per i salvataggi", + music_location = "Seleziona la cartella che vuoi usare per la tua musica", + screenshots_location = "Seleziona la cartella che vuoi usare per i tuoi screenshot", + back = "Indietro", +} + +tooltip.folders_window = { + browse = "Sfoglia le cartelle", + data_location = "La cartella dell'installazione originale di Theme Hospital, che è richiesto per eseguire CorsixTH", + font_location = "Posizione di un font che è in grado di mostrare i caratteri Unicode richiesti dalla tua lingua. Se non specificata, non potrai scegliere lingue che hanno bisogno di più caratteri rispetto a quelli di cui dispone il gioco originale. Esempio: Russo e Cinese", + savegames_location = "Di default la cartella dei salvataggi è posizionata vicina al file di configurazione e ci vengono messi i file di salvataggio. Se non dovesse andare bene puoi scegliere la cartella che preferisci, basta selezionare quella che vuoi usare.", + screenshots_location = "Di default gli screenshot vengono salvati in una cartella vicina al file di configurazione. Se non dovesse andare bene puoi scegliere la cartella che preferisci, basta selezionare quella che vuoi usare.", + music_location = "Seleziona la posizione per i tuoi file MP3. Devi aver già creato la cartella e poi selezionare la cartella che hai creato.", + browse_data = "Sfoglia per selezionare un'altra posizione di un'installazione di Theme Hospital (posizione attuale: %1%)", + browse_font = "Sfoglia per selezionare un altro file font ( posizione attuale: %1% )", + browse_saves = "Sfoglia per selezionare un'altra posizione per la tua cartella dei salvataggi ( Posizione attuale: %1% ) ", + browse_screenshots = "Sfoglia per selezionare un'altra posizione per la tua cartella degli screenshot ( Posizione attuale: %1% ) ", + browse_music = "Sfoglia per selezionare un'altra posizione per la tua cartella della musica ( Posizione attuale: %1% ) ", + no_font_specified = "Non è stata ancora specificata nessuna posizione per il font!", + not_specified = "Non è stata ancora specificata nessuna posizione per la cartella!", + default = "Posizione di default", + reset_to_default = "Ripristina la cartella alla sua posizione di default", + -- original_path = "The currently chosen directory of the original Theme Hospital installation", -- where is this used, I have left if for the time being? + back = "Chiudi questo menù e torna al menù delle impostazioni", +} + font_location_window = { caption = "Scegli il font (%1%)", } @@ -302,7 +429,7 @@ } tooltip.handyman_window = { - parcel_select = "Il lotto dove l'inserviente può operare. Clicca per cambiarlo." + parcel_select = "Il lotto dove l'inserviente può operare, clicca per cambiarlo" } new_game_window = { @@ -316,7 +443,7 @@ hard = "Consulente (Difficile)", tutorial = "Tutorial", start = "Comincia", - cancel = "Cancella", + cancel = "Annulla", } tooltip.new_game_window = { @@ -345,15 +472,28 @@ dialog_missing_graphics = "I file dei dati della demo non contengono questa stringa.", save_prefix = "Errore durante il salvataggio: ", load_prefix = "Errore durante il caricamento: ", + no_games_to_contine = "Non ci sono partite salvate.", + load_quick_save = "Errore, non è possibile caricare il salvataggio veloce perché non esiste, ma non preoccuparti: ne abbiamo appena creato uno al posto tuo!", map_file_missing = "Non ho potuto trovare la mappa %s per questo livello!", minimum_screen_size = "Per favore inserisci almeno una risoluzione di 640x480.", - maximum_screen_size = "Per favore inserisci al massimo una risoluzione di 3000x2000.", unavailable_screen_size = "La risoluzione che hai richiesto non è disponibile a schermo intero.", + alien_dna = "NOTA: Non ci sono animazioni per i pazienti Alieni per quando si siedono, aprono o bussano sulle porte etc. Quindi, così come in Theme Hospital, mentre fanno queste cose appariranno normali per poi tornare ad apparire alieni. I pazienti con DNA Alieno appariranno solo se impostati dal file del livello", + fractured_bones = "NOTA: L'animazione per i pazienti donne con Ossa Rotte non è perfetta", + could_not_load_campaign = "Errore nel caricare la campagna: %s", + could_not_find_first_campaign_level = "Non è stato possibile trovare il primo livello di questa campagna: %s", +} + +warnings = { + levelfile_variable_is_deprecated = "Attenzione: Il livello %s contiene una definizione di variabile deprecata nel file di livello." .. + "'%LevelFile' è stato rinominato in '%MapFile'. Per favore richiedi al creatore della mappa di aggiornare il livello.", } confirmation = { needs_restart = "Cambiare questa impostazione richiede che CorsixTH sia riavviato. Ogni progresso non salvato sarà perduto. Sei sicuro di volerlo fare?", abort_edit_room = "Stai attualmente costruendo o modificando una stanza. Se tutti gli oggetti richiesti sono stati posizionati sarà completata, altrimenti sarà cancellata. Continuare?", + maximum_screen_size = "La risoluzione che hai inserito è superiore a 3000x2000. Risoluzioni maggiori sono supportate, ma richiederanno un hardware migliore per mantenere un livello di frame rate giocabile. Sei sicuro di voler continuare?", + music_warning = "Nota: E' necessario avere la libreria smpeg.dll o equivalente nel tuo sistema operativo, altrimenti non sentirai alcuna musica nel gioco. Vuoi continuare?", + --This next line isn't in the english.lua, but when strings are dump it is reported missing restart_level = "Sei sicuro di voler riavviare il livello?", } @@ -417,19 +557,23 @@ warning = "Attenzione: Non riceverai alcun punto bonus alla fine del livello se usi i cheat!", cheated = { no = "Cheat usati: No", - yes = "Cheats usati: Sì", + yes = "Cheat usati: Sì", }, cheats = { money = "Cheat soldi", - all_research = "Cheat Completa Ricerche", + all_research = "Completa Ricerche", emergency = "Crea Emergenza", vip = "Crea VIP", earthquake = "Crea Terremoto", + epidemic = "Genera paziente contagioso", + toggle_infected = "Attiva o disattiva icone infetti", create_patient = "Crea Paziente", end_month = "Fine Mese", end_year = "Fine Anno", lose_level = "Perdi Livello", win_level = "Vinci Livello", + increase_prices = "Aumenta prezzi", + decrease_prices = "Diminuisci prezzi", }, close = "Chiudi", } @@ -442,23 +586,27 @@ emergency = "Crea un'emergenza.", vip = "Crea un VIP.", earthquake = "Crea un terremoto.", + epidemic = "Crea un paziente contagioso che potrebbe causare un'epidemia", + toggle_infected = "Attiva o disattiva le icone infetti per le epidemie attive scoperte", create_patient = "Crea un Paziente sul bordo della mappa.", end_month = "Salta alla fine del mese.", end_year = "Salta alla fine dell'anno.", lose_level = "Perdi il livello corrente.", win_level = "Vinci il livello corrente.", + increase_prices = "Aumenta tutti i prezzi del 50% (max 200%)", + decrease_prices = "Diminuisci tutti i prezzi del 50% (min 50%)", } } introduction_texts = { - demo = { - "Benvenuto nell'ospedale demo!", - "Sfortunatamente la versione demo contiene solo questo livello. Ad ogni modo c'è abbastanza da fare per tenerti occupato per un bel po'!", - "Incontrerai diverse malattie che richiederanno diverse cliniche per essere curate. Ogni tanto potrebbero presentarsi delle emergenze. E avrai bisogno di ricercare nuove strumentazioni tramite il centro ricerche.", - "Il tuo obiettivo è di guadagnare $100,000, avere un ospedale che valga $70,000 e una reputazione di 700, oltre che curare almeno il 75% dei tuoi pazienti.", - "Assicurati che la tua reputazione non scenda al di sotto di 300 e di non uccidere più del 40% dei tuoi pazienti, o perderai.", + demo = + "Benvenuto nell'ospedale demo!//" .. + "Sfortunatamente la versione demo contiene solo questo livello. Ad ogni modo c'è abbastanza da fare per tenerti occupato per un bel po'! " .. + "Incontrerai diverse malattie che richiederanno diverse cliniche per essere curate. Ogni tanto potrebbero presentarsi delle emergenze. " .. + "E avrai bisogno di ricercare nuove strumentazioni tramite il centro ricerche. " .. + "Il tuo obiettivo è di guadagnare $100,000, avere un ospedale che valga $70,000 e una reputazione di 700, oltre che curare almeno il 75% dei tuoi pazienti. " .. + "Assicurati che la tua reputazione non scenda al di sotto di 300 e di non uccidere più del 40% dei tuoi pazienti, o perderai.//" .. "Buona fortuna!", - }, } calls_dispatcher = { @@ -476,6 +624,52 @@ close = "Chiude la finestra del gestore chiamate", } +update_window = { + caption = "Aggiornamento disponibile!", + new_version = "Nuova versione:", + current_version = "Versione corrente:", + download = "Vai alla pagina del download", + ignore = "Salta e vai al menù principale", +} + +tooltip.update_window = { + download = "Vai alla pagina del download per trovare l'ultima versione di CorsixTH", + ignore = "Ignora l'aggiornamento per ora. Questa notifica apparirà di nuovo al prossimo avvio di CorsixTH", +} + +map_editor_window = { + pages = { + inside = "Interno", + outside = "Esterno", + foliage = "Fogliame", + hedgerow = "Siepe", + pond = "Laghetto", + road = "Strada", + north_wall = "Muro nord", + west_wall = "Muro ovest", + helipad = "Eliporto", + delete_wall = "Cancella mura", + parcel_0 = "Lotto 0", + parcel_1 = "Lotto 1", + parcel_2 = "Lotto 2", + parcel_3 = "Lotto 3", + parcel_4 = "Lotto 4", + parcel_5 = "Lotto 5", + parcel_6 = "Lotto 6", + parcel_7 = "Lotto 7", + parcel_8 = "Lotto 8", + parcel_9 = "Lotto 9", + camera_1 = "Camera 1", + camera_2 = "Camera 2", + camera_3 = "Camera 3", + camera_4 = "Camera 4", + heliport_1 = "Eliporto 1", + heliport_2 = "Eliporto 2", + heliport_3 = "Eliporto 3", + heliport_4 = "Eliporto 4", + paste = "Incolla area", + } +} -------------------------------- UNUSED ----------------------------------- ------------------- (kept for backwards compatibility) ---------------------- diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/korean.lua corsix-th-0.62/CorsixTH/Lua/languages/korean.lua --- corsix-th-0.30/CorsixTH/Lua/languages/korean.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/korean.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2013 nullstein +--[[ Copyright (c) 2013 nullstein Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -2169,7 +2169,7 @@ sack_staff = "정말로 이 직원을 해고하기 원합니까?", replace_machine = "정말로 %s 기계를 $%d 의 비용으로 교체합니까?", maximum_screen_size = "입력한 화면 크기가 3000 x 2000 보다 큽니다. 큰 해상도도 가능하지만, 플레이할만한 프레임 수를 유지하려면 하드웨어 성능이 충분히 좋아야 합니다. 계속하시겠습니까?", - music_warning = "게임중에 mp3 파일들을 재생하도록 하기 전에, smpeg.dll 파일이나 그에 상응하는 파일이 운영 체제에 설치되어 있어야 합니다. 그렇지 않으면 음악이 재생되지 않을 것입니다. 현재 64bit 시스템에는 이에 대응되는 파일이 없습니다. 계속하시겠습니까?", + music_warning = "게임중에 mp3 파일들을 재생하도록 하기 전에, smpeg.dll 파일이나 그에 상응하는 파일이 운영 체제에 설치되어 있어야 합니다. 그렇지 않으면 음악이 재생되지 않을 것입니다. 계속하시겠습니까?", } months = { [1] = "1월", @@ -2232,133 +2232,115 @@ }, } introduction_texts = { - demo = { - [1] = "데모 병원에 오신 것을 환영합니다!", - [2] = "안타깝게도 데모 버전에서는 (커스텀 레벨을 제외하면) 이 레벨만 플레이할 수 있습니다. 그렇지만, 여기에도 당신을 한동안 바쁘게 할만큼의 일거리는 충분히 있습니다! ", - [3] = "당신은 치료를 위해 다른 종류의 시설을 필요로 하는 다양한 질병을 만나게 될 것입니다. 가끔은 응급 상황이 발생할지도 모릅니다. 그리고 당신은 연구실을 지어 새로운 시설들을 연구해야 할 것입니다. ", - [4] = "당신의 목표는 $100,000 를 벌고, 병원 가치를 $70,000 만큼 올리며, 평판을 700 만큼 유지하고, 방문하는 환자의 75% 이상을 완치시키는 것입니다. ", - [5] = "당신의 평판이 300 아래로 떨어지거나 40% 이상의 환자들을 죽게 하지 마세요. 어느 하나라도 발생하면 당신은 게임에서 지게 됩니다. ", - [6] = "행운을 바랍니다!", - }, - level1 = { - [1] = "당신의 첫 병원에 오신 것을 환영합니다!//", - [2] = "접수대와 진료실을 짓고 접수원과 의사를 고용해서 이 곳이 제대로 돌아가게끔 하세요. ", - [3] = "그러고 나서 할일이 생길 때까지 어느 정도 기다리세요. ", - [4] = "정신과를 짓고 정신과 자격이 있는 의사를 고용하는 것은 좋은 생각입니다. ", - [5] = "약국을 짓고 간호사를 고용하는 것도 환자들을 치료하는 데 꼭 필요합니다. ", - [6] = "부은 머리 증상을 호소하는 환자들을 주의하세요 - 팽창실을 지으면 이 문제를 해결할 수 있을 것입니다. ", - [7] = "당신의 목표는 10 명의 환자를 치료하고 평판이 200 아래로 떨어지지 않도록 하는 것입니다.", - }, - level2 = { - [1] = "이 지역에는 더 다양한 병이 도사리고 있습니다. ", - [2] = "더 많은 환자들을 치료할 수 있도록 병원을 구성하고, 연구 시설을 지을 계획을 세우세요. ", - [3] = "당신의 시설들을 깨끗하게 유지하는 것을 잊지 말고, 평판을 최대한 높에 유지하도록 노력하세요. 당신은 늘어진 혀를 발견하게 될텐데, 늘어진 혀 클리닉을 지어서 치료할 수 있습니다. ", - [4] = "또한, 심전도실을 지으면 새로운 질병들을 진단하는 데 도움이 될 것입니다. ", - [5] = "이 두 가지 방을 짓기 위해서는 먼저 연구를 해야 합니다. 그리고 이제 당신은 병원을 확장하기 위한 새로운 토지를 구매할 수도 있습니다. 그러려면 마을 지도를 사용하세요. ", - [6] = "300 의 평판과, $10,000 의 은행 잔고, 그리고 40 명의 환자를 치료하는 것을 목표로 하세요.", - }, - level3 = { - [1] = "이번에는 부유한 지역에 당신의 병원을 세우게 될 것입니다. ", - [2] = "보건부는 이 곳에서 당신이 상당한 이익을 남기기를 바라고 있습니다. ", - [3] = "처음에는 어느 정도 평판을 쌓아야 하겠지만, 병원이 안정적으로 돌아가기 시작하면, 최대한 돈을 많이 버는 것에 집중하세요. ", - [4] = "또한 응급 상황이 발생할 가능성도 있습니다. ", - [5] = "응급 상황에는 동일한 질병을 가진 많은 사람들이 한꺼번에 몰려오게 됩니다. ", - [6] = "제한된 시간 내에 모두를 치료하게 되면 당신의 평판이 올라가며 큰 보너스를 받게 됩니다. ", - [7] = "왕자병과 같은 질병이 발생할 수 있으며, 당신은 수술실을 짓고 또한 가까운 곳에 병동을 지을 예산을 마련해 두어야 할 것입니다. ", - [8] = "성공하기 위해 $20,000 만큼을 버세요.", - }, - level4 = { - [1] = "모든 환자들을 행복하게 해주고, 그들을 가능한한 효율적으로 치료하며, 사망자의 수는 정말 최소한으로 유지하세요. ", - [2] = "당신의 평판이 이 레벨의 성공을 좌우하므로, 평판을 최대한 높게 유지하도록 노력하세요. ", - [3] = "돈에 대해서는 너무 신경쓰지 마세요. 돈은 평판이 높아지면 자연스럽게 따라오게 될 겁니다. ", - [4] = "또한, 당신은 이제 의사들의 능력을 향상시키기 위해 그들을 교육시키는 것도 가능합니다. ", - [5] = "교육받은 의사들은, 어떤 질병인지 아주 확실치 않은 환자들을 더 잘 치료할 수 있을 것입니다. ", - [6] = "500 이상의 평판을 달성하세요.", - }, - level5 = { - [1] = "여기는 가지각색의 질병들을 치료하느라 아주 분주한 병원이 될 겁니다. ", - [2] = "당신이 고용할 수 있는 의사들은 모두 의대를 갓 졸업한 신입들이기 때문에, 교육실을 지어서 적정 수준으로 훈련시키는 것이 필수입니다. ", - [3] = "의사들을 교육할 수 있는 딱 세 명의 전문의들만 주어져 있으므로, 이들을 행복하게 해 주세요. ", - [4] = "또 유념해야할 것은, 병원이 샌 안드로이드 단층 위에 지어져 있다는 것입니다. ", - [5] = "다시말해, 이 병원은 언제나 지진의 위험에 노출되어 있습니다. ", - [6] = "지진은 당신의 기계들을 손상시키고, 병원을 원만하게 운영하는 것을 방해할 것입니다. ", - [7] = "성공하려면 평판을 400 만큼 올리고, $50,000 를 예금하세요. 또한, 200 명의 환자를 치료하세요.", - }, - level6 = { - [1] = "당신의 모든 지식을 동원해서, 적절한 이윤을 남기면서도 병약한 대중이 가진 온갖 질병들을 치료할 수 있도록 원만하게 운영되는 병원을 지으세요. ", - [2] = "이 곳 주변의 공기는 특별히 세균과 질병을 옮기는 데 좋다는 것을 알아두세요. ", - [3] = "병원을 정말 구석구석 깨끗하게 유지하지 않으면, 환자들 사이에서 아주 심각한 전염병이 도는 것을 보게 될 것입니다. ", - [4] = "돈을 $150,000 만큼 벌고, 병원의 가치가 $140,000 이상이 되도록 하세요.", - }, - level7 = { - [1] = "이번에는 당신의 병원이 보건부의 철저한 감시 하에 놓여있게 될 것이므로, 당신이 돈을 충분히 많이 벌고 있다는 것을 은행 잔고로 보여주고, 평판을 올리도록 하세요. ", - [2] = "환자들이 사망하는 것은 최대한 피해야 합니다 - 사업하는데 전혀 도움이 안되니까요. ", - [3] = "최고의 직원들을 고용하도록 하고, 필요한 장비들을 갖추도록 하세요. ", - [4] = "600 의 평판과 $200,000 의 잔고를 얻으세요.", - }, - level8 = { - [1] = "얼마나 비용대비 효율이 높은 병원을 짓는 것은 당신에게 달렸습니다. ", - [2] = "이 주변 주민들은 상당히 부유한 편이니, 할 수 있는 만큼 쥐어 짜내세요. ", - [3] = "사람들을 치료하는 것도 좋지만, 돈을 모으는 것이 목표라는 것을 기억해야 합니다. ", - [4] = "이 아픈 사람들을 아주 빈털터리로 만들어 버리세요. ", - [5] = "이 레벨을 완료하려면 재산을 $300,000 만큼 쌓아야 합니다.", - }, - level9 = { - [1] = "보건부의 재산을 좀 불려주고 장관님께 리무진도 한 대 뽑아드렸으니, 이제 다시 몸이 아픈 사람들을 잘 돌보는 훌륭한 병원을 짓는 일을 재개할 수 있습니다. ", - [2] = "여기서는 굉장히 다양한 문제들을 마주치게 될 것입니다. ", - [3] = "당신이 충분히 훈련받은 직원들과 필요한 시설들을 갖춘다면, 이 천사 같은 사람들을 회복시켜줄 수 있습니다. ", - [4] = "당신의 병원 가치가 $200,000 이상이 되어야 하고, 은행에 $400,000 만큼의 돈이 있어야 합니다. ", - [5] = "이것 보다 적다면 이 레벨을 클리어 하는 것은 어림도 없습니다.", - }, - level10 = { - [1] = "이 동네에 창궐하는 질병들을 치료하는 것 뿐만 아니라, 보건부는 당신의 의약품의 효용성을 높일 것을 요구합니다. ", - [2] = "보건 검사관인 Ofsick 으로부터 불만이 접수되었기 때문에, 좋은 인상을 주기 위해서는 당신의 약들이 엄청나게 잘 듣도록 만들어야 합니다. ", - [3] = "또한, 당신의 병원이 비난 받지 않도록 하는 것도 잊지 마세요. 사망자 수를 낮게 유지하세요. ", - [4] = "힌트를 주자면, 젤리통을 지을 공간을 미리 확보해 두는 것이 좋을 겁니다. ", - [5] = "모든 약의 효율을 80% 이상으로 끌어 올리고, 650 의 평판과 $500,000 을 벌면 승리할 수 있습니다.", - }, - level11 = { - [1] = "당신은 궁극의 병원을 지을 기회를 얻었습니다. ", - [2] = "이 곳은 굉장히 이름난 지역이고, 보건부는 가능한 최고의 병원을 보고 싶어 합니다. ", - [3] = "우리는 당신이 큰 돈을 벌고, 엄청나게 높은 평판을 얻으며 모든 질병들을 치료할 있기를 기대합니다. ", - [4] = "이건 굉장히 중요한 일입니다. ", - [5] = "성공하기 위해서는 당신은 특별한 사람이 되어야 할 겁니다. ", - [6] = "또 주의할 것은, 이 지역에서 UFO 가 여러번 목격되었다는 것입니다. 당신의 직원들이 뜻밖의 방문에 대비할 수 있도록 해 주세요. ", - [7] = "당신의 병원은 $240,000 이상의 가치를 해야 하고, 은행에 $500,000 의 돈과 700 의 평판을 얻어야 할 겁니다.", - }, - level12 = { - [1] = "당신은 최고의 도전에 직면해 있습니다. ", - [2] = "지금까지의 당신의 성공에 크게 인상을 받은 보건부가 당신을 최고의 자리에 앉혀주었습니다. 그들은 당신이 또다른 궁극의 병원을 짓고, 막대한 돈을 벌며 놀라운 평판을 얻기를 원합니다. ", - [3] = "또한 당신이 매입할 수 있는 모든 부지를 사들이고, 모든 질병을 치료하며 (정말 '모든' 질병 말이에요), 모든 상을 수상하기를 원합니다. ", - [4] = "도전해 볼 준비가 되었나요?", - [5] = "$650,000 을 벌고, 750 명의 환자를 치료하며, 800 의 평판을 얻어 이 레벨을 클리어 하세요.", - }, - level13 = { - [1] = "병원 책임자로서의 놀라운 능력을 보고 '비밀 특수 관청'의 '비밀 특수 부서'에서 당신에게 관심을 가지기 시작했습니다. ", - [2] = "그들이 당신에게 주는 보너스가 있습니다. 쥐가 득실거리는 병원에서 쥐를 없애야 합니다. ", - [3] = "당신은 잡역부들이 더러운 것들을 치우기 전에 최대한 쥐들을 쏘아 맞춰야 합니다. ", - [4] = "준비 되셨나요?", - }, - level14 = { - [1] = "또다른 도전입니다 - 전혀 예상치 못한 놀라운 병원을 짓는 것이죠. ", - [2] = "이것을 성공한다면, 당신은 승자 중의 승자로 기억될 것입니다. ", - [3] = "쉬운 일이 될 것이라고 기대하지 마세요. 당신이 마주하게 될 가장 어려운 과제가 될 테니까요. ", - [4] = "행운을 빕니다!", - }, - level15 = { - [1] = "좋아요, 그게 바로 병원을 운영하는 기본적인 방법입니다.//", - [2] = "당신의 의료진은 특정 환자들을 진단하기 위해서 도움을 필요로 할 수 있습니다.", - [3] = "일반 진단실 등과 같은 진단 설비들을 더 많이 지어서 의료진이 정확한 진단을 할 수 있도록 도울 수 있습니다.", - }, - level16 = { - [1] = "환자들을 진단한 후에는, 치료 시설과 클리닉 등을 지어서 환자들을 치료해야 합니다. ", - [2] = "약국에서부터 시작하는 것이 좋습니다. 약국에서 제대로 약을 조제하기 위해서는 간호사도 필요할 것입니다.", - }, - level17 = { - [1] = "마지막 당부입니다 - 당신의 평판에서 눈을 떼지 마세요. 평판이 높아야 더 먼 곳의 환자들을 끌어올 수 있습니다. ", - [2] = "너무 많은 환자들을 죽게 하지 않고 적절히 행복도를 유지해 준다면 이 레벨을 클리어 하는 데 큰 문제는 없을 것입니다!//", - [3] = "이제 모든 것은 당신에게 달렸습니다. 행운을 빌어요.", - }, + demo = + "데모 병원에 오신 것을 환영합니다!//" .. + "안타깝게도 데모 버전에서는 (커스텀 레벨을 제외하면) 이 레벨만 플레이할 수 있습니다. 그렇지만, 여기에도 당신을 한동안 바쁘게 할만큼의 일거리는 충분히 있습니다! " .. + "당신은 치료를 위해 다른 종류의 시설을 필요로 하는 다양한 질병을 만나게 될 것입니다. 가끔은 응급 상황이 발생할지도 모릅니다. 그리고 당신은 연구실을 지어 새로운 시설들을 연구해야 할 것입니다. " .. + "당신의 목표는 $100,000 를 벌고, 병원 가치를 $70,000 만큼 올리며, 평판을 700 만큼 유지하고, 방문하는 환자의 75% 이상을 완치시키는 것입니다. " .. + "당신의 평판이 300 아래로 떨어지거나 40% 이상의 환자들을 죽게 하지 마세요. 어느 하나라도 발생하면 당신은 게임에서 지게 됩니다.//" .. + "행운을 바랍니다!", + level1 = + "당신의 첫 병원에 오신 것을 환영합니다!//" .. + "접수대와 진료실을 짓고 접수원과 의사를 고용해서 이 곳이 제대로 돌아가게끔 하세요. " .. + "그러고 나서 할일이 생길 때까지 어느 정도 기다리세요. " .. + "정신과를 짓고 정신과 자격이 있는 의사를 고용하는 것은 좋은 생각입니다. " .. + "약국을 짓고 간호사를 고용하는 것도 환자들을 치료하는 데 꼭 필요합니다. " .. + "부은 머리 증상을 호소하는 환자들을 주의하세요 - 팽창실을 지으면 이 문제를 해결할 수 있을 것입니다. " .. + "당신의 목표는 10 명의 환자를 치료하고 평판이 200 아래로 떨어지지 않도록 하는 것입니다.", + level2 = + "이 지역에는 더 다양한 병이 도사리고 있습니다. " .. + "더 많은 환자들을 치료할 수 있도록 병원을 구성하고, 연구 시설을 지을 계획을 세우세요. " .. + "당신의 시설들을 깨끗하게 유지하는 것을 잊지 말고, 평판을 최대한 높에 유지하도록 노력하세요. 당신은 늘어진 혀를 발견하게 될텐데, 늘어진 혀 클리닉을 지어서 치료할 수 있습니다. " .. + "또한, 심전도실을 지으면 새로운 질병들을 진단하는 데 도움이 될 것입니다. " .. + "이 두 가지 방을 짓기 위해서는 먼저 연구를 해야 합니다. 그리고 이제 당신은 병원을 확장하기 위한 새로운 토지를 구매할 수도 있습니다. 그러려면 마을 지도를 사용하세요. " .. + "300 의 평판과, $10,000 의 은행 잔고, 그리고 40 명의 환자를 치료하는 것을 목표로 하세요.", + level3 = + "이번에는 부유한 지역에 당신의 병원을 세우게 될 것입니다. " .. + "보건부는 이 곳에서 당신이 상당한 이익을 남기기를 바라고 있습니다. " .. + "처음에는 어느 정도 평판을 쌓아야 하겠지만, 병원이 안정적으로 돌아가기 시작하면, 최대한 돈을 많이 버는 것에 집중하세요. " .. + "또한 응급 상황이 발생할 가능성도 있습니다. " .. + "응급 상황에는 동일한 질병을 가진 많은 사람들이 한꺼번에 몰려오게 됩니다. " .. + "제한된 시간 내에 모두를 치료하게 되면 당신의 평판이 올라가며 큰 보너스를 받게 됩니다. " .. + "왕자병과 같은 질병이 발생할 수 있으며, 당신은 수술실을 짓고 또한 가까운 곳에 병동을 지을 예산을 마련해 두어야 할 것입니다. " .. + "성공하기 위해 $20,000 만큼을 버세요.", + level4 = + "모든 환자들을 행복하게 해주고, 그들을 가능한한 효율적으로 치료하며, 사망자의 수는 정말 최소한으로 유지하세요. " .. + "당신의 평판이 이 레벨의 성공을 좌우하므로, 평판을 최대한 높게 유지하도록 노력하세요. " .. + "돈에 대해서는 너무 신경쓰지 마세요. 돈은 평판이 높아지면 자연스럽게 따라오게 될 겁니다. " .. + "또한, 당신은 이제 의사들의 능력을 향상시키기 위해 그들을 교육시키는 것도 가능합니다. " .. + "교육받은 의사들은, 어떤 질병인지 아주 확실치 않은 환자들을 더 잘 치료할 수 있을 것입니다. " .. + "500 이상의 평판을 달성하세요.", + level5 = + "여기는 가지각색의 질병들을 치료하느라 아주 분주한 병원이 될 겁니다. " .. + "당신이 고용할 수 있는 의사들은 모두 의대를 갓 졸업한 신입들이기 때문에, 교육실을 지어서 적정 수준으로 훈련시키는 것이 필수입니다. " .. + "의사들을 교육할 수 있는 딱 세 명의 전문의들만 주어져 있으므로, 이들을 행복하게 해 주세요. " .. + "또 유념해야할 것은, 병원이 샌 안드로이드 단층 위에 지어져 있다는 것입니다. " .. + "다시말해, 이 병원은 언제나 지진의 위험에 노출되어 있습니다. " .. + "지진은 당신의 기계들을 손상시키고, 병원을 원만하게 운영하는 것을 방해할 것입니다. " .. + "성공하려면 평판을 400 만큼 올리고, $50,000 를 예금하세요. 또한, 200 명의 환자를 치료하세요.", + level6 = + "당신의 모든 지식을 동원해서, 적절한 이윤을 남기면서도 병약한 대중이 가진 온갖 질병들을 치료할 수 있도록 원만하게 운영되는 병원을 지으세요. " .. + "이 곳 주변의 공기는 특별히 세균과 질병을 옮기는 데 좋다는 것을 알아두세요. " .. + "병원을 정말 구석구석 깨끗하게 유지하지 않으면, 환자들 사이에서 아주 심각한 전염병이 도는 것을 보게 될 것입니다. " .. + "돈을 $150,000 만큼 벌고, 병원의 가치가 $140,000 이상이 되도록 하세요.", + level7 = + "이번에는 당신의 병원이 보건부의 철저한 감시 하에 놓여있게 될 것이므로, 당신이 돈을 충분히 많이 벌고 있다는 것을 은행 잔고로 보여주고, 평판을 올리도록 하세요. " .. + "환자들이 사망하는 것은 최대한 피해야 합니다 - 사업하는데 전혀 도움이 안되니까요. " .. + "최고의 직원들을 고용하도록 하고, 필요한 장비들을 갖추도록 하세요. " .. + "600 의 평판과 $200,000 의 잔고를 얻으세요.", + level8 = + "얼마나 비용대비 효율이 높은 병원을 짓는 것은 당신에게 달렸습니다. " .. + "이 주변 주민들은 상당히 부유한 편이니, 할 수 있는 만큼 쥐어 짜내세요. " .. + "사람들을 치료하는 것도 좋지만, 돈을 모으는 것이 목표라는 것을 기억해야 합니다. " .. + "이 아픈 사람들을 아주 빈털터리로 만들어 버리세요. " .. + "이 레벨을 완료하려면 재산을 $300,000 만큼 쌓아야 합니다.", + level9 = + "보건부의 재산을 좀 불려주고 장관님께 리무진도 한 대 뽑아드렸으니, 이제 다시 몸이 아픈 사람들을 잘 돌보는 훌륭한 병원을 짓는 일을 재개할 수 있습니다. " .. + "여기서는 굉장히 다양한 문제들을 마주치게 될 것입니다. " .. + "당신이 충분히 훈련받은 직원들과 필요한 시설들을 갖춘다면, 이 천사 같은 사람들을 회복시켜줄 수 있습니다. " .. + "당신의 병원 가치가 $200,000 이상이 되어야 하고, 은행에 $400,000 만큼의 돈이 있어야 합니다. " .. + "이것 보다 적다면 이 레벨을 클리어 하는 것은 어림도 없습니다.", + level10 = + "이 동네에 창궐하는 질병들을 치료하는 것 뿐만 아니라, 보건부는 당신의 의약품의 효용성을 높일 것을 요구합니다. " .. + "보건 검사관인 Ofsick 으로부터 불만이 접수되었기 때문에, 좋은 인상을 주기 위해서는 당신의 약들이 엄청나게 잘 듣도록 만들어야 합니다. " .. + "또한, 당신의 병원이 비난 받지 않도록 하는 것도 잊지 마세요. 사망자 수를 낮게 유지하세요. " .. + "힌트를 주자면, 젤리통을 지을 공간을 미리 확보해 두는 것이 좋을 겁니다. " .. + "모든 약의 효율을 80% 이상으로 끌어 올리고, 650 의 평판과 $500,000 을 벌면 승리할 수 있습니다.", + level11 = + "당신은 궁극의 병원을 지을 기회를 얻었습니다. " .. + "이 곳은 굉장히 이름난 지역이고, 보건부는 가능한 최고의 병원을 보고 싶어 합니다. " .. + "우리는 당신이 큰 돈을 벌고, 엄청나게 높은 평판을 얻으며 모든 질병들을 치료할 있기를 기대합니다. " .. + "이건 굉장히 중요한 일입니다. " .. + "성공하기 위해서는 당신은 특별한 사람이 되어야 할 겁니다. " .. + "또 주의할 것은, 이 지역에서 UFO 가 여러번 목격되었다는 것입니다. 당신의 직원들이 뜻밖의 방문에 대비할 수 있도록 해 주세요. " .. + "당신의 병원은 $240,000 이상의 가치를 해야 하고, 은행에 $500,000 의 돈과 700 의 평판을 얻어야 할 겁니다.", + level12 = + "당신은 최고의 도전에 직면해 있습니다. " .. + "지금까지의 당신의 성공에 크게 인상을 받은 보건부가 당신을 최고의 자리에 앉혀주었습니다. 그들은 당신이 또다른 궁극의 병원을 짓고, 막대한 돈을 벌며 놀라운 평판을 얻기를 원합니다. " .. + "또한 당신이 매입할 수 있는 모든 부지를 사들이고, 모든 질병을 치료하며 (정말 '모든' 질병 말이에요), 모든 상을 수상하기를 원합니다. " .. + "도전해 볼 준비가 되었나요?" .. + "$650,000 을 벌고, 750 명의 환자를 치료하며, 800 의 평판을 얻어 이 레벨을 클리어 하세요.", + level13 = + "병원 책임자로서의 놀라운 능력을 보고 '비밀 특수 관청'의 '비밀 특수 부서'에서 당신에게 관심을 가지기 시작했습니다. " .. + "그들이 당신에게 주는 보너스가 있습니다. 쥐가 득실거리는 병원에서 쥐를 없애야 합니다. " .. + "당신은 잡역부들이 더러운 것들을 치우기 전에 최대한 쥐들을 쏘아 맞춰야 합니다. " .. + "준비 되셨나요?", + level14 = + "또다른 도전입니다 - 전혀 예상치 못한 놀라운 병원을 짓는 것이죠. " .. + "이것을 성공한다면, 당신은 승자 중의 승자로 기억될 것입니다. " .. + "쉬운 일이 될 것이라고 기대하지 마세요. 당신이 마주하게 될 가장 어려운 과제가 될 테니까요. " .. + "행운을 빕니다!", + level15 = + "좋아요, 그게 바로 병원을 운영하는 기본적인 방법입니다.//" .. + "당신의 의료진은 특정 환자들을 진단하기 위해서 도움을 필요로 할 수 있습니다." .. + "일반 진단실 등과 같은 진단 설비들을 더 많이 지어서 의료진이 정확한 진단을 할 수 있도록 도울 수 있습니다.", + level16 = + "환자들을 진단한 후에는, 치료 시설과 클리닉 등을 지어서 환자들을 치료해야 합니다. " .. + "약국에서부터 시작하는 것이 좋습니다. 약국에서 제대로 약을 조제하기 위해서는 간호사도 필요할 것입니다.", + level17 = + "마지막 당부입니다 - 당신의 평판에서 눈을 떼지 마세요. 평판이 높아야 더 먼 곳의 환자들을 끌어올 수 있습니다. " .. + "너무 많은 환자들을 죽게 하지 않고 적절히 행복도를 유지해 준다면 이 레벨을 클리어 하는 데 큰 문제는 없을 것입니다!//" .. + "이제 모든 것은 당신에게 달렸습니다. 행운을 빌어요.", } transactions = { severance = "퇴직금", diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/norwegian.lua corsix-th-0.62/CorsixTH/Lua/languages/norwegian.lua --- corsix-th-0.30/CorsixTH/Lua/languages/norwegian.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/norwegian.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010 Erlend Mongstad, Ola Skogrand +--[[ Copyright (c) 2017 Erlend Mongstad, Ola Skogrand Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -56,6 +56,7 @@ -----------------------------------------------------------------------------]] +-- TODO GENERAL: Skal det benevnes "spill", "brett", "nivå" eller noe annet? ------------------------------------------------------------------------------- -- SECTION A - NEW STRINGS @@ -93,6 +94,7 @@ -- 3. Objects object = { litter = "Söppel", + rathole = "Rottehull", } tooltip.fax.close = "Lukk dette vinduet uten å slette meldingen" @@ -103,7 +105,6 @@ menu_options = { lock_windows = " LÅS VINDUER ", edge_scrolling = " KANTSCROLLING ", - settings = " INNSTILLINGER ", adviser_disabled = " RÅDGIVER ", warmth_colors = " VARMEFARGER", --Todo: Open for suggestions for a better word for it (warmth colours). } @@ -161,7 +162,12 @@ dynamic_info.staff.actions.fired = "Sparket" -- 7. Tooltip -tooltip.objects.litter = "Söppel: Slengt på gulvet av en pasient, fordi vedkommende ikke fant en söppelbötte å kaste det i." +tooltip = { + objects = { + litter = "Söppel: Slengt på gulvet av en pasient, fordi vedkommende ikke fant en söppelbötte å kaste det i.", + rathole = "Hjemmet til en rottefamilie som syns sykehuset ditt er mökkete nok til å bo i.", + }, +} -- Misc misc.not_yet_implemented = "(ikke implementert enda)" @@ -174,16 +180,19 @@ load_game = "Last inn", options = "Innstillinger", version = "Versjon: ", + continue = "Fortsett siste spill", savegame_version = "Lagringsversjon: ", --todo: en bedre oversettelse eller omskriving? + custom_campaign = "Brukerskapt karriere", -- todo: en bedre oversettelse eller omskriving? + map_edit = "Brettkonstruksjon", exit = "Avslutt", } tooltip.main_menu = { new_game = "Start et nytt spill fra begynnelsen", - custom_level = "Bygg sykehuset ditt på et valgfritt område", + custom_level = "Bygg sykehuset ditt på et valgfritt område", -- todo: forbedre tekst? load_game = "Last inn et tidligere spill", options = "Endre diverse innstillinger", - exit = "Nei, nei, vær så snill å ikke stikk!", + exit = "Nei, nei, vær så snill å ikke avslutt!", } load_game_window = { @@ -199,11 +208,12 @@ custom_game_window = { caption = "Brukerdefinert spill", free_build = "Bygg fritt", + load_selected_level = "Start", } - tooltip.custom_game_window = { - start_game_with_name = "Last nivå %s", - free_build = "Huk av denne boksen om du vil spille uten penger og uten bestemte forutsetninger for vinne eller tape", --todo: finne en bedre oversettelse eller omskrive + free_build = "Huk av denne boksen om du vil spille uten penger og uten bestemte forutsetninger for å vinne eller tape", --todo: finne en bedre oversettelse eller omskrive + load_selected_level = "Last og spill valgt brett", + choose_game = "Klikk på et brett for å lese mer om det", } save_game_window = { caption = "Lagre spill", @@ -229,17 +239,13 @@ height = "Höyde", change_resolution = "Endre opplösning", back = "Tilbake", - browse = "Bla gjennom...", cancel = "Avbryt", - new_th_directory = "Her kan du spesifisere en annen installasjonsmappe for Theme Hospital. Så fort du velger en ny mappe vil spillet starte på nytt.", --kalle det "corsixth" isteden for "theme hospital"? custom_resolution = "Egendefinert...", option_on = "På", option_off = "Av", caption = "Innstillinger", language = "Språk", apply = "Bruk", - data_location = "Data-beliggenhet", - font_location = "Font-beliggenhet", resolution = "Opplösning", folder = "Mapper", audio = "Global lyd", @@ -252,16 +258,10 @@ change_resolution = "Endre opplösningen til dimensjonene du har angitt til venstre.", language = "Velg %s som språk", back = "Lukk vinduet med innstillinger", - original_path = "Valgt mappe for Theme Hospital installasjonen", - browse = "Bla gjennom mappene for å finne et annet sted for Theme Hospital-installasjonen. %1%", fullscreen = "Om spillet skal kjöre i fullskjerm eller vindusmodus", cancel = "Returner uten å endre opplösning", - font_location = "Beliggenhet av en font-fil som klarer å vise Unicode-bokstaver som brukes i det valgte språket. Om dette ikke er spesifisert, så vil ikke ha mulighet til å velge språk som krever andre bokstaver enn i originalspillet. For eksempel: Russisk eller Kinesisk", apply = "Bruk den innskrevne opplösningen", - browse_font = "Se etter en annen font-fil (nåværende beliggenhet: %1%)", - data_location = "Beliggenheten av den originale Theme Hospital installasjonen, som trengs for å kjöre CorsixTH", language_dropdown_item = "Velg %s som språk", - no_font_specified = "Ingen beliggenhet spesifisert!", select_language = "Velg språk", select_resolution = "Velg en ny opplösning", resolution = "Opplösningen spillet skal kjöres i.", @@ -348,6 +348,8 @@ }, cheats = { + decrease_prices = "Senk prisene", + increase_prices = "Hev prisene", end_month = "Slutten av måneden", emergency = "Lag nödstilfelle", win_level = "Vinn nivå", @@ -358,12 +360,16 @@ all_research = "All forskning", end_year = "Slutten av året", earthquake = "Lag jordskjelv", + epidemic = "Lag smittsom pasient", + toggle_infected = "Slå av/på smitte-ikoner", }, } tooltip.cheats_window = { close = "Lukk juksekodevinduet", cheats = { + decrease_prices = "Senk alle priser med 50 % (min. 50 %)", + increase_prices = "Hev alle priser med 50 % (maks. 200 %)", end_month = "Gå til slutten av denne måneden.", emergency = "Lag en nödssituasjon.", win_level = "Vinn dette nivået.", @@ -374,6 +380,8 @@ all_research = "Fullförer all forskning.", end_year = "Gå til slutten av dette året.", earthquake = "Forårsaker et jordskjelv.", + epidemic = "Lager en smittsom pasient som kan forårsake en epidemi", + toggle_infected = "Slå av eller på ikoner for smittsomme pasienter for den aktive, oppdagede epidemien", }, } @@ -406,20 +414,13 @@ } tooltip.customise_window = { --todo kanskje en opprensking her. få det mer konsekvent. -intro_button = "Klikk for å slå av eller på", movies = "Slår av alle videoer i spillet", -aliens = "På grunn av manglende standardanimasjoner ble pasienter med utenomjordisk DNA satt til å kun komme gjennom nödstilfeller. For å la pasienter med denne sykdommen komme til sykehuset på vanlig måte, så må du slå denne av.", -volume_button = "Klikk for å endre hurtigtast. Benyttes hvis volumsenkings-knappen på tastaturet åpner en meny i spillet.", paused = " I Theme Hospital ville spilleren kun få lov til å bruke toppmenyen om spillet var satt til pause. Dette er standard i CorsixTH også, men ved å slå denne på, så er alle bevegelser lov", -average_contents_button = "Lar deg få de mest brukte gjenstandene (gjennomsnittlig) inn i rombyggeren automatisk.", back = "Gå tilbake", -movies_button = "Slå av eller på filmsnutter i spillet", -paused_button = "Tillat bevegelser når spillet er satt til pause", intro = "Slå av eller på introfilmen. Den andre filminnstillingen må også være på for å spille av introfilmen hver ganger du starter spillet", volume = "Om en fysisk volum ned-knapp åpner Medisinboka i spillet, så kan du slå på denne for å endre hurtigtasten til Shift+C", -fractured_bones_button = "Slå denne innstillingen på eller av", -fractured_bones = "På grunn av mangelfulle animasjoner har vi gjort stilt standardoppsettet til å slå av kvinnelige benbrudd. For å tillate dette, slå denne av", -aliens_button = "Slå denne innstillingen på eller av", +fractured_bones = "På grunn av mangelfulle animasjoner har vi stilt standardoppsettet til å slå av kvinnelige benbrudd. For å tillate dette, slå denne av", +aliens = "På grunn av manglende animasjoner har vi slått av pasienter med Utenomjordisk DNA slik at de bare kan komme fra nödstilfeller. For å tillate pasienter med Utenomjordisk DNA å gå til sykehuset, slå denne av.", average_contents = "Om du önsker at spillet skal huske hvilke objekter du vanligvis kjöper til hver rom (gjennomsnittlig), så bör du slå på denne", } @@ -452,10 +453,12 @@ load_quick_save = "Spillet kunne ikke laste inn sist hurtiglagring, siden den ikke eksisterer. Vi har ikke tenkt til å lage en for deg!", map_file_missing = "Kunne ikke finne kartfilen %s for dette nivået!", minimum_screen_size = "Vennligst sett opplösningen til minst 640x480.", - maximum_screen_size = "Vennligst velg en skjermopplösning ikke större enn 3000x2000.", unavailable_screen_size = "Skjermopplösningen du valgte er ikke tilgjengelig i fullskjermmodus.", alien_dna = "Merk: Det er ingen originale animasjoner for utenomjordiske pasienter som sitter, åpner eller banker på dörer osv. Utenomjordiske vil bare komme på besök om det er slått på i levelfila", --todo: bedre beskrivelse? levelfila? var "NOTE: There are no animations for Alien patients for sitting down, opening or knocking on doors etc. So, like with Theme Hospital to do these things they will appear to change to normal looking and then change back. Patients with Alien DNA will only appear if they are set to in the level file" fractured_bones = "Merk: De originale animasjonene for kvinnelige personer med benbrudd er ikke perfekte", + no_games_to_contine = "Det fins ingen lagrede spill", + could_not_load_campaign = "Lasting av brettet feilet: %s", -- todo: skal det kalles "brett" her? + could_not_find_first_campaign_level = "Kunne ikke finne det förste brettet i denne karrieren: %s", -- todo: skal det hete karrieren her? } confirmation = { @@ -513,6 +516,56 @@ next = "Vis neste tips", } +-- Mapmaker? +save_map_window = { -- Usikker på om denne hörer til her, eller om den skal flyttes? +caption = "Lagre brett (%1%)", +new_map = "Nytt brett", +} +tooltip.save_map_window = { + map = "Overskriv brett %s", -- Overskriv/lagre? + new_map = "Skriv inn navn for nytt brett", +} + +-- Custom campaign +custom_campaign_window = { + caption = "Brukerskapte karrierer", -- todo: Forbedre? Sjekke om det passer når spillet har implementer dette. + start_selected_campaign = "Start karriere", +} + +map_editor_window = { -- Sjekkes når de er implementert. Mulig hjelpeteksten må korrigeres! + pages = { + pond = "Dam", + hedgerow = "Hekk", + inside = "Innside", -- Riktig? Innvendig? + outside = "Utside", + road = "Vei", + delete_wall = "Slett vegger", + parcel_9 = "Tomt 9", + camera_1 = "Kamera 1", + camera_2 = "Kamera 2", + camera_3 = "Kamera 3", + camera_4 = "Kamera 4", + foliage = "Beplantning", + west_wall = "Vestvegg", + north_wall = "Nordvegg", + helipad = "Helikopterplass", + parcel_0 = "Tomt 0", + parcel_1 = "Tomt 1", + parcel_2 = "Tomt 2", + parcel_3 = "Tomt 3", + parcel_4 = "Tomt 4", + parcel_5 = "Tomt 5", + parcel_6 = "Tomt 6", -- Riktig å bruke "tomt"? + parcel_7 = "Tomt 7", + parcel_8 = "Tomt 8", + paste = "Innlimingsområde", + heliport_1 = "Helikopterplass 1", + heliport_2 = "Helikopterplass 2", + heliport_3 = "Helikopterplass 3", + heliport_4 = "Helikopterplass 4", + }, +} + ------------------------------------------------------------------------------- -- SECTION B - OLD STRINGS (OVERRIDE) @@ -1135,6 +1188,7 @@ options = " INNSTILLINGER ", display = " VIS ", charts = " OVERSIKTER ", + player_count = "SPILLERANTALL", -- In map editor debug = " DEBUG ", } @@ -1145,6 +1199,12 @@ restart = " START PÅ NYTT ", quit = " AVSLUTT ", } +menu_player_count = { -- In map editor + players_1 = " 1 SPILLER ", + players_2 = " 2 SPILLERE ", + players_3 = " 3 SPILLERE ", + players_4 = " 4 SPILLERE ", +} menu_file_load = { [1] = " SPILL 1 ", [2] = " SPILL 2 ", @@ -1250,14 +1310,16 @@ plant_pagers = " PLANT PAGERS ", porter_pagers = " PORTER PAGERS ", pixbuf_cells = " PIXBUE CELLS ", - enter_nav_debug = " ENTER NAV DEBUG ", - show_nav_cells = " SHOW NAV CELLS ", + enter_nav_debug = " SKRIV INN NAV DEBUG ", + show_nav_cells = " VIS NAV CELLS ", machine_pagers = " MASKIN PAGERS ", display_room_status = " VIS ROMSTATUS ", display_big_cells = " VIS STORE CELLER ", show_help_hotspot = " VIS HJELP HOTSPOTS ", - win_game_anim = " WIN GAME ANIM ", - win_level_anim = " WIN LEVEL ANIM ", + win_game_anim = " VINN SPILL ANIM ", + win_level_anim = " VINN BANE ANIM ", + debug_script = " (SHIFT + D) KJÖR DEBUG SCRIPT ", + connect_debugger = " (CTRL + C) KOBLE TIL LUA DEBUG SERVER ", lose_game_anim = { [1] = " TAPT SPILL 1 ANIM ", [2] = " TAPT SPILL 2 ANIM ", @@ -1685,9 +1747,11 @@ -- Main menu main_menu = { new_game = "Start en ny karriere", + custom_campaign = "Start en ny karriere skapt av andre spillere", load_game = "Last inn et tidligere spill", continue = "Fortsett forrige spill", network = "Start nettverksspill", + map_edit = "Lag et eget brett", quit = "Du er på vei til å avslutte spillet. Er du sikker på at du vil dette?", --todo: Her tror jeg det er valgt feil navn/sted for "quit". Denne viser til spörsmålet man får ved å trykke på Avslutt i hovedmenyen. load_menu = { load_slot = " SPILL [slotnumber] ", -- NB: no %d! Append " [slotnumber]". @@ -1699,6 +1763,12 @@ cancel = "Avbryt", confirm = "Bekreft", }, + -- Custom campaign + custom_campaign_window = { + choose_campaign = "Velg en karriere for å lese mer om den", + start_selected_campaign = "Last det förste brettet i denne karrieren", + }, + -- Patient window patient_window = { close = "Lukk vindu", @@ -2065,14 +2135,8 @@ -- Cheats cheats = { th_cheat = "Gratulerer du har låst opp juksekodene!", - hairyitis_cheat = "Pelssyndom-kode aktivert!", - hairyitis_off_cheat = "Pelssyndom-kode deaktivert.", roujin_on_cheat = "Roujins utfordring aktivert! Lykke til...", roujin_off_cheat = "Roujins utfordring deaktivert.", - crazy_on_cheat = "Å nei! Alle Legene har blitt gale!", - crazy_off_cheat = "Puh... Legene har fått tilbake forstanden.", - bloaty_cheat = "Ballonghode-kode aktivert!", - bloaty_off_cheat = "Ballonghode-kode deaktivert.", }, -- Epidemic @@ -2212,8 +2276,12 @@ -- Warnings warnings = { - charges_too_low = "Du tar deg for lite betalt. Dette vil tiltrekke mange syke mennesker til sykehuset ditt, men du tjener mindre pr. pasient.", - charges_too_high = "Dine priser er for höye. Dette gir deg god profitt på kort sikt, men på lengre sikt vil de höye prisene skremme bort pasientene.", + low_prices = "Du tar deg for lite betalt for %s. Dette vil tiltrekke mange syke mennesker til sykehuset ditt, men du tjener mindre på hver pasient.", + fair_prices = "Prisene dine for %s virker rettferdige og balanserte.", + high_prices = "Prisene for %s er for høye. Dette gir deg god avkastning på kort sikt, men på lengre sikt vil de höye prisene skremme bort pasientene.", + patient_not_paying = "En pasient har dratt uten å betale for %s fordi det var for dyrt!", + charges_too_low = "Du tar deg for lite betalt. Dette vil tiltrekke mange syke mennesker til sykehuset ditt, men du tjener mindre på hver pasient", + charges_too_high = "Dine priser er for höye. Dette gir deg god avkastning på kort sikt, men på lengre sikt vil de höye prisene skremme bort pasientene.", plants_thirsty = "Du må huske på plantene dine. De er törste.", staff_overworked = "Personalet ditt er meget overarbeidet. De blir ineffektive og gjör fatale feil når de er trötte.", queue_too_long_at_reception = "Du har for mange pasienter som venter ved Resepsjonen. Plasser ut flere Resepsjoner og ansett en Resepsjonist til.", @@ -2389,6 +2457,11 @@ }, } +-- Warnings (more warnings in adviser.warnings) +warnings = { + levelfile_variable_is_deprecated = "Merk: Brett '%s' inneholder en forringet variabeldefinisjon i brettfilen.'%LevelFile' har fått endret navn til '%MapFile'. Vennligst gi beskjed til brett-designeren om å oppdatere brettet", -- Forbedre tekst? +} + -- Confirmation confirmation = { quit = "Du har valgt å avslutte. Er du sikker på at du vil forlate spillet?", @@ -2399,7 +2472,7 @@ sack_staff = "Er du sikker på at du vil si opp denne personen?", restart_level = "Er du sikker på at du vil starte dette nivået på nytt?", maximum_screen_size = "Opplösningen du har valgt er större enn 3000 x 2000. Större opplösninger er mulig, men det krever bedre maskinvare om det ikke skal hakke. Önsker du å fortsette?", - music_warning = "För du får brukt mp3-er som spillmusikk, så må du ha smpeg.dll eller tilsvarende for operativsystemet ditt. Eller vil du ikke få musikk i spillet. Forelöpig fins det ikke noe tilsvarende for 64-bit systemer. Önsker du å fortsette?", + music_warning = "För du får brukt mp3-er som spillmusikk, så må du ha smpeg.dll eller tilsvarende for operativsystemet ditt. Eller vil du ikke få musikk i spillet. Önsker du å fortsette?", } @@ -2451,7 +2524,12 @@ -- Letters -- TODO letter = { + campaign_level_completed = "Bra jobbet! Du klarte brettet, men det er ike over enda! Kunne du tenkt den en stilling hos %s Sykehus?", + campaign_completed = "Utrolig! Du har fullført alle brettene. Nå kan du slappe av og skryte på utallige nettforum om dine bragder!", + campaign_level_missing = "Beklaer, men det neste brette i denne karrieren ser ut til å mangle (Navn: %s).", + --original line-ends: 5 4 2 3 + [1] = { [1] = "Kjære %s//", [2] = "Fantastisk! Dette sykehuset har du driftet helt utmerket. Vi i departementet vil vite om du er interessert i å gå lös på et större prosjekt. Vi har en jobbstilling vi tror du ville passet perfekt i. Vi kan friste deg med en lönn på $%d. Tenk litt på det.//", @@ -3036,6 +3114,7 @@ prices_too_high = "Prisene er for höye - Jeg går hjem", epidemic_sent_home = "Sendt hjem av inspektör", epidemic_contagious = "Jeg er smittsom", + epidemic_vaccinated = "Jeg er ikke smittsom lenger", }, diagnosed = "Diagnose: %s", -- %s guessed_diagnosis = "Gjettet diagnose: %s", -- %s @@ -3066,139 +3145,137 @@ introduction_texts = { - level17 = { - [1] = "Siste advarsel - hold öye med omdömmet ditt - det er dette som tiltrekker pasienter til sykehuset ditt. ", - [2] = "Om du ikke dreper for mange mennesker og samtidig holder pasientene noenlunde i godt humör, skal du ikke ha for store problemer med dette nivået!//", - [3] = "Nå må du klare deg selv. Lykke til med det.", - }, - level1 = { - [1] = "Velkommen til ditt förste sykehus!//", - [2] = "Få stedet opp og gå ved å plassere en Resepsjon, bygge en Allmennpraksis, og ansette en Resepsjonist og en Lege. ", - [3] = "Vent så til det begynner å skje ting.", - [4] = "Det er smart å bygge Psykiatri og ansette en Lege med fordypning innenfor psykiatri. ", - [5] = "Et Apotek og en Sykepleier er essensielt for å kurere pasientene dine. ", - [6] = "Se opp for mange tilfeller av Ballonghode - et Pumperom vil fort kunne være til stor hjelp. ", - [7] = "Du må kurere 10 pasienter og sörge for at omdömmet ditt ikke blir mindre enn 200. ", - }, - level9 = { - [1] = "Etter å ha fylt opp Ministerens bankkonto og finansiert Ministerens nye limousin, kan du nå konsentrere deg om å lage et omsorgsfullt og velfungerende sykehus for de trengende. ", - [2] = "Du må forvente å stöte på en rekke problemer her.", - [3] = "Om du har nok av rom og flinke ansatte, skal du kunne ha dette under kontroll. ", - [4] = "Sykehuset ditt må ha en verdi på $200,000, og du må ha $400,000 i banken. ", - [5] = "Med noe mindre får du ikke fullfört dette nivået.", - }, - level2 = { - [1] = "Det er et större spekter av plager i dette området. ", - [2] = "Bygg sykehuset for å behandle flere pasienter, og planlegg en egen Forskningsavdeling. ", - [3] = "Husk å holde institusjonen ren, og streb etter så höyt omdömme som mulig - du vil måtte håndtere plager som Lös tunge, så du trenger en Tungeklinikk. ", - [4] = "Du kan også bygge Kardiorom for å forbedre diagnostisering. ", - [5] = "Begge disse rommene vil måtte forskes på för du kan bygge de. Du kan også utvide sykehustomten slik at du får mer plass å boltre deg på - Bruk Områdekartet til dette. ", - [6] = "Streb etter et omdömme på 300 og en banksaldo på $10,000, samt 40 kurerte pasienter. ", - }, - level7 = { - [1] = "Her vil du være under nöye gransking fra Helsedepartementet, så sörg for at kontoene dine viser at du tjener en masse penger, og at omdömmet ditt er svært bra. ", - [2] = "Vi har ikke råd til unödvendige dödsfall - det er dårlig for forretningene. ", - [3] = "Sörg for at personalet er i tipp-topp form, og at du har alt utstyret du trenger. ", - [4] = "Få et omdömme på 600, pluss $200,000 i banken.", - }, - level5 = { - [1] = "Dette blir et travelt sykehus, siden du må håndtere et bredt spekter av tilfeller. ", - [2] = "Legene du kan ansette kommer rett fra skolen, så det kommer til å være avgjörende for deg å bygge et Klasserom og skolere dem til et akseptabelt nivå. ", - [3] = "Du har kun tre Konsulenter til å lære opp de uerfarne medarbeiderne, så hold dem lykkelige slik at de ikke slutter. ", - [4] = "Merk deg også at sykehusets fundament står på en grunn full av geologiske feil. ", - [5] = "Faren for jordskjelv er alltid tilstedeværende. ", - [6] = "De vil forårsake betydelig skade på maskiner, og forstyrre den jevne driften av sykehuset. ", - [7] = "Få omdömmet ditt opp til 400, og ha $50,000 i banken for å lykkes. Du må også kurere 200 pasienter.", - }, - level4 = { - [1] = "Hold alle pasientene dine fornöyde, ta deg av dem så effektivt som mulig og hold dödsfall til et absolutt minimum. ", - [2] = "Ditt omdömme står på spill, så sörg for at du får det så höyt som mulig. ", - [3] = "Ikke bekymre deg for mye over penger - det vil komme etter som ditt vitale omdömme vokser. ", - [4] = "Du vil kunne skolere Leger til å utvide sine evner. ", - [5] = "Du kan komme til få pasienter som synes å være mer gjennomsiktig enn de fleste. ", --sjekk english.lua er det bra nok oversettelse? - [6] = "Oppnå et omdömme på over 500.", - }, - level14 = { - [1] = "Det er nok en utfordring - det helt uventede overraskelsessykehuset. ", - [2] = "Om du klarer å gjöre en suksess ut av dette, vil du bli vinneren over alle andre vinnere. ", - [3] = "Ikke forvent at det skal være fort gjort, ettersom det er det töffeste oppdraget du noensinne vil få. ", - [4] = "Lykke til!", - }, - level15 = { - [1] = "Ok, det var den grunnleggende teknikken i å sette et sykehus sammen.//", - [2] = "Legene dine kommer til å trenge all den hjelpen de kan få til å diagnostisere noen av disse pasientene. Du kan hjelpe dem ved å ", - [3] = "bygg et ny diagnoserom, for eksempel Generell Diagnose.", - }, - level8 = { - [1] = "Det er opp til deg å sette opp det mest effektive og kostnadseffektive sykehuset som mulig. ", - [2] = "Menneskene rundt her er ganske velstående, så flå dem for så mye grunker du bare klarer. ", - [3] = "Husk at det å kurere mennesker er veldig fint, men du trenger virkelig pengene det bringer. ", - [4] = "Behandle disse syke personene med Pengeutsugeren. ", - [5] = "Samle opp en pengehaug på $300,000 for å fullföre dette nivået.", - }, - level13 = { - [1] = "Din enestående dyktighet som sykehusadministrator har blitt oppdaget av Hemmelig Super-avdeling fra Superhemmelige Tjenester. ", - [2] = "De har en spesiell bonus for deg; det er et rotteinfisert sykehus som trenger en effektiv Terminator. ", - [3] = "Du må skyte så mange rotter som mulig för Vaktmesterne rydder opp all söpla. ", - [4] = "Tror du at du klarer oppgaven?", - }, - level16 = { - [1] = "Når du har diagnostisert noen av pasientene må du bygge behandlingsrom og klinikker for å kurere dem - en god idé å begynne ", - [2] = "med Apoteket. Du trenger også en Sykepleier for å utlevere ulike legemidler fra Apoteket.", - }, - level6 = { - [1] = "Bruk all din kunnskap til å sette opp et velsmurt og kompetent sykehus som gjör et sunt overskudd og kan håndtere alt som den sykelige offentligheten kan kaste på det. ", --todo - godt nok oversatt? - [2] = "Du bör være klar over at atmosfæren rundt her er kjent for å bære med seg bakterier og infeksjoner. ", - [3] = "Med mindre du klarer å holde institusjonen din omhyggelig ren, kan du stå overfor en rekke epidemier blant pasientene. ", - [4] = "Pass på at du skaffer deg $150,000, og at sykehuset er verdt over $140,000.", - }, - level12 = { - [1] = "Du har fått moderen av alle utfordringer nå. ", - [2] = "Departementet er imponert over din suksess, og har skaffet toppjobben for deg; de vil at du skal bygge enda et storslagent sykehus, skaffe en stor haug med penger og få et bra utrolig rykte. ", - [3] = "Det forventes at du kjöper opp alle områdene du klarer, kurerer alle sykdommer (og da mener vi alle) og vinner alle premiene. ", - [4] = "Tror du at du klarer det?", - [5] = "Tjen $650,000, kurer 750 pasienter og få et omdömme på 800 for å vinne dette nivået.", - }, - level3 = { - [1] = "Du setter opp et sykehus i et velstående område denne gangen. ", - [2] = "Helsedepartementet er ute etter at du klarer å sikre en sunn profitt her. ", - [3] = "Du må få et godt rykte til å begynne med, men når sykehuset går av seg selv, så konsentrer deg om å tjene så mye penger du klarer. ", - [4] = "Det er også en sjanse for at nödssituasjoner oppstår. ", - [5] = "Dette er når store mengder mennesker kommer på en gang med samme tilstand. ", - [6] = "Kurerer du alle innen tidsfristen så får du et bedre rykte, og en stor xbonus. ", - [7] = "Sykdommer som Rock'n'Roll-syndrom kan inntreffe og du bör budsjettere for en Operasjonssal med en Sykestue i nærheten. ", - [8] = "Tjen opp $20,000 for å klare nivået.", - }, - level10 = { - [1] = "I tillegg til å få bukt med alle sykdommene som dukker opp i denne skogkanten, så vil Departementet at du bruker litt tid på å konsentrere deg om effektiviteten av legemidlene dine. ", - [2] = "Det har kommet noen klager fra Ofsick, Helsedepartementets vakthund, så for at alt skal se bra ut du må sörge for at alle legemidler er svært effektive. ", --todo (bytte ut "Ofsick" med et norskt navn). - [3] = "Kontroller også at sykehuset i tillegg er uklanderlig. Hold dödsfallene nede. ", - [4] = "Som et hint, så kanskje du bör holde av litt plass til en Gelétönne. ", - [5] = "Utvikle alle dine medisiner til minst 80 prosent effektivitet, få et omdömme på 650 og gjem unna $500,000 i banken for å vinne. ", - }, - level11 = { - [1] = "Du har fått muligheten til å bygge det ultimate innen sykehus. ", - [2] = "Dette er et meget prestisjefylt område, og Departementet önsker å se det best mulige sykehuset. ", - [3] = "Vi vil forvente at du gjör store penger, har et ypperlig og godt omdömme og dekker alle mulige hendelser. ", - [4] = "Dette er en viktig jobb. ", - [5] = "Du må være virkelig begavet for å gjennomföre det. ", - [6] = "Merk også at det har vært observasjoner av UFO-er i området. Sörg for at personalet er forberedt på noen uventede gjester. ", - [7] = "Sykehuset ditt må være verdt $240,000, du må ha $500,000 i banken og ditt omdömme må være på minst 700.", - }, - level18 = { - }, - demo = { - [1] = "Velkommen til demonstrasjonssykehuset!", - [2] = "Uheldigvis inneholder demoversjonen kun dette nivået. Uansett så er det mer enn nok å gjöre her for å holde deg opptatt en stund!", - [3] = "Du vil möte på forskjellige sykdommer som krever forskjellige rom for å kureres. Fra tid til annen kan nödstilfeller oppstå. Du må også forske frem nye rom ved hjelp av en forskningsavdeling.", - [4] = "Målet ditt er å tjene $100,000, ha et sykehus som er verdt $70,000 og et omdömme på 700, samt kurert minst 75% av pasientene.", - [5] = "Pass på at omdömmet ditt ikke faller under 300 og at du ikke dreper mer enn 40% av pasientene, for ellers vil du tape nivået.", - [6] = "Lykke til!", - }, + demo = + "Velkommen til demonstrasjonssykehuset!//" .. + "Uheldigvis inneholder demoversjonen kun dette nivået. Uansett så er det mer enn nok å gjöre her for å holde deg opptatt en stund! " .. + "Du vil möte på forskjellige sykdommer som krever forskjellige rom for å kureres. Fra tid til annen kan nödstilfeller oppstå. Du må også forske frem nye rom ved hjelp av en forskningsavdeling. " .. + "Målet ditt er å tjene $100,000, ha et sykehus som er verdt $70,000 og et omdömme på 700, samt kurert minst 75% av pasientene. " .. + "Pass på at omdömmet ditt ikke faller under 300 og at du ikke dreper mer enn 40% av pasientene, for ellers vil du tape nivået.//" .. + "Lykke til!", + + level1 = + "Velkommen til ditt förste sykehus!//" .. + "Få stedet opp og gå ved å plassere en Resepsjon, bygge en Allmennpraksis, og ansette en Resepsjonist og en Lege. " .. + "Vent så til det begynner å skje ting." .. + "Det er smart å bygge Psykiatri og ansette en Lege med fordypning innenfor psykiatri. " .. + "Et Apotek og en Sykepleier er essensielt for å kurere pasientene dine. " .. + "Se opp for mange tilfeller av Ballonghode - et Pumperom vil fort kunne være til stor hjelp. " .. + "Du må kurere 10 pasienter og sörge for at omdömmet ditt ikke blir mindre enn 200. ", + + level2 = + "Det er et större spekter av plager i dette området. " .. + "Bygg sykehuset for å behandle flere pasienter, og planlegg en egen Forskningsavdeling. " .. + "Husk å holde institusjonen ren, og streb etter så höyt omdömme som mulig - du vil måtte håndtere plager som Lös tunge, så du trenger en Tungeklinikk. " .. + "Du kan også bygge Kardiorom for å forbedre diagnostisering. " .. + "Begge disse rommene vil måtte forskes på för du kan bygge de. Du kan også utvide sykehustomten slik at du får mer plass å boltre deg på - Bruk Områdekartet til dette. " .. + "Streb etter et omdömme på 300 og en banksaldo på $10,000, samt 40 kurerte pasienter. ", + + level3 = + "Du setter opp et sykehus i et velstående område denne gangen. " .. + "Helsedepartementet er ute etter at du klarer å sikre en sunn profitt her. " .. + "Du må få et godt rykte til å begynne med, men når sykehuset går av seg selv, så konsentrer deg om å tjene så mye penger du klarer. " .. + "Det er også en sjanse for at nödssituasjoner oppstår. " .. + "Dette er når store mengder mennesker kommer på en gang med samme tilstand. " .. + "Kurerer du alle innen tidsfristen så får du et bedre rykte, og en stor xbonus. " .. + "Sykdommer som Rock'n'Roll-syndrom kan inntreffe og du bör budsjettere for en Operasjonssal med en Sykestue i nærheten. " .. + "Tjen opp $20,000 for å klare nivået.", + + level4 = + "Hold alle pasientene dine fornöyde, ta deg av dem så effektivt som mulig og hold dödsfall til et absolutt minimum. " .. + "Ditt omdömme står på spill, så sörg for at du får det så höyt som mulig. " .. + "Ikke bekymre deg for mye over penger - det vil komme etter som ditt vitale omdömme vokser. " .. + "Du vil kunne skolere Leger til å utvide sine evner. " .. + "Du kan komme til få pasienter som synes å være mer gjennomsiktig enn de fleste. " .. --sjekk english.lua er det bra nok oversettelse? + "Oppnå et omdömme på over 500.", + + level5 = + "Dette blir et travelt sykehus, siden du må håndtere et bredt spekter av tilfeller. " .. + "Legene du kan ansette kommer rett fra skolen, så det kommer til å være avgjörende for deg å bygge et Klasserom og skolere dem til et akseptabelt nivå. " .. + "Du har kun tre Konsulenter til å lære opp de uerfarne medarbeiderne, så hold dem lykkelige slik at de ikke slutter. " .. + "Merk deg også at sykehusets fundament står på en grunn full av geologiske feil. " .. + "Faren for jordskjelv er alltid tilstedeværende. " .. + "De vil forårsake betydelig skade på maskiner, og forstyrre den jevne driften av sykehuset. " .. + "Få omdömmet ditt opp til 400, og ha $50,000 i banken for å lykkes. Du må også kurere 200 pasienter.", + + level6 = + "Bruk all din kunnskap til å sette opp et velsmurt og kompetent sykehus som gjör et sunt overskudd og kan håndtere alt som den sykelige offentligheten kan kaste på det. " .. --todo - godt nok oversatt? + "Du bör være klar over at atmosfæren rundt her er kjent for å bære med seg bakterier og infeksjoner. " .. + "Med mindre du klarer å holde institusjonen din omhyggelig ren, kan du stå overfor en rekke epidemier blant pasientene. " .. + "Pass på at du skaffer deg $150,000, og at sykehuset er verdt over $140,000.", + + level7 = + "Her vil du være under nöye gransking fra Helsedepartementet, så sörg for at kontoene dine viser at du tjener en masse penger, og at omdömmet ditt er svært bra. " .. + "Vi har ikke råd til unödvendige dödsfall - det er dårlig for forretningene. " .. + "Sörg for at personalet er i tipp-topp form, og at du har alt utstyret du trenger. " .. + "Få et omdömme på 600, pluss $200,000 i banken.", + + level8 = + "Det er opp til deg å sette opp det mest effektive og kostnadseffektive sykehuset som mulig. " .. + "Menneskene rundt her er ganske velstående, så flå dem for så mye grunker du bare klarer. " .. + "Husk at det å kurere mennesker er veldig fint, men du trenger virkelig pengene det bringer. " .. + "Behandle disse syke personene med Pengeutsugeren. " .. + "Samle opp en pengehaug på $300,000 for å fullföre dette nivået.", + + level9 = + "Etter å ha fylt opp Ministerens bankkonto og finansiert Ministerens nye limousin, kan du nå konsentrere deg om å lage et omsorgsfullt og velfungerende sykehus for de trengende. " .. + "Du må forvente å stöte på en rekke problemer her." .. + "Om du har nok av rom og flinke ansatte, skal du kunne ha dette under kontroll. " .. + "Sykehuset ditt må ha en verdi på $200,000, og du må ha $400,000 i banken. " .. + "Med noe mindre får du ikke fullfört dette nivået.", + + level10 = + "I tillegg til å få bukt med alle sykdommene som dukker opp i denne skogkanten, så vil Departementet at du bruker litt tid på å konsentrere deg om effektiviteten av legemidlene dine. " .. + "Det har kommet noen klager fra Ofsick, Helsedepartementets vakthund, så for at alt skal se bra ut du må sörge for at alle legemidler er svært effektive. " .. --todo (bytte ut "Ofsick" med et norskt navn).. + "Kontroller også at sykehuset i tillegg er uklanderlig. Hold dödsfallene nede. " .. + "Som et hint, så kanskje du bör holde av litt plass til en Gelétönne. " .. + "Utvikle alle dine medisiner til minst 80 prosent effektivitet, få et omdömme på 650 og gjem unna $500,000 i banken for å vinne. ", + + level11 = + "Du har fått muligheten til å bygge det ultimate innen sykehus. " .. + "Dette er et meget prestisjefylt område, og Departementet önsker å se det best mulige sykehuset. " .. + "Vi vil forvente at du gjör store penger, har et ypperlig og godt omdömme og dekker alle mulige hendelser. " .. + "Dette er en viktig jobb. " .. + "Du må være virkelig begavet for å gjennomföre det. " .. + "Merk også at det har vært observasjoner av UFO-er i området. Sörg for at personalet er forberedt på noen uventede gjester. " .. + "Sykehuset ditt må være verdt $240,000, du må ha $500,000 i banken og ditt omdömme må være på minst 700.", + + level12 = + "Du har fått moderen av alle utfordringer nå. " .. + "Departementet er imponert over din suksess, og har skaffet toppjobben for deg; de vil at du skal bygge enda et storslagent sykehus, skaffe en stor haug med penger og få et bra utrolig rykte. " .. + "Det forventes at du kjöper opp alle områdene du klarer, kurerer alle sykdommer (og da mener vi alle) og vinner alle premiene. " .. + "Tror du at du klarer det?" .. + "Tjen $650,000, kurer 750 pasienter og få et omdömme på 800 for å vinne dette nivået.", + + level13 = + "Din enestående dyktighet som sykehusadministrator har blitt oppdaget av Hemmelig Super-avdeling fra Superhemmelige Tjenester. " .. + "De har en spesiell bonus for deg; det er et rotteinfisert sykehus som trenger en effektiv Terminator. " .. + "Du må skyte så mange rotter som mulig för Vaktmesterne rydder opp all söpla. " .. + "Tror du at du klarer oppgaven?", + + level14 = + "Det er nok en utfordring - det helt uventede overraskelsessykehuset. " .. + "Om du klarer å gjöre en suksess ut av dette, vil du bli vinneren over alle andre vinnere. " .. + "Ikke forvent at det skal være fort gjort, ettersom det er det töffeste oppdraget du noensinne vil få. " .. + "Lykke til!", + + level15 = + "Ok, det var den grunnleggende teknikken i å sette et sykehus sammen.//" .. + "Legene dine kommer til å trenge all den hjelpen de kan få til å diagnostisere noen av disse pasientene. Du kan hjelpe dem ved å " .. + "bygg et ny diagnoserom, for eksempel Generell Diagnose.", + + level16 = + "Når du har diagnostisert noen av pasientene må du bygge behandlingsrom og klinikker for å kurere dem - en god idé å begynne " .. + "med Apoteket. Du trenger også en Sykepleier for å utlevere ulike legemidler fra Apoteket.", + + level17 = "Siste advarsel - hold öye med omdömmet ditt - det er dette som tiltrekker pasienter til sykehuset ditt. " .. + "Om du ikke dreper for mange mennesker og samtidig holder pasientene noenlunde i godt humör, skal du ikke ha for store problemer med dette nivået!//" .. + "Nå må du klare deg selv. Lykke til med det.", + + level18 = "", } --- Miscellangelous +-- Miscellaneous -- Category of strings that fit nowhere else or we are not sure where they belong. -- If you think a string of these fits somewhere else, please move it there. -- Don't forget to change all references in the code and other language files. diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/original_strings.lua corsix-th-0.62/CorsixTH/Lua/languages/original_strings.lua --- corsix-th-0.30/CorsixTH/Lua/languages/original_strings.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/original_strings.lua 2018-07-21 11:13:17.000000000 +0000 @@ -44,6 +44,16 @@ S[44][168] = S[44][168]:sub(1, 45) end + -- Strings [28][32] and [28][33] are equal in the German translation of the full + -- version, this causes a mismatch with the English strings + -- eng-strings [28][33] to [28][63] are equal to ger-strings [28][34] to [28][64] + -- NB: ONLY in full version, demo version is not affected (thus do checks) + if S[28][32] == S[28][33] and #S[28] == 64 then + for str = 33, 63 do + S[28][str] = S[28][str+1] + end + end + -- German spelling reform: eszett changed to double s in a number of words. -- Mass-apply this change here, so we don't have to override all those strings. local repl = { @@ -951,7 +961,7 @@ -- Menu strings are a little complicated: Different versions of the original -- game have slightly different menu strings. The strings are also organised -- by more levels than traditional strings. For the most part, this extra --- organisation can be use to offset the differences in menu string indicies. +-- organisation can be use to offset the differences in menu string indices. local M = {{}} do local i = 2 @@ -2121,11 +2131,11 @@ local text = S[54][text_index] if text == "." then level_index = level_index + 1 - T["level" .. level_index] = {} + T["level" .. level_index] = "" elseif text == ".." then break else - T["level" .. level_index][#T["level" .. level_index] + 1] = text + T["level" .. level_index] = T["level" .. level_index] .. " " .. text end text_index = text_index + 1 end diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/polish.lua corsix-th-0.62/CorsixTH/Lua/languages/polish.lua --- corsix-th-0.30/CorsixTH/Lua/languages/polish.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/polish.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ +--[[ Copyright (c) 2013 - translation - BuTcHeR (extragry.pl) The study, diagnosis and surgery on the translation performed by: @@ -386,6 +386,7 @@ }, main_menu = { exit = "Nie, nie, proszę nie odchodź!", + custom_campaign = "Rozegraj kampanię stworzoną przez społeczność", custom_level = "Zbuduj swój szpital na dodatkowych poziomach", network = "Rozpocznij grę sieciową", quit = "Wyjdź", @@ -397,6 +398,7 @@ }, new_game = "Zacznij grę od samego początku‏", load_game = "Wczytaj zapisaną grę", + map_edit = "Stwórz własną mapę", }, patient_window = { graph = "Kliknij, aby przełączyć się pomiędzy wykresem zdrowia osób a ich historią leczenia", @@ -595,6 +597,9 @@ fullscreen_button = "Kliknij aby włączyć tryb pełnoekranowy", resolution = "Rozdzielczość w jakiej powinna działać gra", select_resolution = "Wybierz nową rozdzielczość", + audio_toggle = "Włącz/wyłącz", + folder_button = "Opcje folderów", + customise_button = "Dodatkowe ustawienia modifikujące twoją rozgrywkę", width = "Wpisz żądaną szerokość ekranu", height = "Wpisz żądaną wysokość ekranu", apply = "Zatwierdź wybraną rozdzielczość", @@ -796,6 +801,7 @@ dialog_missing_graphics = "Niestety, demo nie zawiera tego dialogu.", maximum_screen_size = "Proszę wpisać rozmiar ekranu, maksimum 3000x2000.", load_prefix = "Błąd podczas ładowania gry: ", + no_games_to_contine = "Nie ma zapisanych gier.", save_prefix = "Błąd podczas zapisywania gry: ", map_file_missing = "Nie można znaleźć pliku z mapą %s dla tego poziomu!", minimum_screen_size = "Proszę wpisać rozmiar ekranu, minimum 640x480.", @@ -822,9 +828,12 @@ custom_level = "Gra niestandardowa", version = "Wersja: ", new_game = "Nowa gra", + custom_campaign = "Własna kampania", + continue = "Powrót do gry", load_game = "Wczytaj grę", options = "Ustawienia", savegame_version = "Wersja zapisu: ", + map_edit = "Edytor map" } date_format = { daymonth = "%1% %2:months%", @@ -1267,18 +1276,24 @@ game_speed = " SZYBKOŚĆ GRY ", music_vol = " GŁOŚNOŚĆ MUZYKI ", sound_vol = " GŁOŚNOŚĆ DŹWIĘKU ", - adviser_disabled = " DORADCA ", + adviser_disabled = " (SHIFT+A) DORADCA ", warmth_colors = " CIEPŁOŚĆ BARW ", + wage_increase = " ŻĄDANIA PODWYŻKI", + twentyfour_hour_clock = " ZEGAR 24 GODZINNY ", edge_scrolling = " PRZEWIJANIE PRZY KRAWĘDZIACH ", - announcements = " POWIADOMIENIA ", + announcements = " (ALT+A) POWIADOMIENIA ", lock_windows = " ZABLOKUJ OKNA ", settings = " USTAWIENIA ", - sound = " DŹWIĘK ", + sound = " (ALT+S) DŹWIĘK ", announcements_vol = " GŁOŚNOŚĆ POWIADOMIEŃ ", - music = " MUZYKA ", + music = " (ALT+M) MUZYKA ", autosave = " AUTOZAPIS ", jukebox = " SZAFA GRAJĄCA ", } +menu_options_wage_increase = { + grant = " PRZYZNAWAJ ", + deny = " ODMAWIAJ ", +} menu_options_warmth_colors = { choice_1 = " CZERWONY ", choice_2 = " NIEBIESKI ZIELONY CZERWONY ", @@ -2194,9 +2209,67 @@ cancel = "Anuluj", data_location = "Lokalizacja danych", font_location = "Lokalizacja czcionki", - language = "Game language", + language = "Język gry", cancel = "Anuluj", back = "Wróć", + audio = "Dźwięk", + customise = "Modyfikuj", + folder = "Foldery", +} +folders_window = { + caption = "Ścieżki folderów", + data_label = "Dane TH", + font_label = "Czcionka", + music_label = "MP3", + savegames_label = "Zapisane stany gry", + screenshots_label = "Zrzuty ekranu", + new_th_location = "Tutaj możesz na nowo wybrać folder, w którym zainstalowana jest gra Theme Hospital. Po wybraniu folderu gra zostanie uruchomiona ponownie.", + savegames_location = "Wybierz folder, w którym chcesz zapisywać stany gry", + music_location = "Wybierz folder z muzyką, której chcesz użyć", + screenshots_location = "Wybierz folder, w którym chcesz zapisywać zrzuty ekranu", + back = "Wstecz", +} +tooltip.folders_window = { + browse = "Przeglądaj foldery", + data_location = "Folder z orginalną grą Theme Hospital, wymagany do uruchomienia CorsixTH", + font_location = "Ścieżka do pliku czcionki będącej w stanie wyświetlić znaki Unicode wymagane przez twój język. Bez podania czcionki nie będzie możliwe wybrania języka, który używa znaki niewspierane przez orginalną grę. Przykład: Rosujski, Chinski, Polski.", + savegames_location = "Domyślnie folder 'Saves', w którym umieszczane są stany gry, leży obok pliku konfiguracyjnego. Jeśli to Ci nie odpowiada możesz wybrać swój własny folder.", + screenshots_location = "Domyślnie folder 'Screenshots', w którym umieszczane są zrzuty ekranu, leży obok pliku konfiguracyjnego. Jeśli to Ci nie odpowiada możesz wybrać swój własny folder.", + music_location = "Wybierz folder z plikami MP3. Folder musi już być stworzony.", + browse_data = "Wskaż inną ścieżkę instalacji Theme Hospital (aktualnie: %1%)", + browse_font = "Wskaż inny plik czcionki ( aktualnie: %1% )", + browse_saves = "Wskaż inną ścieżkę folderu ze stanami gry ( aktualnie: %1% ) ", + browse_screenshots = "Wskaż inną ścieżkę folderu ze zrzutami ekranu ( aktualnie: %1% ) ", + browse_music = "Wskaż inną ścieżkę folderu z twoją muzyką ( aktualnie: %1% ) ", + no_font_specified = "Nie podano jeszcze pliku czcionki!", + not_specified = "Nie podano jeszcze ścieżki folderu!", + default = "Domyślna ścieżka", + reset_to_default = "Przywróć domyślną ścieżkę dla folderu", + back = "Zamknij to menu i wróć do ustawień", +} +customise_window = { + caption = "Własne ustawienia", + option_on = "Wł", + option_off = "Wył", + back = "Wróć", + movies = "Zarządzanie filmami", + intro = "Odtwórz intro", + paused = "Budoowanie w czasie pauzy", + volume = "Skrót ściszania", + aliens = "Pacjenci Obcy", + fractured_bones = "Pogruchotane kości", + average_contents = "Standardowe wyposarzenie", +} + +tooltip.customise_window = { + movies = "Globalne zarządzanie filmami pozwoli Tobie na wyłączenie wszystkich filmików", + intro = "Włącz lub wyłącz intro. Filmiki muszą być globalnie włączone jeśli chcesz oglądać intro przy każdym uruchomieniu CorsixTH", + paused = "W grze Theme Hospital gracz mógł jedynie używać górnego menu podczas pauzy. Jest to również domyślne ustawianie CorsixTH, ale przez włączenie tej opcji wszystko jest dozwolone podczas pauzy", + volume = "Jeśli przycisk ściszania otwiera również 'Teczkę z lekami' , włącz tę opcję aby zmienić skrót do 'Teczki...' na Shift + C", + aliens = "Z powodu braku dobrych animacji dokonaliśmy zmian aby pacjęci z DNA Obcego domyślnie przybywali tylko z nagłych wypadków. Jeśli chcesz aby pacjensi z DNA Obcego mogli odwiedzać twój szpital nie tylko po nagłym wypadku wyłącz tę opcję", + fractured_bones = "Z powodu kiepskich animacji domyślnie wyłączyliśmy damskie modele pacjętów ze Zgruchotanymi Koścmi. Aby zezwolić, żeby pacjentki ze Zgruchotanymi koścmi odwiedzały twój szpital, wyłącz tę opcję", + average_contents = "Jeśli chcesz, żeby gra zapamiętała jakie dodatkowe wyposarzenie używasz zazwyczaj budując dany typ pomieszczenia, włącz tę opcję", + back = "Zamknij to menu i wróć do ustawień", } buy_objects_window = { price = "Cena: ", @@ -2488,10 +2561,10 @@ [8] = " GRA 8 ", } menu_file = { - quit = " WYJDŹ ", - save = " ZAPISZ ", - load = " WCZYTAJ ", - restart = " RESTART ", + quit = " (SHIFT+Q) WYJDŹ ", + save = " (SHIFT+S) ZAPISZ ", + load = " (SHIFT+L) WCZYTAJ ", + restart = " (SHIFT+R) ZACZNIJ OD NOWA ", } rooms_long = { ultrascan = "Ultraskaner", @@ -2804,135 +2877,116 @@ }, } introduction_texts = { - level17 = { - [1] = "Ostatnia rada - dbaj o Reputację - to ona przyciąga lub zniechęca do twojej placówki pacjentów z całej okolicy. ", - [2] = "Jeśli tylko uda ci się nie zabić zbyt wielu ludzi i będą oni w miarę zadowoleni, nie powinieneś mieć problemów z tym poziomem!//", - [3] = "Teraz już musisz radzić sobie sam. Życzę powodzenia.", - }, - level1 = { - [1] = "Witaj w swoim pierwszym szpitalu!//", - [2] = "Aby rozpocząć działalność, postaw Biurko Recepcji, zbuduj Gabinet Lekarski i zatrudnij Recepcjonistkę oraz Lekarza. ", - [3] = "Następnie zaczekaj, aż pojawią się kolejne zadania.", - [4] = "Dobrym pomysłem jest budowa Gabinetu Psychiatrycznego oraz zatrudnienie Lekarza Psychiatry. ", - [5] = "Apteka i Pielęgniarka są także niezbędne w leczeniu pacjentów. ", - [6] = "Zwróć uwagę na ciężkie przypadki Głowowzdęcia - Napowietrzalnia rozwiąże ten problem. ", - [7] = "Będziesz musiał wyleczyć 10 ludzi i upewnić się, że twoja reputacja nie spadnie poniżej 200.", - }, - level9 = { - [1] = "Skoro już wzbogaciłeś konto Ministerstwa oraz ufundowałeś nową limuzynę samemu Ministrowi, możesz wracać do szpitala i nieść pomoc chorym i potrzebującym. ", - [2] = "Tutaj napotkasz wiele różnych trudności.", - [3] = "Z dobrze wyszkolonym personelem i gabinetami, nie powinieneś się niczego obawiać. ", - [4] = "Twój szpital musi być wart 200,000 PLN, a na konto ma trafić 400,000 PLN. ", - [5] = "Ani grosza mniej, bo nie ukończysz poziomu.", - }, - level2 = { - [1] = "Na tym obszarze jest dużo więcej rodzajów schorzeń. ", - [2] = "Urządź swój szpital tak, aby przyjął więcej pacjentów oraz zaplanuj budowę Działu Badawczego. ", - [3] = "Pamiętaj o utrzymywaniu czystości i postaraj się o możliwie najwyższą reputację - będziesz miał do czynienia z chorobami takimi jak Obwisły Język, więc potrzebujesz Przychodni Obrzynania. ", - [4] = "Możesz także zbudować Kardiograf, aby lepiej diagnozować nowe choroby. ", - [5] = "Oba te gabinety muszą zostać wynalezione zanim będziesz mógł je zbudować. Teraz możesz także kupić dodatkowy grunt, aby rozwinąć swój szpital - w tym celu użyj Mapy Miasta. ", - [6] = "Twój cel to reputacja na poziomie 300, stan konta 10000 PLN, i 40 wyleczonych osób.", - }, - level7 = { - [1] = "Będziesz tu pod ścisłym nadzorem Ministerstwa Zdrowia, dopilnuj więc by twoje konto wykazywało duże zyski, a reputacja szybowała w górę. ", - [2] = "Nie stać nas na niepotrzebne zgony - nie służy to biznesowi. ", - [3] = "Upewnij się, że personel jest w dobrej formie i że masz wszystkie wymagane urządzenia. ", - [4] = "Wypracuj reputację 600 oraz 200,000 PLN na koncie.", - }, - level5 = { - [1] = "To będzie szpital pełen życia, leczący wiele różnych dolegliwości. ", - [2] = "Twoi Lekarze dopiero skończyli studia, więc trzeba będzie wybudować salę szkoleniową, aby zdobyli niezbędne kwalifikacje. ", - [3] = "Masz tylko trzech Konsultantów szkolących twój personel. Dbaj więc o to, by byli zadowoleni. ", - [4] = "Zauważ także, że fundamenty szpitala znajdują się na uskoku tektonicznym San Android. ", - [5] = "Występuje tu duże ryzyko trzęsień ziemi. ", - [6] = "Trzęsienia mogą w znacznym stopniu uszkodzić urządzenia i zakłócić pracę szpitala. ", - [7] = "Aby odnieść sukces, dociągnij reputację do 400, zgromadź w banku okrągłe 50,000 PLN i wylecz 200 pacjentów.", - }, - level4 = { - [1] = "Staraj się zadowolić swych pacjentów, obłsuguj ich najlepiej jak potrafisz, utrzymaj również liczbę zgonów na absolutnym minimum.", - [2] = "Stawką jest twoja reputacja, więc dopilnuj żeby osiągnęła wysoki poziom. ", - [3] = "Nie martw się za bardzo o pieniądze - uzyskasz je wraz z rosnącą reputacją. ", - [4] = "Będziesz też mógł szkolić swoich Lekarzy, aby zwiększać ich umiejętności. ", - [5] = "Wyszkolony personel będzie lepiej zajmować się pacjentami, którzy wyglądają na ciężej chorych niż pozostali. ", - [6] = "Osiągnij reputację na poziomie ponad 500.", - }, - level14 = { - [1] = "Jest jeszcze jedno wyzwanie - totalnie niespodziewany szpital niespodzianka. ", - [2] = "Jeżeli tutaj odniesiesz sukces, będziesz zwycięzcą wszech czasów. ", - [3] = "Tylko nie myśl, że to będzie bułka z masłem, ponieważ jest to najtrudniejsze zadanie jakiemu stawisz czoła. ", - [4] = "Powodzenia!", - }, - level15 = { - [1] = "Tak wyglądają podstawowe mechanizmy działalności szpitala.//", - [2] = "Twoi Lekarze będą potrzebować wszelkiej możliwej pomocy do diagnozowania niektórych pacjentów. Możesz im pomóc budując ", - [3] = "kolejne obiekty, takie jak Gabinet Badań Podstawowych.", - }, - level8 = { - [1] = "Do ciebie należy zadanie urządzenia wydajnego i opłacalnego szpitala. ", - [2] = "Ludzie tutaj są dość zamożni, więc oskub ich z forsy jak tylko się da. ", - [3] = "Miło jest leczyć ludzi, ale pamiętaj, że tak naprawdę liczą się PIENIĄDZE. ", - [4] = "Wyczyść tych chorych ludzi z pieniędzy. ", - [5] = "Aby ukończyć ten poziom, zgromadź sumę 300,000 PLN.", - }, - level13 = { - [1] = "Twoje niewiarygodne umiejętności w administrowaniu szpitala zwróciły uwagę Trzeciego Wydziału Tajnych Służb Specjalnych. ", - [2] = "Mają dla ciebie ekstra zadanie: w szpitalu zaatakowanym przez szczury potrzeba Terminatora. ", - [3] = "Musisz ustrzelić tyle szczurów, ile zdołasz, zanim Dozorcy uprzątną bałagan. ", - [4] = "Myślisz, że poradzisz sobie z zadaniem?", - }, - demo = { - [1] = "Witaj w szpitalu demonstracyjnym!", - [2] = "Niestety wersja demo zawiera tylko ten poziom. Jednakże, jest to więcej niż wystarczająco, aby zając ci trochę czasu!", - [3] = "Napotkasz tutaj rozmaite choroby, które będą wymagały różnych gabinetów do ich wyleczenia. Od czasu do czasu moga tu również wystąpić nagłe wypadki. Będziesz musiał równiez wynaleźć nowe pomieszczenia przy użyciu gabinetu badawczego.", - [4] = "Twoim celem jest zarobienie 100,000 PLN, mieć szpital warty 70,000 PLN i reputację 700, przy czym musisz wyleczyć co najmniej 75% swoich pacjentów.", - [5] = "Upewnij się, że Twoja reputacja nie spadnie poniżej 300 oraz, że nie zabijesz więcej niż 40% pacjentów, albo przegrasz.", - [6] = "Powodzenia!", - }, - level16 = { - [1] = "Kiedy już przebadasz część pacjentów, będziesz musiał zbudować pomieszczenia lecznicze oraz przychodnie, aby ich leczyć - ", - [2] = "dobrze jest zacząć od budowy Apteki. Do wydawania leków w Aptece będzie potrzebna Pielęgniarka .", - }, - level6 = { - [1] = "Użyj całej swojej wiedzy, aby gładko poprowadzić szpital, który przyniesie dobry zysk i poradzi sobie ze wszystkim, co przyniesie mu chore społeczeństwo. ", - [2] = "Powinieneś uważać na panujący tu klimat, gdyż sprzyja on rozwojowi bakterii i infekcji. ", - [3] = "Jeśli nie utrzymasz tego miejsca we wzorowej czystości, musisz się liczyć z wybuchem epidemii wśród pacjentów. ", - [4] = "Powinieneś zarobić 150,000 PLN a twój szpital osiągnąć wartość co najmniej 140,000 PLN.", - }, - level12 = { - [1] = "Masz teraz do czynienia z matką wszystkich wyzwań. ", - [2] = "Zachwycone twoimi sukcesami Ministerstwo ma dla ciebie zadanie specjalne. Masz zbudować kolejny wspaniały szpital, zarobić bajeczną ilość kasy i zyskać gigantyczną reputację. ", - [3] = "Musisz także wykupić wszystkie możliwe grunty, wyleczyć wszystko (tak - wszystko) oraz zgarnąć wszystkie nagrody. ", - [4] = "I jak? Dasz radę?", - [5] = "Zarób 650,000 PLN, wylecz 750 ludzi oraz osiągnij reputację 800, aby wygrać.", - }, - level3 = { - [1] = "Tym razem urządzisz swój szpital w zamożej okolicy. ", - [2] = "Ministerstwo Zdrowia ma nadzieję, że osiągniesz tu znaczne zyski. ", - [3] = "Musisz wypracować dobrą reputację, jednak gdy szpital będzie już działał, skoncentruj się na zarabianiu tak dużo, jak tylko możliwe. ", - [4] = "Prawdopodobnie wystąpią tu też Nagłe Wypadki. ", - [5] = "Mają miejsce, gdy do szpitala przybywa duża grupa ludzi z tą samą dolegliwością. ", - [6] = "Wyleczenie ich wszystkich przed upływem czasu podnosi twoją reputację i zapewnia premię. ", - [7] = "Mogą wystąpić choroby takie jak Syndrom Króla. Przeznacz więc pieniądze na budowę Sali Operacyjnej z Oddziałem tuż obok. ", - [8] = "Aby stanąć na wysokości zadania, zarób 20,000 PLN.", - }, - level10 = { - [1] = "Ministerstwo prosi, abyś poza leczeniem chorób typowych dla tych stron, poświęcił nieco czasu na poprawę skuteczności leków. ", - [2] = "Zrzeszenie Pacjentów Bolibrzuch zgłosiło kilka krytycznych uwag. Nie daj im powodów do skarg i dopilnuj, by leki były jak najskuteczniejsze. ", - [3] = "Nikt nie powinien też czynić zarzutów samemu szpitalowi. Zmniejsz poziom umieralności. ", - [4] = "Dobrze będzie, jeśli zarezerwujesz trochę miejsca na Galaretownicę. ", - [5] = "Aby wygrać, udoskonal wszystkie leki do 80% skuteczności, zdobądź reputację 650 i zbierz w banku 500,000 PLN. ", - }, - level11 = { - [1] = "Dostałeś szansę budowy szpitala najdoskonalszego ze wszystkich. ", - [2] = "W tej niezwykle renomowanej okolicy Ministerstwo chciałoby mieć szpital najlepszy z możliwych. ", - [3] = "Oczekujemy, że zarobisz mnóstwo pieniędzy, zyskasz znakomitą reputację i poradzisz sobie ze wszelkimi ewentualnościami. ", - [4] = "To jest bardzo ważna robota. ", - [5] = "Będziesz musiał naprawdę się czymś wyróżnić. ", - [6] = "Trzeba ci wiedzieć, że w tych okolicach widywane jest UFO. Twój personel powinien być przygotowany na niespodziewanych gości. ", - [7] = "Warunki wygranej to: wartość szpitala 240,000 PLN, 500,000 PLN na koncie i reputacja na poziomie co najmniej 700.", - }, - level18 = { - }, + level17 = + "Ostatnia rada - dbaj o Reputację - to ona przyciąga lub zniechęca do twojej placówki pacjentów z całej okolicy. " .. + "Jeśli tylko uda ci się nie zabić zbyt wielu ludzi i będą oni w miarę zadowoleni, nie powinieneś mieć problemów z tym poziomem!//" .. + "Teraz już musisz radzić sobie sam. Życzę powodzenia.", + level1 = + "Witaj w swoim pierwszym szpitalu!//" .. + "Aby rozpocząć działalność, postaw Biurko Recepcji, zbuduj Gabinet Lekarski i zatrudnij Recepcjonistkę oraz Lekarza. " .. + "Następnie zaczekaj, aż pojawią się kolejne zadania. " .. + "Dobrym pomysłem jest budowa Gabinetu Psychiatrycznego oraz zatrudnienie Lekarza Psychiatry. " .. + "Apteka i Pielęgniarka są także niezbędne w leczeniu pacjentów. " .. + "Zwróć uwagę na ciężkie przypadki Głowowzdęcia - Napowietrzalnia rozwiąże ten problem. " .. + "Będziesz musiał wyleczyć 10 ludzi i upewnić się, że twoja reputacja nie spadnie poniżej 200.", + level9 = + "Skoro już wzbogaciłeś konto Ministerstwa oraz ufundowałeś nową limuzynę samemu Ministrowi, możesz wracać do szpitala i nieść pomoc chorym i potrzebującym. " .. + "Tutaj napotkasz wiele różnych trudności. " .. + "Z dobrze wyszkolonym personelem i gabinetami, nie powinieneś się niczego obawiać. " .. + "Twój szpital musi być wart 200,000 PLN, a na konto ma trafić 400,000 PLN. " .. + "Ani grosza mniej, bo nie ukończysz poziomu.", + level2 = + "Na tym obszarze jest dużo więcej rodzajów schorzeń. " .. + "Urządź swój szpital tak, aby przyjął więcej pacjentów oraz zaplanuj budowę Działu Badawczego. " .. + "Pamiętaj o utrzymywaniu czystości i postaraj się o możliwie najwyższą reputację - będziesz miał do czynienia z chorobami takimi jak Obwisły Język, więc potrzebujesz Przychodni Obrzynania. " .. + "Możesz także zbudować Kardiograf, aby lepiej diagnozować nowe choroby. " .. + "Oba te gabinety muszą zostać wynalezione zanim będziesz mógł je zbudować. Teraz możesz także kupić dodatkowy grunt, aby rozwinąć swój szpital - w tym celu użyj Mapy Miasta. " .. + "Twój cel to reputacja na poziomie 300, stan konta 10000 PLN, i 40 wyleczonych osób.", + level7 = + "Będziesz tu pod ścisłym nadzorem Ministerstwa Zdrowia, dopilnuj więc by twoje konto wykazywało duże zyski, a reputacja szybowała w górę. " .. + "Nie stać nas na niepotrzebne zgony - nie służy to biznesowi. " .. + "Upewnij się, że personel jest w dobrej formie i że masz wszystkie wymagane urządzenia. " .. + "Wypracuj reputację 600 oraz 200,000 PLN na koncie.", + level5 = + "To będzie szpital pełen życia, leczący wiele różnych dolegliwości. " .. + "Twoi Lekarze dopiero skończyli studia, więc trzeba będzie wybudować salę szkoleniową, aby zdobyli niezbędne kwalifikacje. " .. + "Masz tylko trzech Konsultantów szkolących twój personel. Dbaj więc o to, by byli zadowoleni. " .. + "Zauważ także, że fundamenty szpitala znajdują się na uskoku tektonicznym San Android. " .. + "Występuje tu duże ryzyko trzęsień ziemi. " .. + "Trzęsienia mogą w znacznym stopniu uszkodzić urządzenia i zakłócić pracę szpitala. " .. + "Aby odnieść sukces, dociągnij reputację do 400, zgromadź w banku okrągłe 50,000 PLN i wylecz 200 pacjentów.", + level4 = + "Staraj się zadowolić swych pacjentów, obłsuguj ich najlepiej jak potrafisz, utrzymaj również liczbę zgonów na absolutnym minimum." .. + "Stawką jest twoja reputacja, więc dopilnuj żeby osiągnęła wysoki poziom. " .. + "Nie martw się za bardzo o pieniądze - uzyskasz je wraz z rosnącą reputacją. " .. + "Będziesz też mógł szkolić swoich Lekarzy, aby zwiększać ich umiejętności. " .. + "Wyszkolony personel będzie lepiej zajmować się pacjentami, którzy wyglądają na ciężej chorych niż pozostali. " .. + "Osiągnij reputację na poziomie ponad 500.", + level14 = + "Jest jeszcze jedno wyzwanie - totalnie niespodziewany szpital niespodzianka. " .. + "Jeżeli tutaj odniesiesz sukces, będziesz zwycięzcą wszech czasów. " .. + "Tylko nie myśl, że to będzie bułka z masłem, ponieważ jest to najtrudniejsze zadanie jakiemu stawisz czoła. " .. + "Powodzenia!", + level15 = + "Tak wyglądają podstawowe mechanizmy działalności szpitala.//" .. + "Twoi Lekarze będą potrzebować wszelkiej możliwej pomocy do diagnozowania niektórych pacjentów. Możesz im pomóc budując " .. + "kolejne obiekty, takie jak Gabinet Badań Podstawowych.", + level8 = + "Do ciebie należy zadanie urządzenia wydajnego i opłacalnego szpitala. " .. + "Ludzie tutaj są dość zamożni, więc oskub ich z forsy jak tylko się da. " .. + "Miło jest leczyć ludzi, ale pamiętaj, że tak naprawdę liczą się PIENIĄDZE. " .. + "Wyczyść tych chorych ludzi z pieniędzy. " .. + "Aby ukończyć ten poziom, zgromadź sumę 300,000 PLN.", + level13 = + "Twoje niewiarygodne umiejętności w administrowaniu szpitala zwróciły uwagę Trzeciego Wydziału Tajnych Służb Specjalnych. " .. + "Mają dla ciebie ekstra zadanie: w szpitalu zaatakowanym przez szczury potrzeba Terminatora. " .. + "Musisz ustrzelić tyle szczurów, ile zdołasz, zanim Dozorcy uprzątną bałagan. " .. + "Myślisz, że poradzisz sobie z zadaniem?", + demo = + "Witaj w szpitalu demonstracyjnym!//" .. + "Niestety wersja demo zawiera tylko ten poziom. Jednakże, jest to więcej niż wystarczająco, aby zając ci trochę czasu! " .. + "Napotkasz tutaj rozmaite choroby, które będą wymagały różnych gabinetów do ich wyleczenia. Od czasu do czasu moga tu również wystąpić nagłe wypadki. Będziesz musiał równiez wynaleźć nowe pomieszczenia przy użyciu gabinetu badawczego. " .. + "Twoim celem jest zarobienie 100,000 PLN, mieć szpital warty 70,000 PLN i reputację 700, przy czym musisz wyleczyć co najmniej 75% swoich pacjentów. " .. + "Upewnij się, że Twoja reputacja nie spadnie poniżej 300 oraz, że nie zabijesz więcej niż 40% pacjentów, albo przegrasz.//" .. + "Powodzenia!", + level16 = + "Kiedy już przebadasz część pacjentów, będziesz musiał zbudować pomieszczenia lecznicze oraz przychodnie, aby ich leczyć - " .. + "dobrze jest zacząć od budowy Apteki. Do wydawania leków w Aptece będzie potrzebna Pielęgniarka .", + level6 = + "Użyj całej swojej wiedzy, aby gładko poprowadzić szpital, który przyniesie dobry zysk i poradzi sobie ze wszystkim, co przyniesie mu chore społeczeństwo. " .. + "Powinieneś uważać na panujący tu klimat, gdyż sprzyja on rozwojowi bakterii i infekcji. " .. + "Jeśli nie utrzymasz tego miejsca we wzorowej czystości, musisz się liczyć z wybuchem epidemii wśród pacjentów. " .. + "Powinieneś zarobić 150,000 PLN a twój szpital osiągnąć wartość co najmniej 140,000 PLN.", + level12 = + "Masz teraz do czynienia z matką wszystkich wyzwań. " .. + "Zachwycone twoimi sukcesami Ministerstwo ma dla ciebie zadanie specjalne. Masz zbudować kolejny wspaniały szpital, zarobić bajeczną ilość kasy i zyskać gigantyczną reputację. " .. + "Musisz także wykupić wszystkie możliwe grunty, wyleczyć wszystko (tak - wszystko) oraz zgarnąć wszystkie nagrody. " .. + "I jak? Dasz radę?" .. + "Zarób 650,000 PLN, wylecz 750 ludzi oraz osiągnij reputację 800, aby wygrać.", + level3 = + "Tym razem urządzisz swój szpital w zamożej okolicy. " .. + "Ministerstwo Zdrowia ma nadzieję, że osiągniesz tu znaczne zyski. " .. + "Musisz wypracować dobrą reputację, jednak gdy szpital będzie już działał, skoncentruj się na zarabianiu tak dużo, jak tylko możliwe. " .. + "Prawdopodobnie wystąpią tu też Nagłe Wypadki. " .. + "Mają miejsce, gdy do szpitala przybywa duża grupa ludzi z tą samą dolegliwością. " .. + "Wyleczenie ich wszystkich przed upływem czasu podnosi twoją reputację i zapewnia premię. " .. + "Mogą wystąpić choroby takie jak Syndrom Króla. Przeznacz więc pieniądze na budowę Sali Operacyjnej z Oddziałem tuż obok. " .. + "Aby stanąć na wysokości zadania, zarób 20,000 PLN.", + level10 = + "Ministerstwo prosi, abyś poza leczeniem chorób typowych dla tych stron, poświęcił nieco czasu na poprawę skuteczności leków. " .. + "Zrzeszenie Pacjentów Bolibrzuch zgłosiło kilka krytycznych uwag. Nie daj im powodów do skarg i dopilnuj, by leki były jak najskuteczniejsze. " .. + "Nikt nie powinien też czynić zarzutów samemu szpitalowi. Zmniejsz poziom umieralności. " .. + "Dobrze będzie, jeśli zarezerwujesz trochę miejsca na Galaretownicę. " .. + "Aby wygrać, udoskonal wszystkie leki do 80% skuteczności, zdobądź reputację 650 i zbierz w banku 500,000 PLN. ", + level11 = + "Dostałeś szansę budowy szpitala najdoskonalszego ze wszystkich. " .. + "W tej niezwykle renomowanej okolicy Ministerstwo chciałoby mieć szpital najlepszy z możliwych. " .. + "Oczekujemy, że zarobisz mnóstwo pieniędzy, zyskasz znakomitą reputację i poradzisz sobie ze wszelkimi ewentualnościami. " .. + "To jest bardzo ważna robota. " .. + "Będziesz musiał naprawdę się czymś wyróżnić. " .. + "Trzeba ci wiedzieć, że w tych okolicach widywane jest UFO. Twój personel powinien być przygotowany na niespodziewanych gości. " .. + "Warunki wygranej to: wartość szpitala 240,000 PLN, 500,000 PLN na koncie i reputacja na poziomie co najmniej 700.", + level18 = "", } humanoid_name_starts = { [1] = "GOLD", @@ -3183,6 +3237,46 @@ options = " OPCJE ", charts = " STATYSTYKI ", } +map_editor_window = { + pages = { + inside = "Wnętrze", + outside = "Na zewnątrz", + foliage = "Ulistowienie", + hedgerow = "Żywopłot", + pond = "Sadzawka", + road = "Droga", + north_wall = "Ściana północna", + west_wall = "Ściana zachodnia", + helipad = "Lądowisko", + delete_wall = "Usuń ściany", + parcel_0 = "Parcela 0", + parcel_1 = "Parcela 1", + parcel_2 = "Parcela 2", + parcel_3 = "Parcela 3", + parcel_4 = "Parcela 4", + parcel_5 = "Parcela 5", + parcel_6 = "Parcela 6", + parcel_7 = "Parcela 7", + parcel_8 = "Parcela 8", + parcel_9 = "Parcela 9", + camera_1 = "Kamera 1", + camera_2 = "Kamera 2", + camera_3 = "Kamera 3", + camera_4 = "Kamera 4", + heliport_1 = "Lądowisko 1", + heliport_2 = "Lądowisko 2", + heliport_3 = "Lądowisko 3", + heliport_4 = "Lądowisko 4", + paste = "Wklej obszar", + } +} +menu["player_count"] = "LICZBA GRACZY" +menu_player_count = { + players_1 = " 1 GRACZ ", + players_2 = " 2 GRACZY ", + players_3 = " 3 GRACZY ", + players_4 = " 4 GRACZY ", +} diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/russian.lua corsix-th-0.62/CorsixTH/Lua/languages/russian.lua --- corsix-th-0.30/CorsixTH/Lua/languages/russian.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/russian.lua 2018-07-21 11:13:17.000000000 +0000 @@ -37,10 +37,13 @@ -- 1. Главное меню main_menu = { new_game = "Новая игра", + continue = "продолжить игру", custom_level = "Дополнительные уровни", load_game = "Загрузить игру", options = "Настройки", exit = "Выход", + savegame_version = "Версия файлов сохранений: ", + version = "Версия: ", } new_game_window = { tutorial = "Обучение", @@ -48,6 +51,20 @@ medium = "Доктор (Средний)", hard = "Консультант (Трудный)", cancel = "Отмена", + difficulty = "Сложность", + option_on = "Вкл.", + option_off = "Выкл.", + caption = "Кампания", + player_name = "Имя Игрока", + start = "Старт", +} +menu_options_warmth_colors = { + choice_2 = " СИНИЙ ЗЕЛЕНЫЙ КРАСНЫЙ ", + choice_1 = " КРАСНЫЙ ", + choice_3 = " ЖЕЛТЫЙ ОРАНЖЕВЫЙ КРАСНЫЙ ", +} +date_format = { + daymonth = "%1% %2:months%", } custom_game_window = { caption = "Дополнительные уровни", @@ -59,6 +76,32 @@ caption = "Сохранить игру", new_save_game = "Новое сохранение", } +folders_window = { + data_label = "Данные TH", + music_location = "Выберите папку, которую хотите использовать под вашу Музыку", + music_label = "MP3", + new_th_location = "Здесь вы можете указать новую папку с установкой оригинальной Theme Hospital. Как только вы выберете новую папку, игра будет перезапущена.", + caption = "Расположение папок", + screenshots_label = "Скриншоты", + font_label = "Шрифт", + savegames_label = "Сохранения", + back = "Назад", + savegames_location = "Выберите папку для размещения сохраненных игр.", + screenshots_location = "Выберите папку для размещения скриншотов.", +} +customise_window = { + average_contents = "Дополнительные объекты", + option_on = "Вкл.", + paused = "Строительство на Паузе", + option_off = "Выкл.", + intro = "Проигрывать вступительный ролик", + caption = "Пользовательские настройки", + back = "Назад", + movies = "Общий контроль за видео", + volume = "Кнопка уменьшения громкости", + aliens = "Пациенты - пришельцы", + fractured_bones = "Сломаные кости", +} options_window = { fullscreen = "Во весь экран", height = "Высота", @@ -67,16 +110,35 @@ back = "Назад", original_path = "Папка с установленной оригинальной игрой Theme Hospital", browse = "Выбрать папку", + folder = "ПАПКИ", + option_off = "Выкл.", + apply = "Применить", + option_on = "Вкл.", + custom_resolution = "Выбрать...", + caption = "Настройки", + cancel = "Отмена", + customise = "Настроить", + audio = "Общие звуки", + resolution = "Разрешение", + language = "Язык в игре", } menu_list_window = { back = "Назад", } +update_window = { + caption = "Доступно обновление!", + new_version = "Новая Версия:", + current_version = "Текущая Версия: ", + download = "Перейти на страницу загрузки", + ignore = "Пропустить и перейти в Главное меню", +} tooltip = { main_menu = { exit = "Стой! Пожалуйста, не уходи!", custom_level = "Играть отдельный уровень", options = "Изменить всякие параметры", new_game = "Начать совершенно новую игру с самого начала", + continue = "продолжить последнюю сохраненную игру", load_game = "Загрузить сохраненную ранее игру", }, new_game_window = { @@ -113,6 +175,8 @@ file = " Файл", options = " Опции", charts = " Отчеты", + display = " ОТОБРАЖЕНИЕ ", + debug = " ОТЛАДКА ", } menu_file = { save = " Сохранить", @@ -133,6 +197,10 @@ music = " Музыка", autosave = " Автосохранение", jukebox = " Музыкальный автомат", + twentyfour_hour_clock = " 24-х часовой формат времени ", + wage_increase = " ЗАПРОСЫ О ЗАРПЛАТЕ ", + warmth_colors = " ЦВЕТА ОТОПЛЕНИЯ ", + adviser_disabled = " (SHIFT+A) ПОМОЩНИК ", } menu_options_game_speed = { pause = " (P) Пауза", @@ -142,6 +210,10 @@ max_speed = " (4) Быстрая", and_then_some_more = " (5) Еще быстрее", } +menu_options_wage_increase = { + deny = " ЗАПРЕТИТЬ ", + grant = " РАЗРЕШИТЬ ", +} menu_charts = { statement = " Баланс банка", casebook = " Лабораторный журнал", @@ -152,6 +224,7 @@ bank_manager = " Управляющий банка", status = " Состояние", briefing = " Инструктаж", + town_map = " (F4) карта города ", } menu_file_load = { [1] = " ИГРА 1 ", @@ -187,10 +260,18 @@ [7] = " ИГРА 7 ", [8] = " ИГРА 8 ", } +menu_display = { + shadows = " ТЕНИ ", + mcga_lo_res = " MCGA НИЗ.РАЗРЕШЕНИЕ ", + high_res = " ВЫСОКОЕ РАЗРЕШЕНИЕ ", +} + install = { title = "--------------------------------- Установка CorsixTH ---------------------------------", th_directory = "CorsixTH для нормальной работы требуется оригинальная установленная игра Theme Hospital. Нажмите кнопку и выберите папку, в которую установлена оригинальная игра.", exit = "Выход", + ok = "OK", + cancel = "Отмена", } dynamic_info = { patient = { @@ -234,8 +315,17 @@ heading_for = "Идет в %s", }, tiredness = "Усталость", + psychiatrist_abbrev = "Псих.", + ability = "Способность", }, } +handyman_window = { + all_parcels = "Все корпуса", + parcel = "Корпус", +} +font_location_window = { + caption = "Выберите шрифт (%1%)", +} staff_title = { junior = "Студент", psychiatrist = "Психиатр", @@ -265,6 +355,151 @@ charts = "Графики", policy = "Политика", }, + options_window = { + select_language = "Выбрать язык игры", + select_resolution = "Выбрать новое разрешение", + language_dropdown_item = "Выбрать %s язык", + audio_button = "Включить или выключить весь игровой звук", + resolution = "Разрешение в котором игра должна работать", + audio_toggle = "Переключатель вкл. или выкл.", + fullscreen = "Игра должна работать в полноэкранном или оконном режиме", + apply = "Использовать введенное разрешение", + cancel = "Вернуться без изменения разрешения", + folder_button = "Свойства Папки", + customise_button = "Выможете изменить больше настроек для индивидуализации игрового опыта", + }, + menu_list_window = { + save_date = "Нажмите тут для сортировки списка по дате последнего изменения", + name = "Нажмите тут для сортировки списка по имени", + }, + cheats_window = { + cheats = { + earthquake = "Вызвать землетрясение.", + vip = "Пригласить ВИП.", + }, + }, + custom_game_window = { + free_build = "Отметьте тут если вы хотите играть без денег и условий для победы и поражения", + }, + new_game_window = { + difficulty = "Выберите уровень сложности игры", + player_name = "Введите имя, которым вы хотите представляться в игре", + start = "Начать игры с выбранными настройками", + }, + casebook = { + cure_type = { + drug = "Это лечение будет использовать лекарство", + unknown = "Вы все ещё не знаете как лечить это заболевание", + }, + cure_requirement = { + hire_surgeon = "Вы должны нанять второго Хирурка для проведения операции", + not_possible = "Вы все ещё не можете справиться с этим лечением", + hire_staff_old = "Вам нужно нанять %s для проведения этого лечения", + hire_surgeons = "Для проведения операций вам нужно нанять двух Хирургов", + build_ward = "Вам необходимо построить Палату для проведения этого лечения", + ward_hire_nurse = "Вам нужна Медсестра для работы в Палате для проведения этого лечения", + }, + }, + main_menu = { + load_menu = { + load_slot = "ЗАГРУЗИТЬ ИГРУ", + empty_slot = "ПУСТО", + }, + continue = "Продолжить предыдущую игру", + network = "Начать сетевую игру", + quit = "Вы собираетесь выйти из CorsixTH. Вы уверены в том что хотите именно этого?", + }, + load_game_window = { + load_game_number = "Загрузить игру %d", + }, + update_window = { + download = "Перейти на страницу загрузки самой последней версии CorsixTH", + ignore = "Игнорировать это обновление. Вы будете снова оповещены когда снова запустите CorsixTH", + }, + folders_window = { + browse_font = "Просмотреть другой файл шрифтаBrowse ( текущее местоположение: %1% )", + screenshots_location = "По умолчанию Скриншоты сохраняются в папке вместе с конфигурационным файлом. Если это не подходит, то вы можете выбрать его самостоятельно, просто перейдите в каталог, который вы хотите для этого использовать.", + reset_to_default = "Установить папку по умолчанию", + back = "Закрть это меню и вернуться в Меню Настроек", + music_location = "Выберете папку, где хранятся файлы с mp3 музыкой. Если вы ее только что создали, тогда перейдите в нее.", + font_location = "Местонахождение файла шрифта, способного отображать Unicode кодировку, необходимую для вашего языка. Если он не указан, то вы не можете выбрать языки, требующие для отображения больше символов, чем были в оригинальной игре. Например: Русский и Китайский ", + savegames_location = "По умолчанию, папка для сохраненных игр находится вместе с конфигурационным файлом. Если это не удобно, тогда вы можете выбрать любую другую просто перейдя в нее. ", + browse_data = "Указать другое место нахождения файлов Theme Hospital (текущее местоположение: %1%)", + browse = "Просмотр папок", + browse_screenshots = "Указать на другое местоположение папки со скиншотами ( текущее местоположение: %1% ) ", + browse_music = "Укажите друго расположение папки с Музыкой ( текущее местоположение: %1% ) ", + no_font_specified = "Расположение файла со шрифтом ещё не указано!", + not_specified = "Местонахождение папки не определено!", + browse_saves = "Укажите другое местонахождение папки с сохраненными играми ( текущее местоположение: %1% ) ", + default = "Местоположение по-умолчанию", + data_location = "Папка, куда установлена оригинальная Theme Hospital, она необходима для запуска CorsixTH", + }, + customise_window = { + aliens = "К сожалению, пациенты с инопланетной ДНК плохо анимированы поэтому в больницу они приходят только по экстренным случаям. Если вы хотите, чтобы они приходили так же как и обычные пациенты, выключите эту опцию.", + average_contents = "Если вы хотите, чтобы игра запоминала какие дополнительные объекты вы устанавливаете в том или ином кабинете, когда его строите, включите эту опцию.", + back = "Закрыть это меню и вернуться в Главное меню", + movies = "Общий контроль за видеороликами. Это позволит вам отключить все видеоролики.", + fractured_bones = "Из-за плохой анимации, по-умолчанию мы отключили всех пациентов женщин со Сломанными костями. Для того чтобы женщины со сломанными костями приходили в вашу больницу, выключите эту опцию.", + volume = "Если кнопка понижения громкости открывает журнал, включите эту опцию, чтобы изменить горячую клавишу журнала на Shift+C", + intro = "Включить или выключить показ вступительного ролика. Общий контроль за видеороликами должен быть включен, если вы хотить видеть вступление каждый раз, когда запускаете CorsixTH", + paused = "В оригинальном Theme Hospital использовать меню сверху экрана можно было только если поставить игру на паузу. Мы оставили это по-умолчанию и в CorsixTH. Если вы включите эту опцию, то на паузе можно будет делать все что угодно.", + }, + handyman_window = { + happiness = "Счастье", + salary = "Зарплата", + parcel_select = "Корпус, в котором рабочий выполняет свои функции, нажмите, чтобы изменить", + tiredness = "Усталость", + sack = "Уволить", + close = "Закрыть", + face = "Изображение рабочего", + pick_up = "Поднять", + center_view = "Центрировать экран на рабочем", + name = "Имя рабочего", + ability = "Способности", + }, + research_policy = { + research_progress = "Прогресс, необходимый до следующего открытия в этой категории: %1%/%2%", + no_research = "В настоящее время исследований в этой категории не производится", + }, + objects = { + lamp = "Лампа: излучает свет и позволяет персоналу видеть.", + op_sink1 = "33 РАКОВИНА", + litter_bomb = "Заминированное письмо: соботирует работу в больнице конкурента", + x_ray = "27 РЕНТГЕН-АППАРАТ", + projector = "37 ПРОЭКТОР", + radiation_shield = "28 РАДИАЦИОННЫЙ ЩИТ", + entrance_left = "58 ЛЕВАЯ ВХОДНАЯ ДВЕРЬ", + table2 = "12 СТОЛ", + bed2 = "неиспользовалась", + console = "15 КОНСОЛЬ УПРАВЛЕНИЯ", + operating_table = "30 СТОЛ ДЛЯ ОПЕРАЦИЙ", + x_ray_viewer = "29 РЕНТГЕН ЭКРАН", + crash_trolley = "20 КРЭШ-ТЕЛЕЖКИ", + shower = "54 ОБЕЗЗАРАЖИВАЮЩИЙ ДУШ", + electrolyser = "46 ЭЛЕКТРОЛИЗЕР", + hair_restorer = "25 ВОССТАНОВИТЕЛЬ ВОЛОС", + jelly_moulder = "47 РАЗЖЕЛЕИВАТЕЛЬ", + couch = "18 КУШЕТКА", + surgeon_screen = "35 ШИРМА ДЛЯ ОПЕРАЦИЙ", + bed3 = "неиспользовалась", + dna_fixer = "23 ВОССТАНОВИТЕЛЬ ДНК", + chair = "Стул: пациенты сидят на нем и обсуждают свое заболевание.", + cast_remover = "24 УДАЛИТЕРЬ ГИПСА", + entrance_right = "59 ПРАВАЯ ВХОДНАЯ ДВЕРЬ", + cardio = "13 КАРДИО АППАРАТ", + slicer = "26 ЯЗЫКОРЕЗКА", + table1 = "Стол (УДАЛЕН): содержит коллекцию журналов, чтобы занять ожидающих пациентов.", + ultrascanner = "22 АППАРАТ УЗИ", + scanner = "14 СКАНЕР", + op_sink2 = "34 РАКОВИНА", + door = "Дверь: люди могут открывать и закрывать ее много раз.", + swing_door2 = "53 РАСПАШНАЯ ДВУСТВОРЧАТАЯ ДВЕРЬ", + screen = "16 ШИРМА", + gates_of_hell = "48 ВОРОТА В АД", + blood_machine = "42 МАШИНА ДЛЯ ЗАБОРА КРОВИ", + comfortable_chair = "61 КОМФОРТНЫЙ СТУЛ", + swing_door1 = "52 РАСПАШНАЯ ДВУСТВОРЧАТАЯ ДВЕРЬ", + }, } misc = { hospital_open = "Открыть больницу", @@ -293,9 +528,12 @@ dialog_missing_graphics = "Сожалеем, но файлы демо версии не содержат этот диалог.", maximum_screen_size = "Максимальный размер экрана не должен превышать 3000x2000.", load_prefix = "Ошибка загрузки игры: ", + no_games_to_contine = "Нет сохраненных игр", save_prefix = "Ошибка сохранения игры: ", map_file_missing = "Не найден файл карты %s для этого уровня!", minimum_screen_size = "Размер экрана не должен быть менее, чем 640x480.", + alien_dna = "Пояснение: не существует анимации как инопланетные пациенты сидят, открывают или стучатся в дверь и т.п. В оригинальной Theme Hospital они при этом превращались в обычного пациента и потом обратно. пациенты с инопланетной ДНК будут доступны только если они разрешены в файле с уровнем.", + fractured_bones = "Пояснение: анимация пациентов со сломанными костями женского пола плохая", } -- 3. Отчеты @@ -303,6 +541,7 @@ morale = "Мораль", tiredness = "Бодрость", skill = "Компетентность", + total_wages = "ВСЕГО ЗАРПЛАТЫ", } bank_manager = { current_loan = "Текущий заем", @@ -342,6 +581,22 @@ machine_replacement = "Замена машины", build_room = "Постройка", drinks = "Продажа напитков", + cure = "Вылечено", + eoy_bonus_penalty = "Призы/Наказания в конце года", + cheat = "Чит с деньгами", + general_bonus = "Оплата Главной премии", + emergency_bonus = "Оплата премии за Экстренные случаи", + epidemy_coverup_fine = "Штраф за сокрытие эпидемий", + research_bonus = "Премия исследований", + final_treat_colon = "Окончательное лечение: ", + jukebox = "Входящее: музыкальный автомат", + vaccination = "Вакцинация", + vip_award = "Денежная премия от ВИП", + epidemy_fine = "Штраф за эпидемию", + compensation = "Компенсация от Правительства", + deposit = "Депозит на лечение", + advance_colon = "Дополнительно: ", + overdraft = "Проценты по кредиту", } town_map = { number = "Номер участка", @@ -350,6 +605,7 @@ for_sale = "Продается", owner = "Владелец уч-ка", area = "Площадь уч-ка", + chat = "Окно детализации города", } high_score = { categories = { @@ -359,7 +615,18 @@ cures = "Пациентов вылечено", visitors = "Количество посетителей", salary = "Размер зарплаты", - }, + clean = "Чистота", + patient_happiness = "Удовлетворенность пациентов", + cure_death_ratio = "Соотношение убитых и вылеченных", + staff_happiness = "Удовлетворенность персонала", + staff_number = "Самое большое количество персонала", + }, + player = "ИГРОК", + pos = "ПОЗ", + best_scores = "ЗАЛ СЛАВЫ", + killed = "Убито", + worst_scores = "ЗАЛ ПОЗОРА", + score = "ОЧКИ", } research = { allocated_amount = "Распределенное количество", @@ -394,6 +661,17 @@ cure = "Лекарство", cured = "Вылечено", earned_money = "Денег получено", + cure_desc = { + hire_surgeons = "Вам необходимо нанять хирургов.", + improve_cure = "Улучшить лечение.", + no_cure_known = "Нет известного лечения.", + build_room = "Я рекомендую вам построить %s", + hire_psychiatrists = "Вы должны нанять психиатра.", + build_ward = "Вам по прежнему нужно построить Палату.", + hire_nurses = "Вам нужно нанять медсестер.", + cure_known = "Вылечен.", + hire_doctors = "Вам нужно нанять докторов.", + }, } progress_report = { quite_unhappy = "Люди вами недовольны", @@ -404,6 +682,7 @@ too_hot = "Настройте систему отопления, у вас слишком жарко", percentage_pop = "Доля клиентов", win_criteria = "Условия для победы", + free_build = "Свободное строительство", } tooltip = { staff_list = { @@ -646,6 +925,13 @@ dna_fixer = "Исправитель ДНК", x_ray = "Рентген", cabinet = "Картотека", + lamp = "Лампа", + entrance_left = "Левая входная дверь", + table2 = "Стол", + bed2 = "Кровать", + bed3 = "Кровать", + entrance_right = "Правая входная дверь", + table1 = "Стол", } room_descriptions = { gp = { @@ -764,6 +1050,9 @@ [2] = "Пациенты, подвергшиеся воздействию радиации, незамедлительно направляются в комнату обеззараживания. Приятный душ смоет с них всю ужасную радиацию и опасные отходы.//", [3] = "Оперировать душем может любой доктор. Также, машине требуется обслуживание.", }, + tv_room = { + [1] = "Телевизионная комната не использовалась", + }, } place_objects_window = { place_objects_in_corridor = "Разместите эти предметы в коридорах.", @@ -771,12 +1060,15 @@ confirm_or_buy_objects = "Вы можете добавить, убрать или передвинуть объекты.", drag_blueprint = "Растяните комнату до желаемого размера.", place_door = "Разместите дверь", + place_objects = "Выберите объект и переместите его на нужное место, потом подтвердите", + pick_up_object = "Нажмите на объект, чтобы его поднять или выберете другую опцию из списка", } staff_class = { doctor = "Доктор", handyman = "Рабочий", receptionist = "Регистратор", nurse = "Медсестра", + surgeon = "Хирург", } staff_descriptions = { good = { @@ -1002,6 +1294,8 @@ sack_staff = "Вы правда хотите уволить этого сотрудника?", replace_machine = "Вы правда хотите заменить %s за %d$?", restart_level = "Вы серьёзно хотите начать уровень заново?", + maximum_screen_size = "Разрешение экрана, которое вы ввели, больше 3000 x 2000. Большее разрешение возможно, но оно может потребовать более производительного оборудования, чтобы поддерживать играбельную частоту кадров. Вы уверены, что хотите продолжить?", + music_warning = "Перед тем, как выбрать mp3 в качестве игровой музыки, вам потребуется smpeg.dll или аналог для вашей операционной системы, иначе музыка не сможет быть проиграна. Вы уверены, что хотите продолжить?", } pay_rise = { definite_quit = "Я увольняюсь, и точка. Я сыт по горло этим местом.", @@ -1246,6 +1540,12 @@ name = "Хроническое носоволосение", symptoms = "Симптомы - нособорода, в которой можно свить гнездо.", }, + pregnancy = { + cure = "Вылечено - ребенка достали в Операционной, отмыли и познакомили с пациентом.", + cause = "Причина - отключение электричества в жилых районах.", + name = "Беременность", + symptoms = "Симптомы - странное питание с последующей непроходимостью кишечника.", + }, } -- 6. Факсы @@ -1312,6 +1612,11 @@ [2] = "Никогда не видел больницы хуже. Какой позор!", [3] = "Я потрясен. Это нельзя назвать больницей! Мне надо выпить.", }, + free_build = { + [1] = "У вас очень милая больница. Не сложно будет заставить ее работать без ограничений по деньгам, правда?", + [2] = "Я не экономист, но я думаю что я тоже смогу управлять этой больницей. Если понимаете о чем это я...", + [3] = "Отлично работающая больница. Берегитесь кризисов! Хотя... вам тут не о чем беспокоиться.", + }, }, rep_boost = "Ваша репутация улучшилась.", vip_remarked_name = "После посещения вашей больницы, %s заметил:", @@ -1322,6 +1627,11 @@ -- Болезни disease_discovered = { discovered_name = "Ваша команда обнаружила новое заболевание. Это %s", + can_cure = "Вы можете вылечить эту болезнь.", + close_text = "Новое состояние было обнаружено.", + need_to_build = "Вы должны построить %s чтобы вылечить это.", + need_to_build_and_employ = "Если вы построите %s и наймете %s то сможете преуспеть.", + need_to_employ = "Наймите %s для того чтобы справиться с этим кризисом.", }, disease_discovered_patient_choice = { need_to_build = "Для лечения нам потребуется %s.", @@ -1373,12 +1683,33 @@ cure_not_possible_build = "Вам надо будет построить %s", cure_not_possible_build_and_employ = "Вам надо будет построить %s и нанять %s", bonus = "Вознаграждение за помощь составит %d. Если вы не справитесь, ваша репутация серьезно пострадает.", + free_build = "Если вы преуспеете, то ваша репутация повысится, если облажаетесь, то она будет серьезно подпорчена.", + num_disease_singular = "Тут 1 пациент с %s и они требуют немедленого внимания.", }, emergency_result = { earned_money = "Из всей суммы %d$ вы заработали %d$.", close_text = "Нажмите чтобы закрыть.", saved_people = "Вы спасли %d из %d человек.", }, + choices = { + return_to_main_menu = "Вернуться в главное меню", + accept_new_level = "Перейти к следующему уровню", + decline_new_level = "Продолжить играть ещё некоторое время", + }, + debug_fax = { + text2 = "ВСЕГО ЛЮДЕЙ В БОЛЬНИЦЕ %d ПРОВЕРЕНО %d", + text7 = "РЕПУТАЦИЯ: %d ОЖИДАЕТСЯ %d СНИЖЕНИЕ %d", + text9 = "КАТАСТРОФЫ %d РАЗРЕШЕНЫ (MTHS) %d (%d)СНИЖЕНИЕ %d", + text4 = "ФАКТОРЫ : ДОКТОРА %d МЕДСЕСТРЫ %d ТЕРРИТОРИЯ %d КАБИНЕТ %d СТОИМОСТЬ %d", + text1 = "ЛУЧШИЙ СЧЕТ %d", + text6 = "СЛЕДУЮЩИЕ ФАКТОРЫ ТАК ЖЕ ПРИМЕНЕНЫ", + close_text = "Да, Да, Да!", + text3 = "КОЛИЧЕСТВА : ДОКТОРА %d МЕДСЕСТРЫ %d ТЕРРИТОРИЯ %d КАБИНЕТЫ %d СТОИМОСТЬ %d", + text5 = "CONTRIBN : ДОКТОРА %d МЕДСЕСТРЫ %d ТЕРРИТОРИЯ %d КАБИНЕТЫ %d СТОИМОСТЬ %d ПРОЦЕНТ(ОВ)", + text8 = "AMENITIES %d PEEPS HANDLED %d REDUCTION %d", + text10 = "УБИЙСТВА %d ДОПУЩЕНО (MTHS) %d (%d) СНИЖЕНИЕ %d", + text11 = "пациентОВ В ЭТОМ МЕСЯЦЕ %d", + }, } -- 7. Советчик @@ -1392,7 +1723,7 @@ hire_receptionist = "А еще вам понадобится регистратор, чтобы принимать новых посетителей.", select_receptionists = "Нажмите мигающую кнопку, чтобы просмотреть регистраторов, которые ищут работу. Число на кнопке показывает, сколько кандидатур доступно.", next_receptionist = "Это резюме первой регистраторши в нашем списке. Нажмите мигающую кнопку, чтобы посмотреть следующее.", - prev_receptionist = "Нажмите мигающую кнопку, чтобы вернуться к предыдущему резюме.", + prev_receptionist = "Нажмите мигающую кнопку, чтобы вернуться к предыдущему резюме.", choose_receptionist = "Выберите регистратора, чьи профессиональные способности и зарплата вас устраивают и нажмите мигающую кнопку чтобы нанять ее.", receptionist_invalid_position = "Здесь ее поставить нельзя.", place_receptionist = "Поставьте вашу новую регистраторшу, где хотите. Она достаточно умна, чтобы добраться до своего стола.", @@ -1416,6 +1747,9 @@ choose_doctor = "Как следует изучите резюме и рекомендации кандидатов прежде чем сделаете выбор.", place_doctor = "Поставьте доктора где-нибудь в пределах больницы. Он направится в кабинет терапевта, когда к вам придет первый пациент.", doctor_in_invalid_position = "Эй! Тут его поставить нельзя.", + start_tutorial = "Прочитайте ваше задание а потом нажмите левую кнопку мыши, чтобы начать обучение.", + room_too_small_and_invalid = "Кабинет слишком маленький, да еще размещен в недопустимом месте.", + build_pharmacy = "Поздравляем! Теперь постройте Аптеку и наймите Медсестру, чтобы у вас получилась работающая больница.", }, epidemic = { hurry_up = "Если что-то не сделать с этой эпидемией, мы окажемся в беде по самые ноздри. Шевелитесь!", @@ -1465,6 +1799,11 @@ receptionists_only_at_desk = "Регистраторы могут работать только в регистратуре.", only_psychiatrists = "В психиатрии могут работать только доктора с дипломом психиатра.", only_surgeons = "Только хирурги могут работать в операционной.", + only_doctors_in_room = "Только Доктора могут работать в %s", + only_nurses_in_room = "Только Медсестры могут работать в %s", + nurses_cannot_work_in_room = "Медсестры не могут работать в %s", + only_researchers = "Доктора могут работать в кабинете исследователей, только если у них есть квалификация исследователя.", + doctors_cannot_work_in_room = "Доктора не могут работать в %s", }, room_forbidden_non_reachable_parts = "Так вы заблокируете доступ к другим частям больницы.", research = { @@ -1472,6 +1811,10 @@ drug_fully_researched = "Вы исследовали %s на 100%.", new_machine_researched = "Изобретена новая %s.", drug_improved = "Исследовательский отдел улучшил ваше лекарство от %s.", + drug_improved_1 = "%s лекарство было улучшенно в вашем Департаменте Исследований.", + new_available = "Новый %s стал доступен.", + new_drug_researched = "Было исследовано новое лекарство для лечения %s ", + autopsy_discovered_rep_loss = "О вашей машине Автоматического Вскрытия стало известно. Ждите негативную реакцию общественности.", }, boiler_issue = { minimum_heat = "Я вас везде ищу! Паровой котел в подвале развалился. Скоро у нас в больнице станет весьма прохладно.", @@ -1578,6 +1921,32 @@ patients_really_thirsty = "Пациенты очень хотят пить. Поставьте ваши торговые автоматы туда, где самые длинные очереди.", some_litter = "Дайте рабочим указание прибраться в больнице, пока проблема с мусором не разрослась.", patients_annoyed = "Люди терпеть не могут вашу больницу, и я не могу их винить за это. Разберитесь с вашими проблемами, или будет хуже!", + doctor_crazy_overwork = "О Нет! Один из ваших докторов стал безумным из-за переработки! Он может вернуться в норму, если вы немедленно отправите его отдыхать.", + no_desk_7 = "Вы построили регистратуру, как насчет нанять регистратора? Запомните, у вас не будет никаких пациентов, пока вы с этим не разберетесь!", + researcher_needs_desk_1 = "Исследователю нужен стол, чтобы на нем работать.", + no_desk_3 = "Это просто необыкновенно, прошел почти года, а вы так и не наняли регистратора! Как вы расчитываете получить пациентов? Теперь разберитесь с этим и прекратите заниматься ерундой.", + no_desk_6 = "У вас нанят регистратор, теперь как насчет построить для нее Регистратуру?", + no_desk_1 = "Если вы хотите, чтобы пациенты приходили в вашу больницу, вам следует построить Регистратуру и нанять регистратора, чтобы в ней работать.", + falling_5 = "Это не место, чтобы выпинывать из него людей! Они больны, знаете ли!", + no_desk = "Вам следует построить Регистратуру и нанять регистратора, наконец!", + no_desk_2 = "Классно сработано! Это должно быть мировой рекорд: почти год и ни одного пациента! Если вы и дальше хотите управлять этой больницей вам нужно построить Регистратуру и нанять регистратора для работы в ней.", + cannot_afford = "У вас недостаточно денег, чтобы нанять этого человека!", + research_screen_open_1 = "Для доступа к разделу исследований, сначала нужно построить Исследовательский кабинет.", + nurse_needs_desk_1 = "Каждой медсестре нужен собственный стол для работы.", + researcher_needs_desk_2 = "Ваш исследователь благодарее вам, что вы разрешили сделать ему перерыв. Если вы намереваетесь иметь больше сотрудников для исследований, то каждому из них нужно купить персональный стол для работы.", + research_screen_open_2 = "Исследования отключены на этом уровне.", + falling_1 = "Эээй! это не смешно! Смотри куда кликаешь мышью, кое-кто может и пострадать!", + receptionists_tired2 = "Ваши регистраторы очень устали. Дайти ем отдохнуть немедленно!", + falling_3 = "Ауч, это было больно, кто-нибудь вызовите доктора!", + no_desk_5 = "Что ж, это вопрос времени, следует подождать и пациенты скоро начнуть приходить!", + no_desk_4 = "Регистратору нужен собственных стол, чтобы приветствовать пациентов, когда они заходят", + falling_2 = "Хватит заниматься ерундой! Как вам это нравится?", + researcher_needs_desk_3 = "Каждому исследователю нужен собственный стол для работы.", + cannot_afford_2 = "У вас недостаточно денег в банке, чтобы сделать эту покупку!", + falling_6 = "Это не боулинг, с больными людьми нельзя обращаться подобным образом!", + nurse_needs_desk_2 = "Ваша Медсестра очень благодарна, что вы разрешили ей отдохнуть. Если вам нужно чтобы в Палате работало больше 1 медсестры купите каждой отдельный стол.", + receptionists_tired = "Ваши регистраторы очень устали. Немедленно отправте их отдыхать.", + falling_4 = "Это больница, а не Парк Развлечений!", }, placement_info = { door_cannot_place = "Извините, тут дверь проделать нельзя.", @@ -1587,6 +1956,11 @@ room_cannot_place_2 = "Тут кабинет не поместится.", window_cannot_place = "Здесь нельзя сделать окно.", reception_cannot_place = "Регистратура сюда не встанет.", + reception_can_place = "Вы можете установить регистратуру здесь.", + window_can_place = "Вы можете расположить окно тут. Оно прекрасно.", + door_can_place = "Вы можете расположить дверь тут, если хотите.", + object_can_place = "Вы можете поставить этот объект здесь.", + staff_can_place = "Вы можете разместить этого сотрудника тут. ", }, information = { larger_rooms = "Большие кабинеты повышают самооценку и производительность людей, которые в них работают.", @@ -1612,6 +1986,10 @@ machine_needs_repair = "Одна из ваших машин требует ремонта. Найдите дымящуюся машину и щелкните на ней. Затем нажмите кнопку вызова рабочего.", increase_heating = "Пациенты замерзают. Увеличьте нагрев в окне карты.", first_VIP = "Скоро вас посетит с экскурсией какая-то большая шишка. Постарайтесь, чтобы он не заметил антисанитарии и недовольных пациентов.", + psychiatric_symbol = "Доктора, разбирающиеся в вопросах психиатрии, оборзначены символом: |", + research_symbol = "Доктора, умеющие проводить исследования, обозначены символом: }", + surgeon_symbol = "Доктора, кто может проводить операции, обозначены симвовом: {", + autopsy_available = "Исследована машина для автоматического вскрытия. С ее помощью вы можете избавляться от проблемных или нежелательных пациентов и проводить исследования над их останками. Но предупреждаем, что использование этой машины - это крайне спорная практика.", }, patient_leaving_too_expensive = "Пациент ушел, не заплатив за %s. Для него это слишком дорого.", vip_arrived = "Внимание! %s прибыл в вашу больницу с официальным визитом! Проследите, чтобы все прошло как по маслу.", @@ -1621,131 +1999,160 @@ place_windows = "Дополнительные окна делают комнаты светлее, а персонал - счастливее.", fax_received = "Значок, который сейчас вылез слева внизу экрана сообщает вам что-то важное или требует ваше решение по какому-либо вопросу.", }, + competitors = { + staff_poached = "Один из сотрудников вашей больницы перешел на работу в другой госпиталь.", + land_purchased = "%s купил участок земли.", + hospital_opened = "%s открыл конкурирующую больницу.", + }, + praise = { + many_benches = "пациентам достаточно мест для седения. Прекрасно.", + few_have_to_stand = "Очень немногим приходится стоять в вашей больнице. пациенты благодарны вам за это.", + plenty_of_benches = "Тут есть много скамеек, так что это не проблема.", + plants_thriving = "Очень хорошо. Ваши растения просто процветают. Они выглядят чудесно. Поддерживайте их и вы можете выйграть за них приз.", + plants_are_well = "Мило. Вы хорошо заботитесь о своих растениях.", + many_plants = "Прекрасно. У вас есть много растений. пациенты будут благодарны за это.", + patients_cured = "%d пациентов вылечено." + }, + build_advice = { + placing_object_blocks_door = "Расположение этого объета здесь не позволит людям входить в дверь.", + door_not_reachable = "Люди не слогут входить в эту дверь. Подумайте об этом.", + blueprint_would_block = "Такая планировка будет блокировать другие комнаты. Попробуйте изменить размер комнаты или переместить ее в другое место!", + blueprint_invalid = "Это не допустимая планировка.", + }, + multiplayer = { + poaching = { + not_interested = " Ха! Им не интересно работать на вас - они счастливы на своем месте.", + already_poached_by_someone = "Невозможно! Кто-то уже пытается переманить этого человека.", + in_progress = "Я дам вам знать когда этот человек захочет перейти работать на вас.", + }, + players_failed = "Нижеследующим игрокам не удалось достичь последней цели : ", + everyone_failed = "Всем не удалось достичь последней цели. Поэтому каждый может поиграть на !", + }, + cheats = { + bloaty_cheat = "Обман Надутой головы активирован!", + th_cheat = "Поздравляем, вы разблокировали обманки!", + hairyitis_cheat = "Обман Оволосителя активирован!", + crazy_on_cheat = "О нет! Все доктора сошли с ума!", + roujin_off_cheat = "Состязание Roujin'а деактивировано.", + crazy_off_cheat = "Уффф... врачи восстановили свое здравомыслие.", + hairyitis_off_cheat = "Обман Оволосителя деактивирован.", + roujin_on_cheat = "Состязание Roujin'а активировано! Удачи...", + bloaty_off_cheat = "Обман Надутой головы деактивирован.", + }, } -- 8. Письма из министерства introduction_texts = { - level1 = { - [1] = "Добро пожаловать в вашу первую больницу!//", - [2] = "Чтобы начать принимать пациентов, постройте регистратуру и кабинет терапевта, наймите регистраторшу и доктора. ", - [3] = "Потом просто ждите когда придут первые пациенты.", - [4] = "Также, вам не помешает построить кабинет психиатра и нанять доктора с соответствующим дипломом. ", - [5] = "Чтобы лечить больных, вам потребуется аптека и медсестра. ", - [6] = "Приготовьтесь принимать пациентов с раздутой головой. Для них надо будет построить кабинет со специальной машиной. ", - [7] = "Попробуйте вылечить 10 человек и смотрите, чтобы ваша репутация не упала ниже 200.", - }, - level2 = { - [1] = "В этой местности встречается больше разных заболеваний. ", - [2] = "Подготовьте больницу к наплыву пациентов и не забудьте построить исследовательский отдел. ", - [3] = "Очень важно поддерживать ваше заведение в чистоте и стараться повысить свою репутацию. Ожидайте прибытия пациентов с длинными языками - постройте для них специальный кабинет. ", - [4] = "Комната кардиографии поможет вам точнее ставить диагнозы. ", - [5] = "Оба этих кабинета должны быть исследованы прежде, чем вы сможете их построить. В окне карты вы теперь можете приобретать дополнительные корпуса для вашей больницы. ", - [6] = "Ваша цель - заработать 10 000$, вылечить 40 человек и не уронить репутацию ниже 300.", - }, - level3 = { - [1] = "На этот раз ваша больница будет расположена в богатом районе. ", - [2] = "Министерство здравоохранения ожидает получить здесь нехилую прибыль. ", - [3] = "Для начала, вам предстоит заработать хорошую репутацию, затем сосредоточтесь на превращении ее в деньги. ", - [4] = "Знайте, что вы можете столкнуться с чрезвычайными ситуациями. ", - [5] = "Это означает, что к вам в больницу прибудет группа людей с серьезным заболеванием. ", - [6] = "Если вы успеете их вылечить за ограниченное время, то заработаете солидный бонус и хорошую репутацию. ", - [7] = "Вам придется столкнуться с синдромом Короля, а также выделить деньги на постройку палаты и операционной. ", - [8] = "Заработайте 20 000$ чтобы добиться успеха.", - }, - level4 = { - [1] = "Проследите, чтобы пациенты были довольны, хорошо обслужены и не умирали.", - [2] = "Ваша репутация имеет большое значение, так что постарайтесь поднять ее как можно выше.", - [3] = "Не беспокойтесь о деньгах - они придут вместе с высокой репутацией.", - [4] = "Теперь вы также можете обучать ваших докторов, чтобы повысить их навыки.", - [5] = "Так они смогут справляться даже с самыми необчными болезнями.", - [6] = "Поднимите вашу репутацию до 500.", - }, - level5 = { - [1] = "С таким разнообразием заболеваний, как в этой больнице, вам не придется сидеть без дела.", - [2] = "Ваши доктора - вчерашние студенты, так что им необходимо будет подучиться.", - [3] = "У вас есть три консультанта, которые помогут обучить новичков, постарайтесь их не разозлить.", - [4] = "А еще наша больница стоит прямо над разломом Сан Андроид.", - [5] = "Ожидайте землетрясений.", - [6] = "Они могут повредить ваши машины и нарушить работу больницы.", - [7] = "Поддерживайте репутацию не ниже 400 и заработайте 50 000$. Также, вылечите 200 пациентов.", - }, - level6 = { - [1] = "Опираясь на весь свой опыт, постройте хорошо организованную больницу, приносящую стабильный доход и способную вылечить все, что угодно.", - [2] = "Знайте, что в этой местности особенно быстро распространяются всякие инфекции.", - [3] = "Если в вашей больнице не будет идеально чисто, ждите вспышек эпидемий среди пациентов.", - [4] = "Заработайте 150 000$ и доведите стоимость больницы до 140 000$.", - }, - level7 = { - [1] = "Здесь вы будете под неусыпным наблюдением министерства здравоохранения, так что постарайтесь, чтобы деньги текли рекой, а репутация стремилась ввысь. ", - [2] = "Мы не можем вам позволить убивать пациентов - это плохо для бизнеса. ", - [3] = "Проследите, чтобы у вас было все необходимое оборудование и высококлассные специалисты. ", - [4] = "Заработайте 600 репутации плюс 200 000$ на банковский счет.", - }, - level8 = { - [1] = "Ваша задача - построить как можно более эффективную и рентабельную больницу. ", - [2] = "Народ здесь живет на широкую ногу, так что не стесняйтесь стричь капусту изо всех сил. ", - [3] = "Нет, конечно, лечить людей - хорошо, и все такое, но вам ОЧЕНЬ нужны их деньги. ", - [4] = "Проследите, чтобы ваши пациенты были в состоянии дойти до кассы. ", - [5] = "Накопите на счету, ни много ни мало, 300 000$ чтобы завершить этот уровень.", - }, - level9 = { - [1] = "Теперь, когда на счету министерства полно денег, и сам министр разъезжает на новеньком лимузине, вы вновь можете заняться постройкой приличной, хорошо организованной больницы для самых нуждающихся. ", - [2] = "Будьте готовы к любым неприятностям.", - [3] = "Если вы озаботитесь приобретением всего необходимого оборудования и кадров, ничто не сможет причинить вам проблем. ", - [4] = "Ваша больница должна стоить 200 000$, а на вашем счету должно быть 400 000$. ", - [5] = "Мы не примем меньшего.", - }, - level10 = { - [1] = "Помимо излечения всех болезней, которые бывают в этом захолустье, министерство просит вас уделить внимание исследованию лекарств.", - [2] = "К нам поступают жалобы от некоего Овсика, местного активиста, так что улучшайте свои лекарства, чттобы не ударить в грязь лицом.", - [3] = "Также, не давайте поводов для упреков. Сведите число трупов к минимуму.", - [4] = "Кстати, отведите место для кабинета лечения ожеления.", - [5] = "Улучшите все лекарства до 80% эффективности, повысьте репутацию до 650 и соберите 500 000$.", - }, - level11 = { - [1] = "Вам предоставляется шанс построить идеальную больницу. ", - [2] = "Это невероятно престижное место, и министерство хотело бы видеть здесь соответствующее лечебное учреждение. ", - [3] = "Мы ожидаем от вас большой прибыли, высокой репутации и использования всех возможных средств для достижения цели. ", - [4] = "Это очень важная работа. ", - [5] = "Чтобы ее выполнить, вам придется лезть из кожи вон. ", - [6] = "Кстати, в этой местности замечены НЛО. Интересно, ваш персонал готов к подобным сюрпризам? ", - [7] = "Доведите стоимость больницы до $240,000, соберите $500,000 и поднимите репутацию до 700.", - }, - level12 = { - [1] = "Эта задача - вершина всех задач. ", - [2] = "Восхищенное вашим успехом, министерство предлагает вам сложную работу: им нужен кто-то, кто построит еще одну идеальную больницу, принесет огромное количество денег и заработает невероятную репутацию. ", - [3] = "От вас ожидается, что вы скупите всю землю в округе, вылечите всех (да-да, именно всех) и получите все награды. ", - [4] = "Возьметесь за дело?", - [5] = "Заработайте $650,000, вылечите 750 человек и ваша репутация не должна быть ниже 800, чтобы выиграть.", - }, - level13 = { - [1] = "Ваше невероятное мастерство владения больницей заинтересовало сверхсекретный отдел сверхсексретной службы. ", - [2] = "У них есть для вас сюрприз: переполненная крысами больница требует эффективного вмешательства. ", - [3] = "Уничтожьте как можно больше крыс, пока рабочие не убрали весь мусор. ", - [4] = "Справитесь?", - }, - level14 = { - [1] = "Перед вами очередное задание: эта больница богата разного рода неожиданностями. ", - [2] = "Приведите ее к успеху и станьте победителем из победителей. ", - [3] = "Не думайте, что все будет очень легко. Перед вашим лицом предстанут весьма жесткие условия ", - [4] = "Удачи!", - }, - level15 = { - [1] = "Итак, освоим важные моменты для создания хорошей больницы.//", - [2] = "Иногда вашим врачам требуется помощь в постановке правильного диагноза. Для дополнительных обследований ", - [3] = "необходимо построить специальные кабинеты, например, кабинет общей диагностики.", - }, - level16 = { - [1] = "Вы уже поставили диагнозы нескольким пациентам, и пора приниматься за их лечение. Для этого необходимо построить различные кабинеты. ", - [2] = "Для начала постройте аптеку и наймите медсестру, которая будет выдавать пациентам спасительные лекарства.", - }, - level17 = { - [1] = "Последнее предупреждение: зорко следите за репутацией, ведь именно она привлекает к вам пациентов из самых дальних уголков страны, а соответственно и их деньги. ", - [2] = "Если вы не будете убивать много людей и они будут довольны вашей больницей, особых проблем у вас не возникнет.//", - [3] = "Теперь вы сами себе хозяин. Удачи! На этом все.", - }, - level18 = { - }, + demo = + "Добро пожаловать в демонстрационную больницу!//" .. + "К сожалению демонстрационная версия содержит только этот уровень. Но этого более чем достаточно, чтобы занять вас на некоторое время! " .. + "Вы будете сталкиваться с разными заболеваниями, которые будет требовать разных кабинетов для лечения. Время от времени, будут поступать пациенты, требующие немедленного лечения. Так же вам необходимо разрабатывать новые кабинеты используя исследовательский кабинет. " .. + "Ваша цель заработать $100 000, стоимость больницы должна быть $70 000, а репутация 700. Кроме того, вы должны вылечивать не менее 75% своих пациентов. " .. + "Удостоверьтесь, что ваша репутация не упадет ниже 300 и вы не убиваете более 40% ваших пациентов. Иначе вы проиграете.//" .. + "Удачи!", + level1 = + "Добро пожаловать в вашу первую больницу!//" .. + "Чтобы начать принимать пациентов, постройте регистратуру и кабинет терапевта, наймите регистраторшу и доктора. " .. + "Потом просто ждите когда придут первые пациенты." .. + "Также, вам не помешает построить кабинет психиатра и нанять доктора с соответствующим дипломом. " .. + "Чтобы лечить больных, вам потребуется аптека и медсестра. " .. + "Приготовьтесь принимать пациентов с раздутой головой. Для них надо будет построить кабинет со специальной машиной. " .. + "Попробуйте вылечить 10 человек и смотрите, чтобы ваша репутация не упала ниже 200.", + level2 = + "В этой местности встречается больше разных заболеваний. " .. + "Подготовьте больницу к наплыву пациентов и не забудьте построить исследовательский отдел. " .. + "Очень важно поддерживать ваше заведение в чистоте и стараться повысить свою репутацию. Ожидайте прибытия пациентов с длинными языками - постройте для них специальный кабинет. " .. + "Комната кардиографии поможет вам точнее ставить диагнозы. " .. + "Оба этих кабинета должны быть исследованы прежде, чем вы сможете их построить. В окне карты вы теперь можете приобретать дополнительные корпуса для вашей больницы. " .. + "Ваша цель - заработать 10 000$, вылечить 40 человек и не уронить репутацию ниже 300.", + level3 = + "На этот раз ваша больница будет расположена в богатом районе. " .. + "Министерство здравоохранения ожидает получить здесь нехилую прибыль. " .. + "Для начала, вам предстоит заработать хорошую репутацию, затем сосредоточтесь на превращении ее в деньги. " .. + "Знайте, что вы можете столкнуться с чрезвычайными ситуациями. " .. + "Это означает, что к вам в больницу прибудет группа людей с серьезным заболеванием. " .. + "Если вы успеете их вылечить за ограниченное время, то заработаете солидный бонус и хорошую репутацию. " .. + "Вам придется столкнуться с синдромом Короля, а также выделить деньги на постройку палаты и операционной. " .. + "Заработайте 20 000$ чтобы добиться успеха.", + level4 = + "Проследите, чтобы пациенты были довольны, хорошо обслужены и не умирали. " .. + "Ваша репутация имеет большое значение, так что постарайтесь поднять ее как можно выше. " .. + "Не беспокойтесь о деньгах - они придут вместе с высокой репутацией. " .. + "Теперь вы также можете обучать ваших докторов, чтобы повысить их навыки. " .. + "Так они смогут справляться даже с самыми необчными болезнями. " .. + "Поднимите вашу репутацию до 500.", + level5 = + "С таким разнообразием заболеваний, как в этой больнице, вам не придется сидеть без дела." .. + "Ваши доктора - вчерашние студенты, так что им необходимо будет подучиться." .. + "У вас есть три консультанта, которые помогут обучить новичков, постарайтесь их не разозлить." .. + "А еще наша больница стоит прямо над разломом Сан Андроид." .. + "Ожидайте землетрясений." .. + "Они могут повредить ваши машины и нарушить работу больницы." .. + "Поддерживайте репутацию не ниже 400 и заработайте 50 000$. Также, вылечите 200 пациентов.", + level6 = + "Опираясь на весь свой опыт, постройте хорошо организованную больницу, приносящую стабильный доход и способную вылечить все, что угодно." .. + "Знайте, что в этой местности особенно быстро распространяются всякие инфекции." .. + "Если в вашей больнице не будет идеально чисто, ждите вспышек эпидемий среди пациентов." .. + "Заработайте 150 000$ и доведите стоимость больницы до 140 000$.", + level7 = + "Здесь вы будете под неусыпным наблюдением министерства здравоохранения, так что постарайтесь, чтобы деньги текли рекой, а репутация стремилась ввысь. " .. + "Мы не можем вам позволить убивать пациентов - это плохо для бизнеса. " .. + "Проследите, чтобы у вас было все необходимое оборудование и высококлассные специалисты. " .. + "Заработайте 600 репутации плюс 200 000$ на банковский счет.", + level8 = + "Ваша задача - построить как можно более эффективную и рентабельную больницу. " .. + "Народ здесь живет на широкую ногу, так что не стесняйтесь стричь капусту изо всех сил. " .. + "Нет, конечно, лечить людей - хорошо, и все такое, но вам ОЧЕНЬ нужны их деньги. " .. + "Проследите, чтобы ваши пациенты были в состоянии дойти до кассы. " .. + "Накопите на счету, ни много ни мало, 300 000$ чтобы завершить этот уровень.", + level9 = + "Теперь, когда на счету министерства полно денег, и сам министр разъезжает на новеньком лимузине, вы вновь можете заняться постройкой приличной, хорошо организованной больницы для самых нуждающихся. " .. + "Будьте готовы к любым неприятностям." .. + "Если вы озаботитесь приобретением всего необходимого оборудования и кадров, ничто не сможет причинить вам проблем. " .. + "Ваша больница должна стоить 200 000$, а на вашем счету должно быть 400 000$. " .. + "Мы не примем меньшего.", + level10 = + "Помимо излечения всех болезней, которые бывают в этом захолустье, министерство просит вас уделить внимание исследованию лекарств." .. + "К нам поступают жалобы от некоего Овсика, местного активиста, так что улучшайте свои лекарства, чттобы не ударить в грязь лицом." .. + "Также, не давайте поводов для упреков. Сведите число трупов к минимуму." .. + "Кстати, отведите место для кабинета лечения ожеления." .. + "Улучшите все лекарства до 80% эффективности, повысьте репутацию до 650 и соберите 500 000$.", + level11 = + "Вам предоставляется шанс построить идеальную больницу. " .. + "Это невероятно престижное место, и министерство хотело бы видеть здесь соответствующее лечебное учреждение. " .. + "Мы ожидаем от вас большой прибыли, высокой репутации и использования всех возможных средств для достижения цели. " .. + "Это очень важная работа. " .. + "Чтобы ее выполнить, вам придется лезть из кожи вон. " .. + "Кстати, в этой местности замечены НЛО. Интересно, ваш персонал готов к подобным сюрпризам? " .. + "Доведите стоимость больницы до $240,000, соберите $500,000 и поднимите репутацию до 700.", + level12 = + "Эта задача - вершина всех задач. " .. + "Восхищенное вашим успехом, министерство предлагает вам сложную работу: им нужен кто-то, кто построит еще одну идеальную больницу, принесет огромное количество денег и заработает невероятную репутацию. " .. + "От вас ожидается, что вы скупите всю землю в округе, вылечите всех (да-да, именно всех) и получите все награды. " .. + "Возьметесь за дело?" .. + "Заработайте $650,000, вылечите 750 человек и ваша репутация не должна быть ниже 800, чтобы выиграть.", + level13 = + "Ваше невероятное мастерство владения больницей заинтересовало сверхсекретный отдел сверхсексретной службы. " .. + "У них есть для вас сюрприз: переполненная крысами больница требует эффективного вмешательства. " .. + "Уничтожьте как можно больше крыс, пока рабочие не убрали весь мусор. " .. + "Справитесь?", + level14 = + "Перед вами очередное задание: эта больница богата разного рода неожиданностями. " .. + "Приведите ее к успеху и станьте победителем из победителей. " .. + "Не думайте, что все будет очень легко. Перед вашим лицом предстанут весьма жесткие условия " .. + "Удачи!", + level15 = + "Итак, освоим важные моменты для создания хорошей больницы.//" .. + "Иногда вашим врачам требуется помощь в постановке правильного диагноза. Для дополнительных обследований " .. + "необходимо построить специальные кабинеты, например, кабинет общей диагностики.", + level16 = + "Вы уже поставили диагнозы нескольким пациентам, и пора приниматься за их лечение. Для этого необходимо построить различные кабинеты. " .. + "Для начала постройте аптеку и наймите медсестру, которая будет выдавать пациентам спасительные лекарства.", + level17 = + "Последнее предупреждение: зорко следите за репутацией, ведь именно она привлекает к вам пациентов из самых дальних уголков страны, а соответственно и их деньги. " .. + "Если вы не будете убивать много людей и они будут довольны вашей больницей, особых проблем у вас не возникнет.//" .. + "Теперь вы сами себе хозяин. Удачи! На этом все.", + level18 = "", } letter = { [1] = { @@ -1933,6 +2340,8 @@ lose_level = "Проиграть Уровень", all_research = "Чит на Все Исследования", end_year = "Закончить Год", + earthquake = "Вызвать землетрясение", + vip = "Вызвать ВИП", }, close = "Закрыть", caption = "Читы", @@ -2357,6 +2766,7 @@ }, custom_game_window = { start_game_with_name = "Загрузить уровень %s", + free_build = "Свободное строительство", }, cheats_window = { close = "Закрыть окно с читами", @@ -2373,6 +2783,8 @@ }, menu_list_window = { back = "Закрыть окно", + save_date = "Измененялось", + name = "Имя", }, watch = { emergency = "Чрезвычайное происшествие: время, оставшееся на лечение срочных пациентов.", @@ -2469,6 +2881,28 @@ } trophy_room = { reputation = "РЕПУТАЦИЯ", + gen_repairs = { + penalty = { + [1] = "Ваши рабочие не обслуживают оборудование должным образом. Вам следует управлять ими рабочими лучше, возможно потребуется нанять больше рабочих, чтобы справиться с нагрузкой.", + [2] = "У вас ужасное обслуживание аппаратов. Ваши сотрудники должны ухаживать за оборудованием клиники быстро и с заботой.", + }, + awards = { + [1] = "Вы удостоены специальной награды для рабочих за поддержание оборудования клиники в хорошем состоянии. Отлично сработано! Устройте себе выходной.", + [2] = "Ваши рабочие справляются лучше своих коллег в других больницах. Это главное достижение, с которым вас стоит поздравить.", + [3] = "Оборудование больницы поддерживается в великолепном состоянии. Усилия ваших рабочих невероятны. Вы все заслуживаете этой престижной награды. Удивительная работа.", + }, + }, + pop_percentage = { + awards = { + [1] = "Заметим, что вы привлекли большую часть населения города в прошлом году. Отлично сработано.", + [2] = "Поздравляем. Более высокая доля местного населения посещает вашу больницу, нежели любую другую.", + [3] = "Превосходно. Вы привлекли в свою больницу больше населения, чем посетило все остальные больницы вместе взятые.", + }, + penalty = { + [1] = "Очень немногие пришли лечиться в вашу больницу в прошлом году. Чтобы заработать денег вам нужны платежеспособные страдальцы.", + [2] = "Через двери любой больницы в этой местности проходит большая доля населения, чем через ваши. Вам должно быть очень стыдно.", + }, + }, happy_vips = { awards = { [1] = "Вы получили Нобелевскую премию за впечатления, произведенное на высокопоставленных особ. Все большие шишки, посещавшие вашу больницу за прошедший год, оценили ее выше всяких похвал.", @@ -2476,6 +2910,18 @@ }, trophies = { [1] = "Клуб Важных Персон вручает вам кубок Популярности за оказанное внимание всем VIP-персонам, посетившим ваше заведение в прошедшем году. Теперь вы можете считать себя немного известнее.", + [2] = "Агентство Известных Людей вручает вам Знаменитую Награду за удовлетворение каждого ВИП, кто посетил ваше предприятие. Считайте себя немного известным, почти одним из нас.", + [3] = "Поздравляем с выигрышем ВИП Путешествия в награду за то что сделали жизнь трудолюбивых людей в глазах общественности лучше, угождая каждому из них, кто посетил вашу больницу. Просто чудесно.", + }, + }, + happy_patients = { + awards = { + [1] = "Вы может быть самодовольны по поводу того, что в прошлом году пациенты были очень довольны находиться в вашей больнице.", + [2] = "Люди, посетившие вашу больницу, в среднем были более довольны своим лечением, нежели в любой другой больнице в игре.", + }, + penalty = { + [1] = "Люди, приходящие в вашу больницу, находят ее ужасной. Вам нужно лучше работать, чтобы заслужить уважение Министерства.", + [2] = "Люди, лечащиеся в вашей больнице, очень недовольны ее состоянием. Вы должны тщательнее следить за состоянием пациента.", }, }, rats_killed = { @@ -2489,12 +2935,23 @@ }, happy_staff = { awards = { + [1] = "Ваши сотрудники номинировали вас на эту награду. Они сказали, что хотя и есть что улучшать, ваша забота о них оставалась, в целом, хорошей.", + [2] = "Ваши сотрудники счастливы работать на вас, у них не сходит улыбка с лица. Вы потрясающий управляющий.", }, trophies = { [1] = "Вы награждены кубком Улыбки за поддержание хорошего настроения ваших тружеников в течении прошедшего года.", [2] = "Институт Вселенского Счастья вручает вам приз за отсутвие в вашем прекрасном заведении несчастных работников в прошедшем году.", [3] = "Эта награда, Сияющий Позолоченный кубок, вручается вам за поддержание в прошедшем году хорошего настроения работников в любой ситуации!", }, + regional_bad = { + [1] = "Ваши сотрудники были очень несчастны в течение прошлого года. Вы должны знать об этом. На самом деле, в любой другой больнице персонал чувствует себя лучше, чем в вашей.", + }, + regional_good = { + [1] = "Ваш персонал счастливее коллег в любой другой больнице. Довольный персонал значит больше прибыль и меньше смертность. Министерство этим довольно.", + }, + penalty = { + [1] = "Ваши сотрудники хотят чтобы было известно о том, что они несчастны. Хороший персонал - это преимущество. Сделайте ваших людей счастливее или однажды вы многое потеряете.", + }, }, rats_accuracy = { awards = { @@ -2517,19 +2974,60 @@ no_deaths = { awards = { [1] = "Поздравляем! Вы получаете орден имени В. Безтрупова за стопроцентное выживание ваших пациентов.", + [2] = "Ваш гейний свел количество смертей в госпитале к минимуму. Вы можете быть очень довольны этим результатом.", }, trophies = { [1] = "Общество Продолжения Жизни вручает вам награду за отсутствие смертей среди пациентов в прошедшем году.", [2] = "Вы награждены кубком Выживания за то, что в прошедшем году сохранили жизни всех своих пациентов. Поразительно!", + [3] = "Вы были награждены Кубком ОСТАТЬСЯ В ЖИВЫХ за то что в этом году избежали смертей среди пациентов в вашей милой больнице. Отлично.", + }, + penalty = { + [1] = "Количество смертей в вашей больнице в прошлом году было непреемлемо высокое. Уделяйте больше времени своей работе. Убедитесь, что в будущем выживет больше людей.", + [2] = "Ваша больница опасна для здоровья пациентов. От вас ждали, что вы будете лечить своих пациентов, а не убивать их.", + }, + regional = { + [1] = "Число погибших в вашей больнице в прошлом году было ниже, чем в любой другой в округе. Пожалуйста, примите эту награду.", }, }, many_cured = { awards = { [1] = "Примите наши поздравления с получением ордена Матери Терезы за большинство вылеченных пациентов в прошедшем году.", + [2] = "Пожалуйста примите эту награду за то что вылечили пациентов больше, чем любая другая больница.", }, trophies = { [1] = "Международная Ассоциация Излечения торжественно вручает вам награду за излечение почти всех пациентов, обратившимся в больницу в прошедшем году.", [2] = "Вы получаете такую ценную награду, как кубок Выживания за невероятно высокий процент вылеченных пациентов вашего заведения за прошедший год.", + [3] = "Вы были представлены к вручению Кубка Gargler за поддержание высокого процента вылеченных людей в прошлом году.", + }, + penalty = { + [1] = "Ваша больница не смогла предоставить эффективное лечение, нуждающимся в нем, пациентам. Сконцентрируйтесь на том, чтобы сделать лечение более эффективным.", + [2] = "Ваша больница наименее эффективная из всех, что касается лечения пациентов. Вы тащите Министерство на дно и сами опускаетесь туда же. Мне больше нечего сказать.", + }, + regional = { + [1] = "Вы представлены к награде за беспрецедентное исцеление. Это за то, что вы вылечили больше пациентов, чем все остальные больницы вместе взятые.", + }, + }, + curesvdeaths = { + awards = { + [1] = "Сердечно поздравляем с достижением впечатляющего соотношения вылеченных к убитым в вашей больнице в прошлом году.", + }, + penalty = { + [1] = "Ваше соотношение вылеченных к убитым крайне плохое. Вы должны быть уверены в том, что вылечите больше людей, чем убьете. Помните - не наоборот.", + }, + }, + emergencies = { + award = { + [1] = "Поздравляем: ваша эффективность и эффективное решение экстренных случаев приносит вам эту особенную награду. Отличная работа!", + [2] = "Вы исключительно хорошо справляетесь с экстренными случаями. Эта награда за то что вы лучше всех справляетесь с большим потоком больных и страждущих.", + }, + regional_good = { + [1] = "Министерство выяснило, что ваша больница в прошлом году справлялась с экстренными случаями лучше чем любая другая. Поэтому оно вручает вам эту награду.", + }, + penalty = { + [1] = "Вы ужасно справляетесь с экстренными пациентами. Прилетающие пациенты для немедленного лечения требуют точного и своевременного внимания, чего вы не смогли им дать.", + }, + regional_bad = { + [1] = "Что касается экстренных случаев с пациентами, ваша больница была самой ужасной в регионе. Это ваша вина в том, что вы томитесь в нижней части местной лиги экстренного лечения.", }, }, high_rep = { @@ -2540,6 +3038,20 @@ trophies = { [1] = "Поздравляем с получением кубка Мегапафоса за достижение такой репутации в прошедшем году. Так держать!", }, + penalty = { + [1] = "Вы были дисциплинированы в поддержании очень плохой репутации на протяжение прошлого года. Убедитесь в том, что она поднимется в будущем.", + [2] = "Репутация вашей больницы самая ужасная в городе. Вы опозорены. Улучшите ее или найдите другую работу.", + }, + regional = { + [1] = "Пожалуйста примите нагдару от Bullfrog за самую высокую репутацию из всех больниц. Наслаждайтесь - вы это заработали.", + [2] = "В этом году, репутация вашей больницы превысила все остальные вместе взятые. Это крупное достижение.", + } + }, + consistant_rep = { + trophies = { + [1] = "Настоящим, вы получаете награду от Кабинета Министров за самые безупречные стандарты и наивысшую репутацию какая только может быть. Хорошо сработано.", + [2] = "Поздравляем с получением Кубка СкуаэкиКлин за лучшую репутацию больницы в прошлом году. Вы это заслужили.", + }, }, sold_drinks = { awards = { @@ -2550,6 +3062,14 @@ [3] = "Позвольте нам, при поддержке кондитерской фабрики «Синий Пролетарий», вручить вам покрытый шоколадом кубок за высокий уровень продаж газированных напитков в прошедшем году.", }, }, + wait_times = { + award = { + [1] = "Поздравляем. В вашей больнице пациенты почти не проводят время в очередях. Это важная награда.", + }, + penalty = { + [1] = "Людям в вашей больнице приходится ждать слишком долго. Здесь всегда непреемлемые очереди. Вы должны управляться с вашими пациентами более эффективно, раз уж за это взялись.", + }, + }, healthy_plants = { awards = { [1] = "Поздравляем! Вы награждены орденом Лопаты и Тяпки за поддержание растений в добром здравии круглый год.", @@ -2559,6 +3079,55 @@ [2] = "Компания «СемеНа, получи» награждает вас премией имени Мичурина в честь своевременного ухода за растениями в прошедшем году.", }, }, + cleanliness = { + regional_good = { + [1] = "Ваша больница была отмечена как одна из самых не прибранных в округе. В грязной больнице опасно и воняет. Вы лучше должны за этим следить.", + }, + award = { + [1] = "Инспекторы отметили, что ваша больница очень чистая. Чистая больница - это безопасная больница. Поддерживайте ее в том же виде.", + }, + regional_bad = { + [1] = "Ваша больница самая грязная в округе. Любой другой управляющий поддерживает свои коридоры более чистыми. Вы - позор медицины!", + }, + }, + hosp_value = { + awards = { + [1] = " Министерство Здравоохранения хочет использовать представившуюся возможность, чтобы поздравить вас с впечатляющей общей стоимостью вашей больницы.", + }, + penalty = { + [1] = "Вашей больнице не удалось достичь достойной стоимости. Вы приняли плохие решения по управлению капиталом. Помните, хорошая больница - это так же дорогая больница.", + }, + regional = { + [1] = "Вы финансовый волшебник. Ваша больница стоить больше чем все остальные вместе взятые.", + }, + }, + best_value_hosp = { + regional = { + [1] = "Поздравляем с владением самой дорогой больницей в игре. Хорошая работа. Постарайтесь сохранить это вдальнейшем.", + }, + penalty = { + [1] = "Любая больница в округе стоит дороже вашей. Сделайте что-нибудь с этой позорной частью дел. Поставте больше дорогого оборудования!", + }, + trophies = { + [1] = "Посздравляем с получением Кубка SqueakiKlean за больницу с лучшей репутацией в прошлом году. Вы это заслужили.", + }, + }, + research = { + regional_good = { + [1] = "Ваши исследователи поддерживали вашу больницу в курсе последних разработок. Ваши исследователи заслужили эту награду. Продолжайте в том же духе!", + }, + regional_bad = { + [1] = "Любая больница в округе продвинулась в исследованиях лучше вашей. Так как исследования критически важны для вашей больницы, то Министерство пребывает в ярости.", + }, + penalty = { + [1] = "Вы били плохи в исследовании новых лекарств оборудования и методов лечения. Это очень плохо. Технологическое превосходство жизненно необходимо.", + }, + awards = { + [1] = "Ваши исследования сохранили вашу больницу в курсе последних событий. Ваш исследовательский персонал заслужил эту награду. Хорошо сработано.", + [2] = "В течение прошлого года вы исследовали больше лекарств и оборудования, чем можно было бы даже надеяться. Пожалуйста примите эту награду от всех нас из Министерства.", + + }, + }, cash = "ДЕНЬГИ", } drug_companies = { @@ -2604,6 +3173,9 @@ [19] = "АМБУЛАНТА", [20] = "АХМЕД", [21] = "МАКСВЕЛ", + [22] = "ДАНИЭЛ", + [23] = "ОЛИВА", + [24] = "НИК", } level_names = { [1] = "Отравинск", @@ -2755,6 +3327,94 @@ }, cannot_restart = "К сожалению, эта пользовательская игра была сохранена до реализации функции перезапуска.", custom_game = "Добро пожаловать в CorsixTH. Развлекайтесь по полной на пользовательской карте!", -} - + very_old_save = "Произошло много улучшений с того момента, как вы в последний раз запускали этот уровень. Чтобы быть уверенным, что все функции работают как положено, пожалуйста перезапустите его.", + cheat_not_possible = "Не могу так жульничать на этом уровне. Вы даже обмануть не можете, не смешно, да?", + no_custom_game_in_demo = "Извините, но в демонстрационной версии вы не можете играть в дополнительные карты.", +} +confirmation.maximum_screen_size = "Размер экрана, введённый Вами, превышает 3000 x 2000. Большие разрешения поддерживаются, но требуют хорошее аппаратное обеспечение для поддержания нормальной частоты кадров. Вы уверены, что хотите продолжить?" +confirmation.music_warning = "Если Вы хотите использовать mp3 файлы в качестве вашей музыки в игре, Ваша операционная система должна иметь smpeg.dll или его эквивалент, иначе музыка не будет проигрываться. Продолжить?" +menu_options_wage_increase.deny = " ОТКАЗАТЬ " +menu_options_wage_increase.grant = " РАЗРЕШИТЬ " +tooltip.options_window.audio_button = "Включить/Выключить всё аудио в игре" +tooltip.options_window.audio_toggle = "Включить/Выключить" +tooltip.options_window.folder_button = "Свойства папки" +tooltip.options_window.customise_button = "Больше настроек для улучшения игрового опыта" +tooltip.update_window.download = "Перейти к странице загрузки новейшей версии CorsixTH" +tooltip.update_window.ignore = "Игнорировать это обновление сейчас. Вы снова будете уведомлены при следующем запуске CorsixTH" +tooltip.folders_window.browse_font = "Поиск другого файла со шрифтом ( текущее расположение: %1% )" +tooltip.folders_window.screenshots_location = "По умолчанию скриншоты сохраняются в папке рядом с файлом конфигурации. По желанию Вы можете выбрать свою папку, просто укажите нужный путь к ней." +tooltip.folders_window.reset_to_default = "Вернуть папку в её изначальное расположение" +tooltip.folders_window.back = "Закрыть это меню и вернуться к настройкам" +tooltip.folders_window.music_location = "Выберите расположение ваших mp3 аудиофайлов. Вы должны были уже создать для них папку, теперь же укажите путь к ней." +tooltip.folders_window.font_location = "Расположение файла со шрифтом, который может отображать символы Юникода, необходимые вашему языку. Если это не будет указано, вы не сможете выбрать языки, которым нужно больше символов, чем игра может предложить. Например, китайский и русский." +tooltip.folders_window.savegames_location = "По умолчанию папка, куда помещаются сохранения, находится в папке рядом с файлом конфигурации. По желанию Вы можете выбрать свою папку, просто укажите нужный путь к ней." +tooltip.folders_window.browse_data = "Обзор расположения установленной версии Theme Hospital (текущее расположение: %1%)" +tooltip.folders_window.browse = "Обзор расположения папки" +tooltip.folders_window.browse_screenshots = "Обзор расположения папки скриншотов ( Текущее расположение: %1% ) " +tooltip.folders_window.browse_music = "Обзор расположения папки музыки ( Текущее расположение: %1% ) " +tooltip.folders_window.no_font_specified = "Расположение шрифта ещё не указано!" +tooltip.folders_window.not_specified = "Расположение папки ещё не указано!" +tooltip.folders_window.browse_saves = "Обзор расположения папки сохранений ( Текущее расположение: %1% ) " +tooltip.folders_window.default = "Расположение по умолчанию" +tooltip.folders_window.data_location = "Папка с установленной версией Theme Hospital, которая нужна CorsixTH для запуска" +tooltip.customise_window.aliens = "Из-за отсутствия подходящих анимаций, по умолчанию пациенты-инопланетяне могут приходить только в крайних случаях. Чтобы разрешить пациентам с инопланетной ДНК приходить в любое время, выключите эту опцию" +tooltip.customise_window.average_contents = "Если Вы хотите, чтобы игра запоминала, какие объекты Вы обычно добавляете при создании комнат, включите эту опцию" +tooltip.customise_window.back = "Закрыть это меню и вернуться к настройкам" +tooltip.customise_window.movies = "Глобальное управление роликами поможет вам выключить все ролики" +tooltip.customise_window.fractured_bones = "Из-за плохо сделанной анимации женские пациенты со сломанными костями изначально выключены. Чтобы разрешить женщинам со сломанными костями посещать вашу больницу, выключите это" +tooltip.customise_window.volume = "Если кнопка уменьшения громкости также открывает больничный журнал, включите эту опцию, чтобы поменять горячую клавишу для журнала на Shift+C" +tooltip.customise_window.intro = "Выключить/Включить заставку; ролики должны быть включены, если Вы хотите, чтобы заставка проигрывалась при запуске CorsixTH" +tooltip.customise_window.paused = "Во время паузы игрок в Theme Hospital может использовать только верхнее меню. По умолчанию это верно и для CorsixTH, но, включив эту опцию, вы можете получит доступ ко всему даже во время паузы" +update_window.caption = "Доступно новое обновление!" +update_window.new_version = "Новая версия:" +update_window.current_version = "Текущая версия:" +update_window.download = "Перейти к странице загрузки" +update_window.ignore = "Пропустить и перейти к главному меню" +errors.fractured_bones = "ПРИМЕЧАНИЕ: Анимация женских персонажей с разрушенными костями не идеальна" +errors.alien_dna = "ПРИМЕЧАНИЕ: Для пациентов-инопланетян нет анимации сидения, открывания и стучания в двери и т.д. Поэтому, как и в Theme Hospital, они будут на время превращаться в обычных пациентов и обратно. Пациенты с инопланетной ДНК будут появляться только если это указано уровнем." +errors.load_quick_save = "Ошибка, не удалось загрузить быстрое сохранение, так как оно не существовало, но мы создали для Вас новое!" +folders_window.data_label = "Данные TH" +folders_window.music_location = "Выберите папку, которую Вы хотите использовать для музыки" +folders_window.music_label = "MP3 файлы" +folders_window.new_th_location = "Здесь вы можете указать папку с установленной Theme Hospital. Как только вы выберете новую папку, игра будет перезапущена." +folders_window.caption = "Расположения папок" +folders_window.screenshots_label = "Скриншоты" +folders_window.font_label = "Шрифт" +folders_window.savegames_label = "Сохранения" +folders_window.back = "Назад" +folders_window.savegames_location = "Выберите папку, которую Вы хотите использовать для сохранений" +folders_window.screenshots_location = "Выберите папку, которую Вы хотите использовать для скриншотов" +customise_window.average_contents = "Среднее содержимое" +customise_window.option_on = "Вкл" +customise_window.paused = "Строить во время паузы" +customise_window.option_off = "Выкл" +customise_window.intro = "Проигрывать заставку" +customise_window.caption = "Пользовательские настройки" +customise_window.back = "Назад" +customise_window.movies = "Управление роликами" +customise_window.volume = "Горячая клавиша убавления громкости" +customise_window.aliens = "Инопланетные пациенты" +customise_window.fractured_bones = "Сломанные кости" +options_window.folder = "Папки" +options_window.customise = "Настроить" +options_window.audio = "Глобальное аудио" +menu_options.twentyfour_hour_clock = " 24-ЧАСОВОЕ ВРЕМЯ " +menu_options.wage_increase = " ЗАПРОСЫ ЗАРПЛАТЫ" +install.ok = "ОК" +install.cancel = "Отмена" +adviser.research.drug_improved_1 = "Лекарство %s было улучшено Вашим департаментом исследований." +adviser.warnings.no_desk_7 = "Вы построили приёмную стойку, как насчёт нанятия регистратора? У Вас не будет пациентов, пока Вы с этим не разберётесь!" +adviser.warnings.researcher_needs_desk_1 = "Исследователю нужно рабочее место" +adviser.warnings.no_desk_6 = "Вы наняли регистратора, как насчёт приёмной стойки для него?" +adviser.warnings.nurse_needs_desk_1 = "Каждая медсестра нуждается в собственном рабочем месте." +adviser.warnings.researcher_needs_desk_2 = "Ваш исследователь рад, что Вы разрешили ему отдохнуть. Если Вы хотели, чтобы у Вас работали несколько исследователей, Вы должны предоставить каждому из них собственное рабочее место." +adviser.warnings.no_desk_5 = "Время пришло, скоро к Вам начнут приходить пациенты!" +adviser.warnings.no_desk_4 = "Регистратору нужна приёмная стойка, чтобы он мог приветствовать новых пациентов" +adviser.warnings.researcher_needs_desk_3 = "Каждый исследователь нуждается в собственном рабочем месте." +adviser.warnings.cannot_afford_2 = "У вас недостаточно денег в банке, чтобы сделать эту покупку!" +adviser.warnings.nurse_needs_desk_2 = "Ваша медсестра рада, что Вы разрешили ей отдохнуть. Если Вы хотели, чтобы у Вас работали несколько медсестёр, Вы должны предоставить каждой из них собственное рабочее место." +custom_game_window.free_build = "Свободное строительство" +menu_list_window.save_date = "Изменено" +menu_list_window.name = "Имя" +information.level_lost.cheat = "Вы это выбрали или просто нажали не ту кнопку? Вы даже нормально обмануть не можете, не смешно, да?" diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/simplified_chinese.lua corsix-th-0.62/CorsixTH/Lua/languages/simplified_chinese.lua --- corsix-th-0.30/CorsixTH/Lua/languages/simplified_chinese.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/simplified_chinese.lua 2018-07-21 11:13:17.000000000 +0000 @@ -32,36 +32,36 @@ daymonth = "%2%月 %1%日", } misc = { - no_heliport = "Either no diseases have been discovered yet, or there is no heliport on this map.", + no_heliport = "还没有疾病被发现或者地图上需要一个直升机场", not_yet_implemented = "(尚未实现)", } debug_patient_window = { - caption = "Debug Patient", + caption = "病人除错", } totd_window = { - previous = "上一个提示", tips = { - [1] = "Corsix-TH,主题医院复刻版,项目主页:http://code.google.com/p/corsix-th", - [2] = "运行游戏需要原版主题医院,下载地址:http://www.gougou.com/search?search=主题医院", - [3] = "找到bug可以提交到这里:http://code.google.com/p/corsix-th/issues/list", - [4] = "这个复刻版还有很多功能没有实现,例如地震、传染病等,这里有说明:http://code.google.com/p/corsix-th/wiki/ProgrammingIdeas", - [5] = "有问题可加入QQ群“【主题医院】交流平台”(群号:13365299)详细询问,或者到百度贴吧“主题医院”吧详细询问", - [6] = "项目论坛地址1:http://forums.corsix-th.com", - [7] = "项目论坛地址2:http://groups.google.com/group/corsix-th-dev", - [8] = "如果你对这个项目有兴趣,最新版源码在这里:http://th.corsix.org/corsix-th-latest.tar.gz", - [9] = "编译源码的方法:http://code.google.com/p/corsix-th/wiki/HowToCompile", - [10] = "自定义游戏里面有一幅地图Avatar,里面有特殊的任务", - [11] = "Corsix-TH,主题医院复刻版,项目主页:http://code.google.com/p/corsix-th", - [12] = "运行游戏需要原版主题医院,下载地址:http://www.gougou.com/search?search=主题医院", - [13] = "找到bug可以提交到这里:http://code.google.com/p/corsix-th/issues/list", - [14] = "这个复刻版还有很多功能没有实现,例如地震、传染病等,这里有说明:http://code.google.com/p/corsix-th/wiki/ProgrammingIdeas", - [15] = "有问题可加入QQ群“【主题医院】交流平台”(群号:13365299)详细询问,或者到百度贴吧“主题医院”吧详细询问", - [16] = "项目论坛地址1:http://forums.corsix-th.com", - [17] = "项目论坛地址2:http://groups.google.com/group/corsix-th-dev", - [18] = "如果你对这个项目有兴趣,最新版源码在这里:http://th.corsix.org/corsix-th-latest.tar.gz", - [19] = "编译源码的方法:http://code.google.com/p/corsix-th/wiki/HowToCompile", + "医院想开张就需要一个前台桌子和一个问诊室.这之后还需要根据不同病人建立各种房间.但有个药房总是对的.", + "有一些机器需要维护,比如说充气机.所以雇一两个修理人员还是必要的, 不然那就是个定时炸弹.", + "你的员工会不时感到疲倦. 所以建一间休闲室也很必要.", + "多放点几个暖气,让你的员工和病人感到春天般温暖.用全景地图来查看它们的覆盖面积以决定是否还需要多放些.", + "一个医生的医疗水平很大程度影响他的诊断速度.把最牛逼的医生放在问诊室,这样你会省下其他的问诊室.", + "实习生和医生们可以通过在学习室向专家学习来提高水平.如果请来的专家拥有某一项专长,他也会教给他的学生们.", + "有没有试过在传真机上拨112?这是欧洲的急救电话.别忘了把你的音箱开到最大!", + "在主菜单和游戏菜单里面,找到选项窗口,在那里可以调整分辨率和语言.", + "你选择了中文,但是你还是可能会在游戏中不停地看到英文.把他们翻译了吧,我们需要你的帮助!", + "CorsixTH小组正在壮大!如果你对编程,翻译,创做主题医院需要的图片等等任何方面感兴趣,请通过我们的论坛,邮件列表或者IRC频道(corsix-th at freenode)联系我们.", + "如果你碰到了bug,请提交给我们: th-issues.corsix.org", + "每一关都需要满足特定的条件才能过关.你可以通过状态窗口看到你的进度.", + "如果你需要编辑或者删除一间房间,屏幕下方找到工具栏,然后点编辑房间按钮.", + "在成群结队等待就诊的病人中, 你可以通过指向房间的门来找到哪些病人在等.", + "点击房间门可以看到等待队列.你可以做些调整让某些人走个后门,或者送到另一个房间去.", + "不开心的员工只有通过涨薪来平衡自己了.你要保证你的员工的工作环境像家一样,才能让他们甘心给你卖命.", + "病人等的时间长了,会口渴,如果开了暖气,口渴得会更快!放些自动贩卖机吧,还能多些零花钱.", + "如果你见过某种病,你可以中断诊疗过程直接去治,治死了不要找我.", + "从紧急事件总能赚一大笔,但是你要按时处理好才行.", }, - next = "下一个提示", + previous = "前一项提示", + next = "下一项提示", } tooltip = { totd_window = { @@ -69,23 +69,23 @@ next = "显示下一个提示", }, message = { - button = "Left click to open message", - button_dismiss = "Left click to open message, right click to dismiss it", + button = "点击打开消息", + button_dismiss = "点击打开消息,右键点击忽略", }, custom_game_window = { start_game_with_name = "%s", }, cheats_window = { - close = "Close the cheats dialog", + close = "关闭作弊窗口", cheats = { - end_month = "Jumps to the end of the month.", - emergency = "Creates an emergency.", - win_level = "Win the current level.", - create_patient = "Creates a Patient at the map border.", - money = "Adds 10.000 to your bank balance.", - lose_level = "Lose the current level.", - all_research = "Completes all research.", - end_year = "Jumps to the end of the year.", + end_month = "跳到月末.", + emergency = "建一个急诊室.", + win_level = "赢得当前关卡.", + create_patient = "在地图的边缘生成一个病人.", + money = "往银行里存 10.000.", + lose_level = "在当前关卡败北.", + all_research = "完成所有的研究.", + end_year = "跳到年末.", }, }, casebook = { @@ -116,32 +116,32 @@ save_game = "%s", }, calls_dispatcher = { - assigned = "This box is marked if someone is assigned to the corresponding task.", - task = "List of tasks - click task to open assigned staff's window and scroll to location of task", - close = "Close the calls dispatcher dialog", + assigned = "这个框代表是否有人被分配给此任务.", + task = "任务列表 - 点击任务打开人员分配窗口然后滚动到任务的位置", + close = "关闭接线员窗口", }, research_policy = { - research_progress = "Progress towards the next discovery in this category: %1%/%2%", - no_research = "No research is being carried out in this category at the moment", + research_progress = "此类研究下次发现的进度: %1%/%2%", + no_research = "当前没有任何此类研究在进行中", }, information = { close = "关闭", }, lua_console = { - textbox = "Enter Lua code to run here", - execute_code = "Run the code you have entered", - close = "Close the console", + textbox = "输入Lua代码可直接运行", + execute_code = "运行输入的代码", + close = "关闭控制台", }, load_game_window = { load_game = "%s", - load_autosave = "Load autosave", - load_game_number = "Load game %d", + load_autosave = "载入自动保存的游戏", + load_game_number = "载入游戏 %d", }, fax = { close = "关闭此窗口,但不删除消息", }, objects = { - litter = "Litter: Left on the floor by a patient because he did not find a bin to throw it in.", + litter = "废弃物: 病人找不到垃圾桶,所以随意丢在了地上.", }, options_window = { fullscreen_button = "全屏幕", @@ -157,92 +157,128 @@ } cheats_window = { cheats = { - end_month = "End of Month", - emergency = "Create Emergency", - win_level = "Win Level", - create_patient = "Create Patient", - money = "Money Cheat", - lose_level = "Lose Level", - all_research = "All Research Cheat", - end_year = "End of Year", + end_month = "月末", + emergency = "修建急诊室", + win_level = "获胜", + create_patient = "生成病人", + money = "给我钱!!", + lose_level = "失败", + all_research = "所有研究", + end_year = "年末", }, - close = "Close", - caption = "Cheats", + close = "关闭", + caption = "作弊", cheated = { - no = "Cheats used: No", - yes = "Cheats used: Yes", + no = "作弊了吗: 否", + yes = "作弊了吗: 是", }, - warning = "Warning: You will not get any bonus points at the end of the level if you cheat!", + warning = "警告: 如果作弊关卡结束时你将得不到任何奖励!", } errors = { - unavailable_screen_size = "The screen size you requested is not available in fullscreen mode.", - dialog_missing_graphics = "Sorry, the demo data files don't contain this dialog.", - maximum_screen_size = "Please enter a screen size of at most 3000x2000.", - load_prefix = "Error while loading game: ", - save_prefix = "Error while saving game: ", - map_file_missing = "Could not find the map file %s for this level!", - minimum_screen_size = "Please enter a screen size of at least 640x480.", + unavailable_screen_size = "你设置的屏幕大小无法应用于全屏模式。", + dialog_missing_graphics = "哎呀, Demo 数据文件不包含这个对话框.", + load_prefix = "载入游戏失败:", + save_prefix = "保存游戏失败:", + map_file_missing = "找不到该关卡的地图文件 %s!", + minimum_screen_size = "最小屏幕大小为 640x480。", } main_menu = { - exit = "退出", - custom_level = "自定义游戏", new_game = "开始游戏", - load_game = "装载游戏", + custom_level = "自定义游戏", + continue = "继续游戏", + load_game = "载入游戏", options = "选项", + version = "版本: ", + exit = "退出" } menu_debug = { - lua_console = " (F12) LUA CONSOLE ", - disable_salary_raise = " DISABLE SALARY RAISE ", - make_debug_fax = " MAKE DEBUG FAX ", - make_debug_patient = " MAKE DEBUG PATIENT ", - sprite_viewer = " SPRITE VIEWER ", - dump_strings = " DUMP STRINGS ", - map_overlay = " MAP OVERLAY ", - calls_dispatcher = " CALLS DISPATCHER ", - cheats = " (F11) CHEATS ", - dump_gamelog = " (CTRL+D) DUMP GAME LOG ", - limit_camera = " LIMIT CAMERA ", - transparent_walls = " (X) TRANSPARENT WALLS ", - jump_to_level = " JUMP TO LEVEL ", + lua_console = " (F12) LUA 控制台 ", + disable_salary_raise = " 关闭涨工资 ", + make_debug_fax = " 建一个传真DEBUG ", + make_debug_patient = " 建一个病人DEBUG ", + sprite_viewer = " 图像浏览器 ", + dump_strings = " 输出字符串 ", + map_overlay = " 地图层次 ", + calls_dispatcher = " 接线员窗口 ", + cheats = " (F11) 作弊 ", + dump_gamelog = " (CTRL+D) 输出游戏记录文本 ", + limit_camera = " 限制镜头 ", + transparent_walls = " (X) 把墙变透明 ", + jump_to_level = " 跳关 ", } menu_options = { - edge_scrolling = " 开启鼠标滚动", + edge_scrolling = " 边缘滚动", lock_windows = " 锁定窗口", - settings = " 选项", + sound = " (ALT+S) 音效 ", + announcements = " (ALT+A) 公告 ", + music = " (ALT+M) 音乐 ", + jukebox = " (J) 音乐盒 ", + adviser_disabled = " (SHIFT+A) 建议 ", + warmth_colors = " 暖气区域显示 ", + wage_increase = " 涨工资要求", + twentyfour_hour_clock = " 24小时时钟 " } menu_options_game_speed = { pause = " 暂停", } lua_console = { - execute_code = "Execute", - close = "Close", + execute_code = "运行", + close = "关闭", } install = { - title = "--------------------------------- CorsixTH 游戏设置 ---------------------------------", + title = "-------------------------------- CorsixTH 游戏设置 -------------------------------", th_directory = "运行游戏需要原版主题医院。请指定原版主题医院游戏安装文件夹。", + ok = "确定", + exit = "退出", + cancel = "取消" } load_game_window = { - caption = "装载游戏", + caption = "载入游戏", } adviser = { cheats = { - th_cheat = "Congratulations, you have unlocked cheats!", - hairyitis_cheat = "Hairyitis cheat activated!", - roujin_on_cheat = "Roujin's challenge activated! Good luck...", - crazy_on_cheat = "Oh no! All doctors have gone crazy!", - bloaty_off_cheat = "Bloaty Head cheat deactivated.", - bloaty_cheat = "Bloaty Head cheat activated!", - crazy_off_cheat = "Phew... the doctors regained their sanity.", - roujin_off_cheat = "Roujin's challenge deactivated.", - hairyitis_off_cheat = "Hairyitis cheat deactivated.", + th_cheat = "恭喜, 你解锁了作弊选项!", + hairyitis_cheat = "Hairyitis 作弊模式已经开启!", + roujin_on_cheat = "Roujin's challenge已经开启!祝你好运...", + crazy_on_cheat = "不会吧!所有的医生都疯了!", + bloaty_off_cheat = "大头病作弊被关闭.", + bloaty_cheat = "大头病作弊开启!", + crazy_off_cheat = "还好... 所有的一生都恢复理智了.", + roujin_off_cheat = "Roujin's challenge关闭.", + hairyitis_off_cheat = "Hairyitis 作弊模式关闭.", + }, + warnings = { + no_desk = "你总得有个前台吧!", + no_desk_1 = "你得有个前台,这样才会有病人来!", + no_desk_2 = "干的不错, 基本上也是个世界纪录了吧:快一年了,一个病人都没有! 如果你想继续当这个经理的话,你需要去雇一个前台,然后给她一张桌子工作!", + no_desk_3 = "你真是个天才,一年了连个前台都没有! 你怎么可能有任何的病人来? 赶紧给我搞定,别在那里不务正业了!", + no_desk_4 = "前台需要一个桌子来接待来访的病人", + no_desk_5 = "Well it's about time, you should start to see some patients arriving soon!", + no_desk_6 = "You have a receptionist, so how about building a reception desk for her to work from?", + no_desk_7 = "You've built the reception desk, so how about hiring a receptionist? You won't see any patients until you get this sorted out you know!", + falling_1 = "嘿!别开玩笑了, 看看你都是怎么点鼠标的, 你可能会伤到人!", + falling_2 = "不要再胡搞了, 跟有病似的?", + falling_3 = "啊~有人受伤了,赶紧叫医生!", + falling_4 = "这里是医院,不是主题公园!", + falling_5 = "这里不适合逗人玩,他们是病人好吗?", + falling_6 = "这里不是保龄球馆, 应该对待病人如春天般温暖!", + cannot_afford = "你已经没有足够的钱来雇这个人!",-- I can't see anything like this in the original strings + cannot_afford_2 = "你没有足够的存款来做这件事!", + research_screen_open_1 = "你需要建设一个研究科室才能访问研究页面.", + research_screen_open_2 = "这一关不能开展研究.", + researcher_needs_desk_1 = "研究员需要一张桌子展开工作.", + researcher_needs_desk_2 = "你的研究员对你允许他休息片刻表示感谢,但如果你想让每个人都工作,你需要给每个人一张桌子.", + researcher_needs_desk_3 = "每个研究院需要自己的桌子.", + nurse_needs_desk_1 = "每个护士都需要自己的桌子.", + nurse_needs_desk_2 = "你的护士对你允许他休息片刻表示感谢,但如果你想让每个人都工作,你需要给每个人一张桌子.", }, - room_forbidden_non_reachable_parts = "Placing the room in this location would result in parts of the hospital not being reachable.", + room_forbidden_non_reachable_parts = "在这个地方放置房间会导致医院的部分空间无法到达.", } calls_dispatcher = { - repair = "Repair %s", - summary = "%d calls; %d assigned", - close = "Close", - watering = "Watering @ %d,%d", + repair = "修理 %s", + summary = "%d 次电话; %d 被分配", + close = "关闭", + watering = "浇水 @ %d,%d", staff = "%s - %s", } information = { @@ -253,29 +289,50 @@ balance = "银行账户资金低于%d。", percentage_killed = "杀死了%d的病人。", }, - cannot_restart = "Unfortunately this custom game was saved before the restart feature was implemented.", - custom_game = "Welcome to CorsixTH. Have fun with this custom map!", + cannot_restart = "不幸的是这个自定义地图是在 重新开始 功能开发之前创建的.", + custom_game = "欢迎来到 CorsixTH。尽情享受自定义地图吧!", } new_game_window = { - hard = "专家(难)", - cancel = "返回", - tutorial = "第一次游戏", + caption = "竞争上岗", + player_name = "玩家名称", + option_on = "开", + option_off = "关", + difficulty = "难度", easy = "实习医生(容易)", medium = "医生(一般)", + hard = "专家(难)", + tutorial = "游戏教程", + start = "开始", + cancel = "返回", } + options_window = { + caption = "设置", + option_on = "开", + option_off = "关", fullscreen = "全屏幕", - height = "", - width = "", - change_resolution = "更改分辨率", + resolution = "分辨率", + custom_resolution = "自定义...", + width = "宽度", + height = "高度", + audio = "全局音效", + customise = "自定义", + folder = "文件夹", + language = "语言", + apply = "应用", + cancel = "取消", back = "返回", } + menu_list_window = { + name = "名称", + save_date = "已修改", back = "返回", } + save_game_window = { caption = "保存游戏", - new_save_game = "", + new_save_game = "给新游戏存档起个名", } fax = { choices = { @@ -285,7 +342,7 @@ }, } menu_debug_overlay = { - heat = " TEMPERATURE ", + heat = " 温度 ", byte_0_1 = " BYTE 0 & 1 ", byte_6 = " BYTE 6 ", flags = " FLAGS ", @@ -299,8 +356,8 @@ none = " NONE ", } confirmation = { - abort_edit_room = "You are currently building or editing a room. If all required objects are placed it will be finished, but otherwise it will be deleted. Continue?", - needs_restart = "Changing this setting requires CorsixTH to restart. Any unsaved progress will be lost. Are you sure you want to do this?", + abort_edit_room = "你正在修建或者就该一个房间.如果所有必需的物品都被放置了就没有问题,否则所做的修改将被删除. 继续吗?", + needs_restart = "这项设置的改动需要重新启动 CorsixTH. 尚未保存的进度将会丢失. 确定要这么做吗?", } dynamic_info = { patient = { @@ -316,59 +373,51 @@ }, } introduction_texts = { - demo = { - [1] = "Welcome to the demo hospital!", - [2] = "Unfortunately the demo version only contains this level. However, there is more than enough to do here to keep you busy for a while!", - [3] = "You will encounter various diseases that require different rooms to cure. From time to time, emergencies may occur. And you will need to research additional rooms using a research room.", - [4] = "Your goal is to earn $100,000, have a hospital value of $70,000 and a reputation of 700, while having cured at least 75% of your patients.", - [5] = "Make sure your reputation does not fall below 300 and that you don't kill off more than 40% of your patients, or you will lose.", - [6] = "Good luck!", - }, + demo = + "欢迎来到演示版医院!//" .. + "演示版本只有当前这一个关卡. 但有一堆事情足够你忙一阵了! " .. + "你将会遇到各种疾病需要各种医疗室来救治. 紧急情况也会经常性地发生. 你需要通过研究室来研发更多的医疗室. " .. + "你的目标是挣够 $100,000, 使医院的价值达到 $70,000 以及得到 700 声望值, 同时你还需要救治超过 75% 的病人. " .. + "确保你的声望值不会掉到 300 以下, 你的病人死亡率不超过 40% , 否则你就完了.//" .. + "祝你好运!", } object = { - litter = "Litter", + litter = "废弃物", } letter = { - custom_level_completed = "Well done! You've completed all goals on this custom level!", - dear_player = "Dear %s", - return_to_main_menu = "Would you like to return to the main menu or continue playing?", + custom_level_completed = "做的好!你已完成自定义游戏的所有目标!", + dear_player = "亲爱的 %s", + return_to_main_menu = "你想要回到主菜单还是继续游戏?", } -tooltip.custom_game_window.free_build = "Tick this box if you want to play without money or winning and losing conditions" -tooltip.cheats_window.cheats.vip = "Creates a VIP." -tooltip.menu_list_window.save_date = "Click here to sort the list by last modification date" -tooltip.menu_list_window.name = "Click here to sort the list by name" -tooltip.options_window.original_path = "The currently chosen directory of the original Theme Hospital installation" -tooltip.options_window.browse = "Browse for another location of a Theme Hospital installation. %1%" -custom_game_window.free_build = "Free Build" -cheats_window.cheats.vip = "Create VIP" -main_menu.version = "Version: " -main_menu.savegame_version = "Savegame version: " -progress_report.free_build = "FREE BUILD" -menu_options.adviser_disabled = " 显示助手" -install.exit = "Exit" -adviser.warnings.falling_2 = "Stop messing about, how would you like it?" -adviser.warnings.no_desk_2 = "Well done, that must be a world record: nearly a year and no patients! If you want to continue as Manager of this hospital, you will need to hire a receptionist and build a reception desk for her to work from!" -adviser.warnings.falling_5 = "This is not the place for knocking people over, they're ill you know!" -adviser.warnings.falling_4 = "This is an Hospital, not a Theme Park!" -adviser.warnings.falling_6 = "This is not a bowling alley, sick people should not be treated like that!" -adviser.warnings.falling_3 = "Ouch, that had to hurt, someone call a Doctor!" -adviser.warnings.no_desk_3 = "That's just brilliant, nearly a year and you don't have a staffed reception! How do you expect to get any patients, now get it sorted out and stop messing around!" -adviser.warnings.cannot_afford = "You don't have enough money in the bank to hire that person!" -adviser.warnings.no_desk = "You should build a reception desk and hire a receptionist at some point!" -adviser.warnings.no_desk_1 = "If you want patients to come to your hospital, you will need to hire a receptionist and build her a desk to work at!" -adviser.warnings.falling_1 = "Hey! that is not funny, watch where you click that mouse; someone could get hurt!" -information.very_old_save = "There have been a lot of updates to the game since you started this level. To be sure that all features work as intended please consider restarting it." +update_window = { + caption = "可升级新版本!", + new_version = "新版本:", + current_version = "当前版本:", + download = "打开下载页面", + ignore = "回到主菜单" +} + +tooltip.custom_game_window.free_build = "勾选此框你将不需要为钱以及胜利失败而操心" +tooltip.cheats_window.cheats.vip = "创建一个 VIP." +tooltip.menu_list_window.save_date = "点击整理一个按照最后修改日期排序的列表" +tooltip.menu_list_window.name = "点击按照名字整理" +custom_game_window.free_build = "自由模式" +cheats_window.cheats.vip = "创建 VIP" +main_menu.version = "版本: " +main_menu.savegame_version = "存档版本: " +progress_report.free_build = "自由模式" +menu_options.adviser_disabled = " 显示建议" +install.exit = "退出" +information.very_old_save = "你上次存档之后,这个游戏有很多更新. 为了保证你能玩到最新最酷的游戏,请考虑重新来过" options_window.cancel = "取消" -options_window.browse = "浏览..." -options_window.new_th_directory = "Here you can specify a new Theme Hospital installation directory. As soon as you choose the new directory the game will be restarted." menu_list_window.save_date = "修改日期" menu_list_window.name = "名称" -fax.vip_visit_result.remarks.free_build[1] = "It is a very nice hospital you have there! Not very hard to get it working without money limitations though, eh?" -fax.vip_visit_result.remarks.free_build[2] = "I'm no economist, but I think I could run this hospital too if you know what I mean..." -fax.vip_visit_result.remarks.free_build[3] = "A very well run hospital. Watch out for the recession though! Right... you didn't have to worry about that." -fax.emergency.free_build = "If you are successful your reputation will increase but if you fail your reputation will be seriously dented." -fax.emergency.num_disease_singular = "There is 1 person with %s and they require immediate attention." +fax.vip_visit_result.remarks.free_build[1] = "你的医院相当不错! 没有预算的限制,搞定很容易吧?" +fax.vip_visit_result.remarks.free_build[2] = "我不是一个经济学家, 但我要是你我也行. 你懂我啥意思..." +fax.vip_visit_result.remarks.free_build[3] = "医院经营的不错. 但要小心经济不景气. 哦对了,你才不操那个心." +fax.emergency.free_build = "成功的话,你的声望就会上升,但你要是失败了, 就会一落千丈." +fax.emergency.num_disease_singular = "那里有一个人患了 %s ,他们需要马上救治." ------------------------------------ --OLD STRINGS IN LANGUAGE "简体中文": @@ -582,7 +631,7 @@ research = "研究", hire = "雇佣员工", status = "状态", - town_map = "城镇地图", + town_map = "城市地图", rooms = "建造房屋", bank_button = "左击进入银行经理画面,右击进入银行帐户", }, @@ -659,15 +708,16 @@ insurance_owed = "%s欠款的金额", }, main_menu = { + new_game = "开始新游戏", + load_game = "载入进度", network = "开始网络游戏", - quit = "退出", - continue = "继续游戏", + exit = "不要,不要,请不要退出游戏!", + quit = "确定要退出游戏吗?", + continue = "继续游戏最近的游戏", load_menu = { load_slot = "读取进度", - empty_slot = "空", - }, - new_game = "开始新游戏", - load_game = "读入进度", + empty_slot = "空" + } }, patient_window = { graph = "通过点击可以在健康情况和病史之间切换", @@ -818,15 +868,16 @@ }, } menu_charts = { - briefing = " 任务简报", - casebook = " 治疗手册", - graphs = " 图表", - policy = " 制度", - bank_manager = " 银行经理", - statement = " 银行账户", - staff_listing = " 员工列表", - research = " 研究", - status = " 状态", + briefing = " 任务简报", + casebook = " (F5) 治疗手册", + graphs = " (F8) 图表", + policy = " (F9) 制度", + bank_manager = " (F1) 银行经理", + statement = " (F2) 银行账户", + town_map = " (F4) 城市地图 ", + staff_listing= " (F3) 员工列表", + research = " (F6) 研究", + status = " (F7) 状态", } town_map = { number = "地区编号", @@ -2754,13 +2805,13 @@ [26] = "林", } confirmation = { - return_to_blueprint = "您是否确定返回蓝图模式?", - restart_level = "您是否希望重新开始这个任务?", - delete_room = "您是否希望拆除这个房间?", - quit = "您已经选择了退出。您是否确定真的要退出游戏?", - overwrite_save = "该位置已储存游戏进度。您是否确定要将其覆盖?", - sack_staff = "您是否确定要解雇该员工?", - replace_machine = "您是否确定将%s更新,需花费$%d?", + return_to_blueprint = "您定要返回蓝图模式吗?", + restart_level = "确定要重新开始这个任务吗?", + delete_room = "确定要拆除这个房间吗?", + quit = "确定要退出游戏吗?", + overwrite_save = "该位置已有游戏进度。是否覆盖?", + sack_staff = "确定要解雇该员工吗?", + replace_machine = "确定要更新%s,并花费$%d?", } months = { [1] = "1 月", @@ -2820,127 +2871,109 @@ }, } introduction_texts = { - level17 = { - [1] = "最后的警告-时刻关注您的声望-这是真正吸引病人前来就诊的关键。", - [2] = "如果您没有杀死太多的病人,且使就诊病人保持快乐,则不必太担心声望!", - [3] = "决定权就在您的手中。祝您好运。", - }, - level1 = { - [1] = "欢迎来到您的第一座医院!//", - [2] = "首先要摆放接待台,建造一般诊断室,并雇佣一名接待员和一名医生。", - [3] = "随后就可以等待开张了。", - [4] = "建造精神病诊断治疗室并雇佣一名精神病医生是一个好主意。", - [5] = "药房和护士也是治疗病人所必需的。", - [6] = "建造一个充气机房间就可以治疗头部肿胀患者。", - [7] = "您需要治愈10个病人,并使声望保持在200以上。", - }, - level9 = { - [1] = "当填满了卫生部的银行帐户并为部长大人购买了一辆轿车后,您现在又要开始新的工作了。", - [2] = "在这里您要面对很多问题。", - [3] = "只有拥有足够经验充分的员工和房间,您才能够顺利过关。", - [4] = "医院价值需要达到$200,000,且银行帐户上要有$400,000。", - [5] = "如果无法达到上述要求,则无法胜利完成任务。", - }, - level2 = { - [1] = "在该区域内还有一些其它的疾病。", - [2] = "建造医院从而可以治疗更多的病人,并应该考虑建造研究部门。", - [3] = "记住保持内部的清洁,从而使声望尽可能地高-您将遇到患有舌头松弛症的病人,因此需要建造舌头诊治房间。", - [4] = "您也可以建造心电图房间来帮助诊断疾病。", - [5] = "这些房间都需要经过研究才能够被建造。现在你可以购买其它土地扩展医院-使用城镇地图就可以购买土地。", - [6] = "目标是声望300,银行现金为10000,且治愈40个病人。", - }, - level7 = { - [1] = "在这里您将受到卫生部的密切监察,因此要在赚钱的同时,努力提高自己的声望。", - [2] = "我们无法处理太多的医疗事故-这对于医院的运营是十分不利的。", - [3] = "确认所有员工都很快乐,并确认已经购买了所有需要的仪器装备。", - [4] = "声望需要达到600,且银行里需要有$200,000。", - }, - level5 = { - [1] = "医院将非常繁忙,处理各种各样的病人。", - [2] = "医生都是刚刚毕业的实习医生,因此需要建造一间培训室对他们进行培训,提高能力。", - [3] = "您只有3名专家可以帮助培训这些员工,因此一定要让专家快乐。", - [4] = "另外要注意的是,医院的位置不是很好。", - [5] = "经常会发生地震。", - [6] = "地震将对医院中的机器产生损坏,从而影响医院的运营。", - [7] = "使您声望达到400以上,现金达到$50,000。另外需要治愈200个病人。", - }, - level4 = { - [1] = "使所有的病人快乐,保持治疗的高效率并尽量降低死亡人数。", - [2] = "声望是十分重要的,因此尽量赢得更高的声望。", - [3] = "不要太多担心收入情况-当声望提高了,收入也自然会提高。", - [4] = "您需要培训您的医生,拓宽他们的能力。", - [5] = "这样他们就可以更好的为病人服务。", - [6] = "胜利条件是声望达到500以上。", - }, - level14 = { - [1] = "这里还有一个挑战-一个充满惊奇的医院。", - [2] = "如果您能够成功完成这个任务,则您将成为所有胜利者中的佼佼者。", - [3] = "不要认为完成这个任务就象吃蛋糕一样,这将是您所遇到的最艰苦的工作。", - [4] = "祝您好运!", - }, - level15 = { - [1] = "好的,下面是管理医院的一些技巧。//", - [2] = "医生需要各种帮助来诊断病人。您可以", - [3] = "建造另一个诊断类房间,例如高级诊断室。", - }, - level8 = { - [1] = "需要您来建造一座高效的医院。", - [2] = "很多人都无事可做,因此需要适量的裁员以保持高效。", - [3] = "记住治愈病人是很重要的一件事情,但是您更要从中赚钱。", - [4] = "让恶心呕吐的病人靠近清洁工人。", - [5] = "需要赚取$300,000就可以过关。", - }, - level13 = { - [1] = "您的高超管理技能被特殊机密部门获知。", - [2] = "他们将向您提高特别奖金,因为他们有一座被老鼠困扰的医院需要有效管理。", - [3] = "您必须杀死尽可能多的老鼠,并让清洁工人打扫干净。", - [4] = "接受这个任务?", - }, - level16 = { - [1] = "当对病人完成诊断后,需要建造处理和治疗类房间完成对病人的治疗工作。可以从", - [2] = "建造药房开始。在药房中需要一名护士分配各种药品。", - }, - level6 = { - [1] = "使用您的所有知识来建造一个运行平稳的医院,从而可以赚取利润并处理任何问题。", - [2] = "您需要注意一点,医院周围的空气对细菌繁殖,传染病流行非常适宜。", - [3] = "如果您没有保持医院的清洁,则将面对传染病的流行。", - [4] = "赚取$150,000,并使医院价值超过$140,000。", - }, - level12 = { - [1] = "您现在遇到了最大的挑战。", - [2] = "我们为您的成功感到由衷地高兴,卫生部为您准备了一项顶级工作;他们需要有人建造另一个超级医院,赚钱的同时获取较高的声望。", - [3] = "您可以购买任何需要的土地,治疗各种疾病赢得各种奖励。", - [4] = "动心了吗?", - [5] = "赚取$650,000,治愈750个病人,使声望达到800就可以胜利过关。", - }, - level3 = { - [1] = "这次您将在一个富裕地区建造医院。", - [2] = "卫生部希望您能够在这里赚取更多的利润。", - [3] = "开始时您被要求获取好的声望,但是一旦医院步入正轨,就可以集中精力赚取更多的钱。", - [4] = "有可能会发生紧急事件。", - [5] = "也就是说一次会有大量病人就诊,且他们的病情都一样。", - [6] = "在时间限制内如果能够治愈他们,则不仅可以拿到奖金,声望也会提高。", - [7] = "一些疾病如猫王综合症等有可能发生,因此最好建造一间手术中心和附属病房。", - [8] = "胜利条件是赚取$20,000。", - }, - level10 = { - [1] = "随着您的经验不断增长,卫生部要求您集中精力提高药品的治疗效果。", - [2] = "有人对您颇有微辞,为此您必须使所有的药物都非常有效。", - [3] = "另外,一定要降低医疗事故的发生次数,减少死亡人数。", - [4] = "作为提示,您需要为建造胶桶留一些空地。", - [5] = "使所有药物的疗效都达到80%%,声望达到650且在银行帐户上有$500,000,这样就可以胜利过关。", - }, - level11 = { - [1] = "现在您有机会建造一座终极医院。", - [2] = "该地区享有极高的声望,因此卫生部希望能够看到最好的医院建造在这里。", - [3] = "我们希望您能够赚取大量的金钱,获得很高的声望,并能够成功地处理任何事件。", - [4] = "这是一项非常重要的工作。", - [5] = "这需要您的努力工作。", - [6] = "注意一点,该区域常常会看到不明飞行物。因此请让您的员工做好准备迎接不速之客。", - [7] = "您的医院价值需要达到$240,000,在银行帐户内需要$500,000,且声望需要达到700。", - }, - level18 = { - }, + level17 = + "最后的警告-时刻关注您的声望-这是真正吸引病人前来就诊的关键。" .. + "如果您没有杀死太多的病人,且使就诊病人保持快乐,则不必太担心声望!" .. + "决定权就在您的手中。祝您好运。", + level1 = + "欢迎来到您的第一座医院!//" .. + "首先要摆放接待台,建造一般诊断室,并雇佣一名接待员和一名医生。" .. + "随后就可以等待开张了。" .. + "建造精神病诊断治疗室并雇佣一名精神病医生是一个好主意。" .. + "药房和护士也是治疗病人所必需的。" .. + "建造一个充气机房间就可以治疗头部肿胀患者。" .. + "您需要治愈10个病人,并使声望保持在200以上。", + level9 = + "当填满了卫生部的银行帐户并为部长大人购买了一辆轿车后,您现在又要开始新的工作了。" .. + "在这里您要面对很多问题。" .. + "只有拥有足够经验充分的员工和房间,您才能够顺利过关。" .. + "医院价值需要达到$200,000,且银行帐户上要有$400,000。" .. + "如果无法达到上述要求,则无法胜利完成任务。", + level2 = + "在该区域内还有一些其它的疾病。" .. + "建造医院从而可以治疗更多的病人,并应该考虑建造研究部门。" .. + "记住保持内部的清洁,从而使声望尽可能地高-您将遇到患有舌头松弛症的病人,因此需要建造舌头诊治房间。" .. + "您也可以建造心电图房间来帮助诊断疾病。" .. + "这些房间都需要经过研究才能够被建造。现在你可以购买其它土地扩展医院-使用城镇地图就可以购买土地。" .. + "目标是声望300,银行现金为10000,且治愈40个病人。", + level7 = + "在这里您将受到卫生部的密切监察,因此要在赚钱的同时,努力提高自己的声望。" .. + "我们无法处理太多的医疗事故-这对于医院的运营是十分不利的。" .. + "确认所有员工都很快乐,并确认已经购买了所有需要的仪器装备。" .. + "声望需要达到600,且银行里需要有$200,000。", + level5 = + "医院将非常繁忙,处理各种各样的病人。" .. + "医生都是刚刚毕业的实习医生,因此需要建造一间培训室对他们进行培训,提高能力。" .. + "您只有3名专家可以帮助培训这些员工,因此一定要让专家快乐。" .. + "另外要注意的是,医院的位置不是很好。" .. + "经常会发生地震。" .. + "地震将对医院中的机器产生损坏,从而影响医院的运营。" .. + "使您声望达到400以上,现金达到$50,000。另外需要治愈200个病人。", + level4 = + "使所有的病人快乐,保持治疗的高效率并尽量降低死亡人数。" .. + "声望是十分重要的,因此尽量赢得更高的声望。" .. + "不要太多担心收入情况-当声望提高了,收入也自然会提高。" .. + "您需要培训您的医生,拓宽他们的能力。" .. + "这样他们就可以更好的为病人服务。" .. + "胜利条件是声望达到500以上。", + level14 = + "这里还有一个挑战-一个充满惊奇的医院。" .. + "如果您能够成功完成这个任务,则您将成为所有胜利者中的佼佼者。" .. + "不要认为完成这个任务就象吃蛋糕一样,这将是您所遇到的最艰苦的工作。" .. + "祝您好运!", + level15 = + "好的,下面是管理医院的一些技巧。//" .. + "医生需要各种帮助来诊断病人。您可以" .. + "建造另一个诊断类房间,例如高级诊断室。", + level8 = + "需要您来建造一座高效的医院。" .. + "很多人都无事可做,因此需要适量的裁员以保持高效。" .. + "记住治愈病人是很重要的一件事情,但是您更要从中赚钱。" .. + "让恶心呕吐的病人靠近清洁工人。" .. + "需要赚取$300,000就可以过关。", + level13 = + "您的高超管理技能被特殊机密部门获知。" .. + "他们将向您提高特别奖金,因为他们有一座被老鼠困扰的医院需要有效管理。" .. + "您必须杀死尽可能多的老鼠,并让清洁工人打扫干净。" .. + "接受这个任务?", + level16 = + "当对病人完成诊断后,需要建造处理和治疗类房间完成对病人的治疗工作。可以从" .. + "建造药房开始。在药房中需要一名护士分配各种药品。", + level6 = + "使用您的所有知识来建造一个运行平稳的医院,从而可以赚取利润并处理任何问题。" .. + "您需要注意一点,医院周围的空气对细菌繁殖,传染病流行非常适宜。" .. + "如果您没有保持医院的清洁,则将面对传染病的流行。" .. + "赚取$150,000,并使医院价值超过$140,000。", + level12 = + "您现在遇到了最大的挑战。" .. + "我们为您的成功感到由衷地高兴,卫生部为您准备了一项顶级工作;他们需要有人建造另一个超级医院,赚钱的同时获取较高的声望。" .. + "您可以购买任何需要的土地,治疗各种疾病赢得各种奖励。" .. + "动心了吗?" .. + "赚取$650,000,治愈750个病人,使声望达到800就可以胜利过关。", + level3 = + "这次您将在一个富裕地区建造医院。" .. + "卫生部希望您能够在这里赚取更多的利润。" .. + "开始时您被要求获取好的声望,但是一旦医院步入正轨,就可以集中精力赚取更多的钱。" .. + "有可能会发生紧急事件。" .. + "也就是说一次会有大量病人就诊,且他们的病情都一样。" .. + "在时间限制内如果能够治愈他们,则不仅可以拿到奖金,声望也会提高。" .. + "一些疾病如猫王综合症等有可能发生,因此最好建造一间手术中心和附属病房。" .. + "胜利条件是赚取$20,000。", + level10 = + "随着您的经验不断增长,卫生部要求您集中精力提高药品的治疗效果。" .. + "有人对您颇有微辞,为此您必须使所有的药物都非常有效。" .. + "另外,一定要降低医疗事故的发生次数,减少死亡人数。" .. + "作为提示,您需要为建造胶桶留一些空地。" .. + "使所有药物的疗效都达到80%%,声望达到650且在银行帐户上有$500,000,这样就可以胜利过关。", + level11 = + "现在您有机会建造一座终极医院。" .. + "该地区享有极高的声望,因此卫生部希望能够看到最好的医院建造在这里。" .. + "我们希望您能够赚取大量的金钱,获得很高的声望,并能够成功地处理任何事件。" .. + "这是一项非常重要的工作。" .. + "这需要您的努力工作。" .. + "注意一点,该区域常常会看到不明飞行物。因此请让您的员工做好准备迎接不速之客。" .. + "您的医院价值需要达到$240,000,在银行帐户内需要$500,000,且声望需要达到700。", + level18 = "", } humanoid_name_starts = { [1] = "欧得", @@ -3181,9 +3214,50 @@ cost = "花费:", } menu = { - debug = " DEBUG", - display = " 显示", - file = " 文件", - options = " 选项", - charts = " 图表", + debug = "除错", + display = "显示", + file = "文件", + options = "选项", + charts = "图表", } +menu_display.shadows = " 影子 " +menu_display.mcga_lo_res = " MCGA低分辨率 " +cheats_window.cheats.earthquake = "制造地震" +confirmation.maximum_screen_size = "你使用的分辨率比 3000 x 2000 大。大的分辨率是可行的,但是要维持一个可以接受的帧率你需要好点的硬件。是否继续?" +confirmation.music_warning = "選擇MP3檔為你的音樂之前,你需要有 smpeg.dll 或者你的作業系統的版本,否則你在遊戲裡不會有任何音樂。是否繼續?" +menu_options_wage_increase.deny = " 拒绝 " +menu_options_wage_increase.grant = " 允许 " +tooltip.options_window.select_language = "选择语言" +tooltip.options_window.select_resolution = "选择分辨率" +tooltip.options_window.language_dropdown_item = "选择 %s 为语言" +tooltip.options_window.audio_button = "开关所有的声音" +tooltip.options_window.resolution = "在此分辨率下运行游戏" +tooltip.options_window.audio_toggle = "开关" +tooltip.options_window.fullscreen = "應該在全屏還是窗口模式運行" +tooltip.options_window.apply = "应用此分辨率" +tooltip.options_window.cancel = "取消" +tooltip.options_window.folder_button = "文件夹选项" +tooltip.options_window.customise_button = "更多可以改变游戏体验的选项" +tooltip.cheats_window.cheats.earthquake = "制造地震" +tooltip.new_game_window.difficulty = "选择游戏难度" +tooltip.new_game_window.player_name = "输入你游戏中的名字" +tooltip.new_game_window.start = "使用当前设置开始游戏" +tooltip.update_window.download = "前往下载页面下载CorsixTH" +tooltip.update_window.ignore = "忽略这次更新。你将在下次启动CorsixTH时再次被通知" +tooltip.folders_window.browse_font = "寻找另一个字体 ( 现在的位置: %1% )" +tooltip.folders_window.screenshots_location = "屏幕截图默认和设置文件在一起。如果不想这样,选择你想存储屏幕截图的位置。" +tooltip.folders_window.reset_to_default = "重置到默认选项" +tooltip.folders_window.back = "关闭及返回选项菜单" +tooltip.folders_window.music_location = "选择存储MP3文件的位置. 此目录必须已经存在." +tooltip.folders_window.font_location = "选择可以显示你的语言所需Unicode字体的位置,如果没有指定,你将不能使用原游戏提供字体之外的语言,例如中文和俄语.(你一定已经选了,要不怎么可以看到这句话呢?)" +tooltip.folders_window.savegames_location = "游戏存档默认和设置文件在一起。如果不想这样,选择你想存储游戏存档的位置。" +tooltip.folders_window.browse_data = "寻找主题医院安装位置 ( 現在的位置: %1% )" +tooltip.folders_window.browse = "寻找文件夹的位置" +tooltip.folders_window.browse_screenshots = "寻找另一个储存屏幕截图的位置 ( 现在的位置: %1% )" +tooltip.folders_window.browse_music = "寻找另一个存储音乐的位置 ( 现在的位置: %1% )" +tooltip.folders_window.no_font_specified = "没有指定字体的位置!" +tooltip.folders_window.not_specified = "没有指定文件夹位置!" +tooltip.folders_window.browse_saves = "寻找另一个储存游戏存档的位置 ( 现在的位置: %1% ) " +tooltip.folders_window.default = "默认位置" +tooltip.folders_window.data_location = "需要用来运行CorsixTH的主题医院的位置" +tooltip.customise_window.aliens = "因为缺少动画,默认设置下外星人DNA病人只会从紧急事件中来. 要在紧急事件以外允许有外星人DNA的病人来你的意愿,请关闭此选项。" diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/spanish.lua corsix-th-0.62/CorsixTH/Lua/languages/spanish.lua --- corsix-th-0.30/CorsixTH/Lua/languages/spanish.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/spanish.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010 Víctor González a.k.a. "mccunyao" +--[[ Copyright (c) 2016 Víctor González a.k.a. "mccunyao" Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -42,10 +42,6 @@ -- TODO adviser.multiplayer.objective_completed -- TODO adviser.multiplayer.objective_failed -fax.vip_visit_result.remarks.mediocre[2] = "¡Oh, cielos! No es un lugar agradable para ir si estás pachucho." -fax.vip_visit_result.remarks.mediocre[3] = "Si le soy sincero, es un hospital normalucho. Francamente, yo esperaba más." -fax.vip_visit_result.remarks.very_bad[1] = "¡Vaya tugurio! Voy a intentar clausurarlo." -introduction_texts.level1[7] = "Tendrás que curar a 10 personas y asegurarte de que tu reputación no sea inferior a 200." fax.emergency.num_disease = "Hay %d personas con %s y necesitan ser atendidas inmediatamente." tooltip.handyman_window.close = "Cerrar ventana" @@ -96,7 +92,6 @@ --Typos found on the official Spanish translation tooltip.rooms.dna_fixer = "El médico usa el Reparador de ADN para curar a los pacientes con ADN alienígena" diseases.broken_heart.cause = "Causa - alguien más rico, más joven y más delgado que el paciente." -fax.vip_visit_result.remarks.very_bad = "Estoy horrorizado. ¡Y a esto lo llama un hospital! Me voy de cañas..." fax.emergency.locations[1] = "Planta química González" fax.emergency.locations[3] = "Centro de plantas acuáticas" fax.emergency.locations[5] = "Congreso de bailarines rusos" @@ -104,9 +99,528 @@ fax.emergency.locations[9] = "Emporio petroquímico usado Díaz y Díaz" fax.epidemic.cover_up_explanation_2 = "Si un inspector sanitario te visita y encuentra una epidemia encubierta tomará medidas drásticas en tu contra." fax.epidemic.disease_name = "Tus médicos han descubierto una variedad contagiosa de %s." +tooltip.main_menu.continue = "Continuar la última partida guardada." +tooltip.watch.epidemic = "Epidemia: tiempo que queda para encubrir la epidemia. Cuando este tiempo expire O un paciente contagioso abandone tu hospital, un Inspector de Sanidad puede visitarte. El botón activa o desactiva el modo vacuna. Pulsa en un paciente para que lo vacune una Enfermera." +tooltip.watch.hospital_opening = "Tiempo de construcción: es el tiempo que queda para que tu hospital sea declarado abierto. Si pulsas el botón verde abrirás el hospital inmediatamente." +rooms_short.decontamination = "Descontaminación" +adviser.room_requirements.op_need_another_surgeon = "Tienes que contratar a otro cirujano para poder usar el quirófano." +adviser.information.patient_abducted = "Los alienígenas han raptado a uno de tus pacientes." +adviser.praise.plants_thriving = "Muy bien. Tus plantas están muy lozanas. Tienen un aspecto maravilloso. Si las mantienes así podrás ganar un premio." +adviser.level_progress.reputation_good_enough = "De acuerdo, tu reputación lo es bastante buena para ganar este nivel, manténla por encima de %d y soluciona otros problemas para terminar." +adviser.staff_place_advice.only_nurses_in_room = "Sólo pueden trabajar las Enfermeras en el(la) %s" +adviser.tutorial.select_receptionists = "Haz click en el icono que parpadea para ver qué recepcionistas están disponibles." +rooms_long.decontamination = "Consulta de Descontaminación" +dynamic_info.staff.ability = "Habilidad" +dynamic_info.staff.actions.going_to_repair = "Yendo a reparar %s" +dynamic_info.object.queue_expected = "Fila esperada: %d" +fax.vip_visit_result.remarks.super[1] = "¡Qué hospital tan eficaz! La próxima vez que esté gravemente enfermo, llevadme allí." +research.categories.drugs = "Investigación farmacéutica" +transactions = { + machine_replacement = "Coste de máquina de reemplazo", + eoy_trophy_bonus = "Primas por trofeo Fin de Año", + drinks = "Ingreso: Máquinas de bebidas", + jukebox = "Ingreso: Gramolas", + cheat = "Dinero de trampas", + eoy_bonus_penalty = "Primas/Multas en fin de año", +} +confirmation.return_to_blueprint = "¿Seguro que quieres sustituir el(la) %s por $%d?" +staff_descriptions = { + misc = { + [9] = "Le gusta hacer surf. ", + [10] = "Le gusta el piragüismo. ", + [11] = "Destila whisky. ", + [12] = "Es un experto en formación. ", + [13] = "Le gusta el cine francés. ", + [15] = "Conduce coches de carreras. ", + [25] = "Participó en un concurso. ", + [26] = "Colecciona metralla de la segunda guerra mundial. ", + [29] = "Pone furiosos a los insectos rociándolos con desodorante. ", + }, + good = { + [3] = "Sabe de todo.", + }, +} +progress_report.percentage_pop = "% población" +letter = { + [1] = { + [1] = "¡Hola, %s!//", + [2] = "¡Estupendo! Diriges este hospital de una manera excelente. Los peces gordos del Ministerio de Sanidad queremos saber si estarías interesado en hacerte cargo de un gran proyecto. Hay un trabajo para el que creemos eres la persona perfecta. El sueldo sería de %d. Piénsalo.//", + }, + [2] = { + [1] = "¡Hola, %s!//", + [2] = "¡Felicidades! Has realizado notables mejoras en tu hospital. Tenemos otra cosa de la que podrías encargarte, si te apetece un cambio y afrontar nuevos retos. No tienes que aceptar, pero estaría bien que lo hicieras. El sueldo es de %d//", + }, + [3] = { + [1] = "¡Hola, %s!//", + [2] = "Has dirigido con notable acierto este hospital. Creemos que tienes un brillante futuro y nos gustaría ofrecerte un puesto en otra parte. El sueldo sería de %d y creemos que te encantaría el reto que ello supondría.//", + }, + [4] = { + [1] = "¡Hola, %s!//", + [2] = "¡Felicidades! En el Ministerio estamos muy impresionados por tu capacidad como director de hospital. Eres sin duda una persona valiosa para el Departamento de Sanidad, pero creemos que preferirías un trabajo más cualificado. Recibirías un sueldo de %d, si bien la decisión es tuya.//", + }, + [5] = { + [1] = "¡Hola, %s!//", + [2] = "Saludos de nuevo. Respetamos tus deseos de no trasladarte de tu estupendo hospital, pero te pedimos que lo reconsideres. Te ofreceremos un mejor sueldo de %d si decides marcharte a otro hospital y te encargas de la dirección del mismo.//", + }, + [6] = { + [1] = "¡Hola, %s!//", + [2] = "Recibe nuestros saludos. Sabemos lo mucho que has disfrutado de tu estancia en esta institución, tan agradable y bien dirigida, pero creemos que ahora deberías pensar en tu futuro. Naturalmente, tendrías un sueldo de %d si decidieras trasladarte. Merece la pena que lo pienses.//", + }, + [7] = { + [1] = "¡Hola, %s!//", + [2] = "¡Buenos días! El Ministerio de Sanidad quisiera saber si vas a reconsiderar tu decisión de quedarte en tu hospital. Comprendemos que tienes un estupendo hospital, pero creemos que harías muy bien en aceptar un trabajo más estimulante, con un sueldo de %d.//", + }, + [8] = { + [1] = "¡Hola, %s!//", + [2] = "Buenas de nuevo. Recibimos tu negativa a nuestra última carta, en la que te ofrecíamos un puesto de dirección en otro hospital y un alto sueldo de %d. No obstante, creemos que deberías reconsiderar esta decisión. Como verás, tenemos el trabajo perfecto para ti.//", + }, + [9] = { + [1] = "¡Hola, %s!//", + [2] = "Has demostrado ser el mejor director de hospital en la larga y azarosa historia de la medicina. Este importantísimo logro no puede quedar sin recompensa, por lo que nos gustaría ofrecerte el puesto de Director Jefe de Todos los Hospitales. Es un puesto honorífico, con un sueldo de %d. Tendrás una presentación con todos los honores y la gente te demostrará su reconocimiento vayas donde vayas.//", + }, + [10] = { + [1] = "¡Hola, %s!//", + [2] = "Enhorabuena, has gestionado tus hospitales satisfactoriamente. Este logro te permitirá viajar dónde quieras, con una paga de %d y una limusina. Aunque por supuesto esperamos que en tus viajes, no defraudes a tu público y sigas promocionando los hospitales.//" + }, + [11] = { + [1] = "¡Hola, %s!//", + [3] = "Eres un ejemplo para todos los hombres de bien y todo el mundo, sin excepción, te considera una persona de enorme valía.//", + }, + [12] = { + [1] = "¡Hola, %s!//", + [2] = "Tu exitosa carrera como el mejor director de hospital desde Moisés está llegando a su fin. No obstante, has provocado tal efecto en los círculos médicos, que el Ministerio quiere ofrecerte un sueldo de %s sólo por actuar en nuestro nombre inaugurando festejos, botando barcos y organizando coloquios. ¡El mundo entero te aclamaría y serías un excelente relaciones públicas!//", + }, +} +tooltip.staff_window.ability = "Nivel de cualificación" +tooltip.policy.diag_termination = "Se mantendrá el diagnóstico de un paciente hasta que los médicos estén seguros del porcentaje de DETENER, o hasta que se hayan usado todos los diagnosticadores" +tooltip.staff_list.ability = "Muestra el nivel de habilidad de estos empleados" + +introduction_texts = { + level1 = + "¡Bienvenido a tu primer hospital!//" .. + "Para hacer que empiece a funcionar, coloca una recepción, construye una consulta y contrata a una recepcionista y a un médico. " .. + "Luego espera a que lleguen los pacientes. " .. + "Sería una buena idea que construyeras una consulta de psiquiatría y contrataras a un psiquiatra. " .. + "Una farmacia y una enfermera son fundamentales para curar a tus pacientes. " .. + "Cuidado con los casos malignos de pacientes cabezudos; se solucionan pronto en la consulta de inflatoterapia. " .. + "Tendrás que curar a 10 personas y asegurarte de que tu reputación no sea inferior a 200.", + + level2 = + "Hay una gran variedad de indisposiciones en esta zona.//" .. + "Prepara tu hospital para tratar a más pacientes y proyecta la construcción de un Departamento de Investigación. " .. + "Recuerda que debes mantener limpio el hospital y procura conseguir que tu reputación sea lo más alta posible. Tratarás enfermedades como la Lengua Larga, así que necesitarás una consulta de laringología. " .. + "También puedes construir un cardiómetro para diagnosticar nuevas enfermedades. " .. + "Estas dos consultas deberán ser investigadas antes de construirlas. También puedes comprar más terreno para ampliar tu hospital. Para ello, utiliza un mapa de la ciudad. ", + "Intenta alcanzar una reputación de 300, un saldo bancario de 10.000 dólares y cura a 40 personas.", + + level3 = + "Esta vez colocarás tu hospital en una zona acaudalada.//" .. + "El Ministerio de Sanidad espera que consigas curar a muchos pacientes. " .. + "Tendrás que ganarte una buena reputación para empezar, pero una vez que el hospital empiece a funcionar, concéntrate en ganar todo el dinero que puedas. " .. + "También puede haber urgencias. " .. + "Se producen cuando llega mucha gente que padece la misma enfermedad. " .. + "Si los curas dentro de un plazo determinado, conseguirás aumentar tu reputación y ganar una prima extra. " .. + "Habrá enfermedades, como el síndrome de rey, y deberás tener presupuesto para construir un quirófano y una enfermería adyacente. " .. + "Tienes que ganar 20.000 dólares para superar este nivel.", + + level4 = + "Haz que todos tus pacientes estén contentos, atiéndelos con la mayor eficacia e intenta que mueran los menos posibles.//" .. + "Tu reputación está en juego, así que procura aumentarla todo lo que puedas. " .. + "No te preocupes demasiado por el dinero; Lo irás ganando a medida que crezca tu reputación. " .. + "También podrás formar a tus médicos para ampliar sus conocimientos: " .. + "ellos podrán curar a los pacientes más difíciles. " .. + "Alcanza una reputación por encima de 500.", + + level5 = + "Este será un hospital concurrido, que tratará casos muy variados.//" .. + "Tus médicos acaban de salir de la facultad, por lo que es fundamental que construyas una sala de formación para que alcancen el nivel de formación necesario. " .. + "Sólo tienes tres especialistas para enseñar a tu personal inexperto, así que procura que estén contentos. " .. + "Tienes que tener en cuenta que el hospital está ubicado encima de la falla geológica de San Androide. " .. + "Siempre hay riesgo de terremoto. " .. + "Los terremotos provocarán daños importantes en tus máquinas y alterarán el buen funcionamiento de tu hospital. " .. + "Aumenta tu reputación hasta 400 y consigue unos ingresos de 50.000 dólares para triunfar. También debes curar a 200 pacientes. ", + + level6 = + "Utiliza toda tu capacidad para conseguir un hospital que funcione bien y consiga curar a muchos pacientes y que pueda tratar cualquier caso que presenten los enfermos.//" .. + "Estás avisado de que el ambiente, aquí, es especialmente propenso a gérmenes e infecciones. " .. + "A menos que mantengas una escrupulosa limpieza en tu institución, tendrás que hacer frente a una serie de epidemias entre los pacientes. " .. + "Procura obtener unos ingresos de 20.000 dólares y que el valor de tu hospital supere los 140.000 dólares. ", + + level7 = + "Aquí estarás bajo la estricta vigilancia del Ministerio de Sanidad, así que procura que tus cuentas tengan unos ingresos excelentes y que aumente tu reputación.//" .. + "No podemos permitirnos que haya muertes innecesarias; no son nada buenas para el negocio. " .. + "Asegúrate de que tu personal está en plena forma y de que tienes todos los equipos necesarios. " .. + "Consigue una reputación de 600, y un saldo bancario de 200.000 dólares.", + + level8 = + "De ti depende que puedas construir el hospital más eficiente y rentable posible.//" .. + "La gente de por aquí es bastante adinerada, así que sabléalos todo lo que puedas. " .. + "Recuerda, curar a la gente está muy bien, pero lo que de verdad NECESITAS es su dinero. " .. + "Despluma vivos a estos pacientes. " .. + "Acumula 300.000 dólares para completar este nivel. ", + + level9 = + "Después de ingresar dinero en la cuenta bancaria del Ministerio y pagar una nueva limusina para el Ministro, ahora puedes dedicarte a crear un buen hospital para cuidar a los enfermos y necesitados. " .. + "Aquí tendrás un montón de problemas diferentes. " .. + "Si tu personal tiene una buena formación y cuentas con suficientes consultas, podrás resolver cualquier situación. " .. + "Tu hospital tendrá que valer 200.000 dólares y necesitarás tener 400.000 dólares en el banco. " .. + "Si no lo consigues no podrás terminar el nivel.", + + level10 = + "Además de ocuparte de curar todas las enfermedades que pueda haber, el Ministerio te pide que emplees algo de tiempo en aumentar la eficacia de tus medicinas.//" .. + "Ha habido algunas quejas por parte de D. Salutísimo, el Perro Guardián de la Salud, así que debes procurar que todas tus medicinas sean sumamente eficaces para quedar bien. " .. + "También debes asegurarte de que tu hospital tenga una reputación intachable. Procura que mueran pocos pacientes. " .. + "Como sugerencia, deberías dejar espacio para un baño gelatinoso. " .. + "Para ganar, tus medicinas deberán tener una eficacia de, al menos, un 80%, tienes que conseguir una reputación de 650 y guardar 500.000 dólares en el banco.", + + level11 = + "Tienes la oportunidad de construir el no va más en hospitales. " .. + "Esta es una zona de enorme prestigio y al Ministerio le gustaría que éste fuera el mejor hospital. " .. + "Esperamos que ganes mucho dinero, alcances una excelente reputación y te ocupes de todos los casos que se presenten. " .. + "Este es un trabajo importante. " .. + "Tendrás que ser muy hábil para llevarlo a cabo. " .. + "También debes tener en cuenta que se han visto ovnis en la zona. Asegúrate de que tu personal esté preparado para recibir alguna visita inesperada. " .. + "Tu hospital tendrá que alcanzar un valor de 240.000 dólares, necesitarás tener 500.000 dólares en el banco y una reputación de 700.", + + level12 = + "Ahora te enfrentas al mayor de los retos. " .. + "El Ministerio ha quedado impresionado con tus logros y tiene una tarea difícil para ti, quieren que se construya otro magnífico hospital, que tenga unos excelentes ingresos y una reputación increíble. " .. + "También se espera que compres todo el terreno que puedas, cures todo (y queremos decir todas las enfermedades) y ganes todos los premios. " .. + "¿Crees que podrás conseguirlo? " .. + "Gana 650.000 dólares, cura a 750 personas y consigue una reputación de 800 para ganar este nivel. ", + + level13 = + "Tu increíble habilidad como director de hospital ha atraído la atención de la División Secreta Especial del Servicio Secreto Especial. " .. + "Tienen un trabajo especial para ti. Hay un hospital infestado de ratas que necesita un exterminador eficiente. " .. + "Tienes que matar todas las ratas que puedas antes de que el personal de Mantenimiento limpie toda la suciedad. " .. + "¿Crees que eres apto para la misión?", + + level14 = + "Aún tienes un reto más: el hospital sorpresa totalmente imprevisible. " .. + "Si consigues tener éxito, serás el ganador de todos los ganadores. " .. + "Y no esperes que sea pan comido, porque es la tarea más difícil que jamás afrontarás. " .. + "¡Buena suerte!", + + level15 = + "Bien, estos son los mecanismos básicos para poner en marcha un hospital.//" .. + "Tus Médicos van a necesitar toda la ayuda que puedan obtener para diagnosticar a algunos de los pacientes. " .. + "Puedes ayudarles construyendo otros equipos de diagnóstico como la Sala de Diagnóstico General.", + + level16 = + "Una vez que hayas diagnosticado a alguno de los pacientes necesitarás construir salas de tratamiento y clínicas para curarles: " .. + "puedes comenzar con una Farmacia, y necesitarás una Enfermera que dispense las medicinas en la Farmacia.", + + level17 = + "Un último aviso: estate atento a tu Reputación, es lo que atraerá pacientes a tu establecimiento. " .. + "¡Si no matas a mucha gente y los mantienes razonablemente felices no deberías tener muchos problemas en este nivel!//" .. + "Ahora es cosa tuya, buena suerte y todo eso.", + + demo = + "¡Bienvenido al hospital de demostración!//" .. + "Por desgracia, la versión de demostración solo contiene este nivel. Sin embargo, tienes más que suficiente para estar entretenido por un rato. " .. + "Te enfrentarás a varias enfermedades que necesitan de ciertas habitaciones para su cura. De vez en cuando pueden surgir emergencias. Y necesitarás " .. + "investigar sobre las enfermedades construyendo un Departamento de investigación. " .. + "Tu objetivo es ganar 100.000 dólares, que el valor de tu hospital llegue hasta 70.000 dólares y tengas una reputación de 700, con un porcentaje de pacientes curados del 75%. " .. + "Procura que tu reputación no caiga por debajo de 300 y que no mates a más del 40% de tus pacientes, o fracasarás.//" .. + "¡Buena suerte!", +} + +town_map.area = "Zona" +trophy_room = { + rats_killed = { + trophies = { + [2] = "Mereces este premio de la Federación Matarratas por tu excepcional habilidad para eliminar ratas, demostrándolo al acabar con %s ejemplares.", + [3] = "Se te concede el Trofeo Exterminador de Ratas por tu gran habilidad para eliminar %d ratas en tu hospital el año pasado.", + }, + }, + hosp_value = { + penalty = { + [1] = "Tu hospital no ha alcanzado un valor razonable. Has administrado mal el dinero. Recuerda, un buen hospital también es un hospital caro.", + }, + regional = { + [1] = "Eres una promesa de los negocios. Tu hospital es el más valioso de toda la zona.", + }, + }, + happy_patients = { + awards = { + [2] = "Los pacientes que visitaron tu hospital se sintieron más contentos con su tratamiento que en el resto de los hospitales.", + }, + penalty = { + [1] = "La gente que acude al hospital tiene una experiencia terrible. Tendrás que esforzarte más si quieres ganarte el respeto del Ministerio.", + [2] = "La gente que fue atendida en tu hospital se quejó del estado del mismo. Deberías tener más en cuenta el bienestar de los pacientes.", + }, + }, + research = { + penalty = { + [1] = "Has sido poco eficiente investigando curaciones, máquinas y medicinas nuevas. Esto no es bueno, ya que el avance tecnológico es algo fundamental.", + }, + regional_bad = { + [1] = "Los demás hospitales son mejores que el tuyo en investigación. En el Ministerio están furiosos, tu hospital debería concederle más importancia.", + }, + }, + many_cured = { + regional = { + [1] = "Se te concede el premio a la curación total por haber curado a más gente que todos los demás hospitales juntos.", + }, + awards = { + [1] = "Felicidades por curar a un montón de gente el año pasado. Un gran número de personas se sienten mucho mejor gracias a tu trabajo.", + }, + }, + best_value_hosp = { + penalty = { + [1] = "Todos los hospitales de la zona valen más que el tuyo. Haz algo respecto a esta vergonzosa situación. ¡Consigue cosas más caras!", + }, + }, + healthy_plants = { + trophies = { + [2] = "Salvar a las Plantas quiere concederte el Premio del Ecologista Mayor por mantener bien sanas las plantas de tu hospital durante el pasado año.", + }, + }, + high_rep = { + regional = { + [1] = "Por favor, acepta el Premio Bullfrog por dirigir el mejor hospital del año. ¡Disfrútalo, te lo has ganado!", + }, + }, + consistant_rep = { + trophies = { + [2] = "Felicidades por ganar el Premio Sábanas Limpias por ser el hospital con la mejor reputación del año. Te lo has merecido.", + }, + }, + wait_times = { + penalty = { + [1] = "En tu hospital, los pacientes esperan demasiado tiempo. Siempre hay colas inaceptables. Podrías tratar a tus pacientes con más eficacia si quisieras.", + }, + }, + happy_staff = { + awards = { + [2] = "Tu personal está tan contento de trabajar para ti que no pueden dejar de sonreír. Eres un director excelente.", + }, + trophies = { + [1] = "Has ganado el Premio Médico Sonriente por mantener lo más contento posible a tu personal.", + [3] = "Te concedemos el premio Copa de la Sonrisa Radiante por mantener contento a todo tu personal por encima de todo durante el año pasado.", + }, + }, + emergencies = { + award = { + [1] = "¡Felicidades! Has ganado este premio por la eficacia con la que has solucionado las urgencias. Buen trabajo.", + }, + }, +} +diseases = { + corrugated_ankles = { + cause = "Causa: Atropellar señales de tráfico en la carretera.", + symptoms = "Síntomas: Los pies no entran en los zapatos.", + cure = "Cura: Los tobillos se enderezan bebiendo una infusión ligeramente tóxica de hierbas y plantas.", + }, + jellyitis = { + cause = "Causa: Una dieta rica en gelatina y demasiado ejercicio.", + symptoms = "Síntomas: Un temblor excesivo y caerse al suelo muchas veces.", + cure = "Cura: Se sumerge al paciente durante un rato en el baño gelatinoso en una consulta especial.", + }, + kidney_beans = { + cause = "Causa: Masticar los cubitos de hielo de las bebidas.", + symptoms = "Síntomas: Dolor e ir con frecuencia al baño.", + cure = "Cura: Dos cirujanos extraen los cálculos sin rozar los bordes del riñón.", + }, + fractured_bones = { + cause = "Causa: Caída de cosas voluminosas sobre el cemento.", + symptoms = "Síntomas: Un gran crujido y la imposibilidad de usar los miembros afectados.", + cure = "Cura: Se pone una escayola, que después se quita con un láser quitaescayolas.", + }, + spare_ribs = { + cause = "Causa: Sentarse sobre suelos muy fríos.", + symptoms = "Síntomas: Malestar en el pecho.", + cure = "Cura: Dos cirujanos extraen las costillas y se las dan al paciente en una bolsita.", + }, + alien_dna = { + cause = "Causa: Enfrentarse a gigantes que tienen sangre alienígena inteligente.", + symptoms = "Síntomas: Metamorfosis gradual en alienígena y deseos de destruir nuestras ciudades.", + cure = "Cura: Se extrae el ADN con una máquina, se purifica de elementos alienígenas y se vuelve a inyectar rápidamente.", + }, + invisibility = { + cause = "Causa: El picotazo de una hormiga radiactiva (e invisible).", + symptoms = "Síntomas: Los pacientes no sufren. Muchos aprovechan su enfermedad para gastar bromas a sus familiares.", + cure = "Cura: Beber un líquido coloreado en la farmacia que hará completamente visible al paciente.", + }, + infectious_laughter = { + cause = "Causa: Una comedia clásica de situación", + symptoms = "Síntomas: No poder parar de reír y repetir frases hechas nada divertidas.", + cure = "Cura: Un psiquiatra cualificado debe recordar al paciente que su enfermedad es grave.", + }, + broken_wind = { + cause = "Causa: Usar un aparato gimnástico después de las comidas.", + symptoms = "Síntomas: Molestar a la gente que está justo detrás del paciente.", + cure = "Cura: En la farmacia se bebe rápidamente una fuerte mezcla de átomos acuosos.", + }, + chronic_nosehair = { + cause = "Causa: Oler con desprecio a aquellos que están peor que el paciente.", + symptoms = "Síntomas: Tener tanto pelo en la nariz como para hacer una peluca.", + cure = "Cura: Se toma por vía oral un jarabe quitapelo preparado en la farmacia.", + }, + bloaty_head = { + name = "Paciente cabezudo", + cause = "Causa: Oler queso y beber agua de lluvia no purificada.", + symptoms = "Síntomas: Muy incómodos para el paciente.", + cure = "Cura: Se pincha la cabeza hinchada y luego se vuelve a inflar hasta el tamaño correcto con una máquina inteligente.", + }, + serious_radiation = { + name = "Radiación grave", + cause = "Causa: Confundir isótopos de plutonio con chicle.", + symptoms = "Síntomas: Los pacientes que padecen esta enfermedad se sienten muy, pero que muy mal.", + cure = "Cura: Se debe dar al paciente una buena ducha descontaminadora.", + }, + ruptured_nodules = { + cause = "Causa: Tirarse de cabeza al agua fría.", + symptoms = "Síntomas: Imposibilidad de sentarse cómodamente.", + cure = "Cura: Dos cirujanos cualificados colocan ciertas partes con manos firmes.", + }, + gastric_ejections = { + cause = "Causa: Comida mejicana o india muy condimentada.", + symptoms = "Síntomas: El paciente vomita la comida a medio digerir en cualquier momento.", + cure = "Cura: Beber un preparado astringente especial para detener los vómitos.", + }, + hairyitis = { + cause = "Causa: Exposición prolongada a la luna.", + symptoms = "Síntomas: Los pacientes experimentan un aumento del olfato.", + cure = "Cura: Una máquina de electrólisis elimina el vello y cierra los poros.", + }, + sweaty_palms = { + cause = "Causa: Temer las entrevistas de trabajo.", + symptoms = "Síntomas: Dar la mano al paciente es como coger una esponja empapada.", + cure = "Cura: Un psiquiatra debe discutir a fondo con el paciente sobre esta enfermedad inventada.", + }, + diag_x_ray = { + name = "Diag. de rayos X", + }, + the_squits = { + cause = "Causa: Comer pizza que se ha encontrado debajo de la cocina.", + symptoms = "Síntomas: ¡Agh! Seguro que te los puedes imaginar.", + cure = "Cura: Una mezcla de sustancias viscosas preparada en la farmacia solidifica las tripas del paciente.", + }, + slack_tongue = { + name = "Lengua caída", + cause = "Causa: Hablar sin parar sobre culebrones.", + symptoms = "Síntomas: La lengua crece hasta cinco veces su tamaño original.", + cure = "Cura: Se coloca la lengua en el acortalenguas y se elimina de forma rápida, eficaz y dolorosa.", + }, + pregnancy = { + cause = "Causa: Cortes de electricidad en zonas urbanas.", + symptoms = "Síntomas: Comer por antojo con el consecuente malestar de estómago.", + cure = "Cura: Se extrae al bebé en el quirófano, se limpia y se entrega al paciente.", + }, + sleeping_illness = { + cause = "Causa: Una glándula del sueño hiperactiva en el paladar.", + symptoms = "Síntomas: Deseo imperioso de echarse una cabezadita en cualquier parte.", + cure = "Cura: Una enfermera administra una elevada dosis de un poderoso estimulante.", + }, + transparency = { + cause = "Causa: Lamer el yogur que queda en las tapas de los envases.", + symptoms = "Síntomas: La carne se transparenta y se ve horrible.", + cure = "Cura: Tomar un preparado de agua enfriada y coloreada en la farmacia.", + }, + broken_heart = { + cause = "Causa: Alguien más rico, más joven y más delgado que el paciente.", + symptoms = "Síntomas: Llorar y reír después de pasarse horas rompiendo fotos de las vacaciones", + cure = "Cura: Dos cirujanos abren el pecho y miman con delicadeza el corazón mientras contienen la respiración.", + }, + unexpected_swelling = { + cause = "Causa: Cualquier cosa imprevista.", + symptoms = "Síntomas: Inflamación.", + cure = "Cura: Sólo puede reducirse la inflamación con una lanceta durante una operación que requiere dos cirujanos.", + }, + discrete_itching = { + cause = "Causa: Insectos diminutos con los dientes afilados.", + symptoms = "Síntomas: Rascarse, lo que conduce a una inflamación de la parte afectada.", + cure = "Cura: El paciente bebe un jarabe pegajoso que evita que la piel pique.", + }, + third_degree_sideburns = { + cause = "Causa: Anhelar con ansia los años 70.", + symptoms = "Síntomas: Pelo largo, ropa ancha, zapatos con plataformas y mucho maquillaje.", + cure = "Cura: El personal psiquiátrico debe, empleando técnicas actualizadas, convencer al paciente de que esta moda es horrible.", + }, + uncommon_cold = { + cause = "Causa: Pequeñas partículas de moco en el aire.", + symptoms = "Síntomas: Mucosidad, estornudos y pulmones descoloridos.", + cure = "Cura: Beber un gran trago de una medicina para la tos anormal que se fabrica en la farmacia con ingredientes especiales.", + }, + heaped_piles = { + cause = "Causa: Permanecer de pie junto a refrigeradores de agua.", + symptoms = "Síntomas: El paciente se siente como si se sentara sobre una bolsa de canicas.", + cure = "Cura: Una bebida agradable, aunque muy ácida, disuelve las hemorroides internas.", + }, + golf_stones = { + cause = "Causa: Inhalar el gas venenoso que contienen las pelotas de golf.", + symptoms = "Síntomas: Delirar y sentir mucha vergüenza.", + cure = "Cura: Dos cirujanos operan para extraer los cálculos.", + }, + baldness = { + cause = "Causa: Contar mentiras e inventar historias para ser famoso.", + symptoms = "Síntomas: Tener la cabeza brillante y pasar vergüenza.", + cure = "Cura: El pelo se cose a la cabeza del paciente con una dolorosa máquina.", + }, + fake_blood = { + cause = "Causa: El paciente suele ser la víctima de todas las bromas.", + symptoms = "Síntomas: Fluido rojo en las venas que se evapora al contacto con la ropa.", + cure = "Cura: Este problema sólo se resuelve con tratamiento psiquiátrico.", + }, + gut_rot = { + cause = "Causa: El jarabe para la tos, a base de whisky, de la Sra. McGuiver.", + symptoms = "Síntomas: El paciente no tose, pero tampoco tiene paredes en el estómago.", + cure = "Cura: Una enfermera administra una variada disolución de sustancias químicas para revestir el estómago.", + }, + iron_lungs = { + cause = "Causa: Contaminación urbana mezclada con restos de kebab.", + symptoms = "Síntomas: Capacidad para aspirar fuego y gritar debajo del agua.", + cure = "Cura: Dos cirujanos realizan una operación para eliminar las partes duras del pulmón en el quirófano.", + }, + king_complex = { + cause = "Causa: El espíritu del rey se introduce en la mente del paciente y se apodera de ella.", + symptoms = "Síntomas: Calzar unos zapatos de ante teñidos y comer hamburguesas.", + cure = "Cura: Un psiquiatra le dice al paciente lo ridículo o ridícula que está.", + }, + tv_personalities = { + cause = "Causa: Ver la televisión durante el día.", + symptoms = "Síntomas: Tener la ilusión de presentar en la tele un programa de cocina.", + cure = "Cura: Un psiquiatra experto debe convencer al paciente de que venda su televisor y se compre una radio.", + }, +} +room_descriptions = { + staff_room = { + [1] = "Sala de personal//", + [2] = "Tu personal se cansa cuando realiza su trabajo. Necesitan esta sala para descansar y reponer energías. El personal cansado es más lento, pide más dinero, comete más errores y al final dimite. Merece la pena construir una sala para el personal que tenga muchos pasatiempos. Asegúrate de que hay sitio para varios miembros del personal al mismo tiempo. ", + }, + gp = { + [2] = "Esta es la consulta más importante de tu hospital. Los nuevos pacientes son enviados aquí para averiguar qué es lo que les pasa. Entonces, o se les hace otro diagnóstico o se les manda a una consulta donde puedan ser curados. Quizá quieras construir otra consulta si la primera tiene mucho trabajo. Cuanto más grande sea la consulta y cuantos más objetos pongas en ella, mayor prestigio tendrá el médico. Lo mismo sucede con todas las consultas abiertas.//", + }, + blood_machine = { + [3] = "El transfusiómetro requiere un médico. También necesita mantenimiento. ", + }, + x_ray = { + [2] = "Los rayos X fotografían el interior del paciente empleando una radiación especial para ayudar al personal a descubrir lo que le pasa.//", + [3] = "La consulta de rayos X requiere un médico. También necesita mantenimiento. ", + }, + ultrascan = { + [1] = "Ultra escáner//", + }, + training = { + [1] = "Sala de formación//", + }, + fracture_clinic = { + [2] = "Los pacientes que tienen la desgracia de tener fracturas vienen aquí. El quitaescayolas emplea un potente láser industrial para cortar las escayolas más duras, causando al paciente sólo una pequeña molestia.//", + }, + slack_tongue = { + [2] = "Los pacientes a los que se les diagnostica lengua caída en la consulta serán enviados aquí para recibir tratamiento. El médico utilizará una máquina de alta tecnología para estirar la lengua y acortarla, con lo que el paciente volverá a estar sano.//", + }, + jelly_vat = { + [1] = "Baño gelatinoso//", + }, + general_diag = { + [1] = "Diagnosis general//", + }, +} -- An override for the squits becoming the the squits see issue 1646 -adviser.research.drug_improved_1 = "Tu Departamento de Investigación ha mejorado el medicamento para la %s." +adviser.research.drug_improved_1 = "Tu departamento de investigación ha mejorado el medicamento para la %s." ------------------------------- NEW STRINGS ------------------------------- date_format = { daymonth = "%1% %2:months%", @@ -115,21 +629,26 @@ object.litter = "Basura" tooltip.objects.litter = "Basura: Un paciente la ha tirado porque no ha encontrado una papelera." +object.rathole = "Ratonera" +tooltip.objects.rathole = "El hogar de una familia de ratas a la que le ha gustado la suciedad de tu hospital." + tooltip.fax.close = "Cierra esta ventana sin borrar el mensaje." tooltip.message.button = "Haz clic izquierdo para abrir el mensaje." tooltip.message.button_dismiss = "Haz clic izquierdo para abrir el mensaje, clic derecho para rechazarlo." tooltip.casebook.cure_requirement.hire_staff = "Necesitas contratar empleados para realizar este tratamiento." tooltip.casebook.cure_type.unknown = "Todavía no sabes cómo curar esta enfermedad." tooltip.research_policy.no_research = "En este momento no se está investigando ningún apartado de esta categoría." -tooltip.research_policy.research_progress = "Progreso para terminar el siguiente descubrimiento de esta categoría: %1%/%2%" +tooltip.research_policy.research_progress = "Progreso del siguiente descubrimiento de esta categoría: %1%/%2%" + +menu["player_count"] = "CANTIDAD DE JUGADORES" menu_file = { load = " (MAYUS+L) CARGAR ", save = " (MAYUS+S) GUARDAR ", - restart = " (MAYUS+R) REINICIAR", + restart = " (MAYUS+R) REINICIAR ", quit = " (MAYUS+Q) SALIR " } - +--These menus lack uppercase accented characters, so lowercase are a must. menu_options = { sound = " (ALT+S) SONIDO ", announcements = " (ALT+A) ANUNCIOS ", @@ -159,8 +678,8 @@ } menu_options_wage_increase = { - grant = " CONCEDER ", - deny = " RECHAZAR ", + grant = " CONCEDER ", + deny = " RECHAZAR ", } -- Add F-keys to entries in charts menu (except briefing), also town_map was added. @@ -178,6 +697,7 @@ menu_debug = { jump_to_level = " CAMBIAR DE NIVEL ", + connect_debugger = " (CTRL + C) CONECTAR A SERVIDOR DBGp LUA ", transparent_walls = " (X) PAREDES TRANSPARENTES ", limit_camera = " LIMITAR CáMARA ", disable_salary_raise = " DESACTIVAR SUBIDA DE SUELDO ", @@ -185,6 +705,7 @@ make_debug_patient = " CREAR PACIENTE DE DEPURACIóN ", cheats = " (F11) TRUCOS ", lua_console = " (F12) CONSOLA LUA ", + debug_script = " (MAYúS + D) EJECUTAR SCRIPT DE DEPURACIóN ", calls_dispatcher = " LLAMAR A CONTROLADOR ", dump_strings = " VOLCAR TEXTOS DEL JUEGO ", dump_gamelog = " (CTRL+D) VOLCAR REGISTRO DEL JUEGO ", @@ -205,8 +726,14 @@ byte_7 = " BYTE 7 ", parcel = " PARCELA ", } +menu_player_count = { + players_1 = " 1 JUGADOR ", + players_2 = " 2 JUGADORES ", + players_3 = " 3 JUGADORES ", + players_4 = " 4 JUGADORES ", +} adviser = { - room_forbidden_non_reachable_parts = "Si colocas la habitación en este lugar, bloquearás el acceso a ciertas partes del hospital.", + room_forbidden_non_reachable_parts = "Si colocas la habitación ahí bloquearás el acceso a ciertas partes del hospital.", warnings = { no_desk = "¡Deberías construir una mesa de recepción y contratar a una recepcionista en algún momento!", no_desk_1 = "¡Si quieres que los pacientes vayan a tu hospital, necesitas contratar a una recepcionista y construir una mesa donde pueda trabajar!", @@ -224,13 +751,17 @@ falling_4 = "¡Esto es un hospital, no un parque de atracciones!", falling_5 = "¡Este no es lugar para tirar personas al suelo, que están enfermas!", falling_6 = "¡Esto no es una bolera, no trates así a los enfermos!", - research_screen_open_1 = "Para acceder a la pantalla de investigación, tienes que construir un Departamento de Investigación.", + research_screen_open_1 = "Para acceder a la pantalla de investigación, tienes que construir un departamento de investigación.", research_screen_open_2 = "No se pueden realizar investigaciones en este nivel.", researcher_needs_desk_1 = "Un investigador necesita una mesa en la que trabajar.", researcher_needs_desk_2 = "Tu investigador agradece que le hayas dado un descanso. Si pretendías tener a más personas investigando, tienes que dar a cada uno una mesa para que trabajen.", researcher_needs_desk_3 = "Cada investigador necesita una mesa para trabajar.", nurse_needs_desk_1 = "Cada enfermera necesita una mesa para trabajar.", nurse_needs_desk_2 = "Tu enfermera agradece que le hayas dado un descanso. Si pretendías tener a más personas trabajando en la enfermería, tienes que dar a cada una una mesa para que trabajen.", + low_prices = "Estás cobrando muy poco por el uso de %s. Así atraerás a más personas a tu hospital, pero no te darán muchos beneficios.", + high_prices = "Estás cobrando mucho por el uso de %s. Así tendrás muchos beneficios a corto plazo, pero harás que los pacientes dejen de venir.", + fair_prices = "El precio de %s parece justo.", + patient_not_paying = "¡Un paciente se ha ido sin pagar por %s porque es demasiado caro!", }, cheats = { th_cheat = "¡Felicidades, has desbloqueado los trucos!", @@ -242,6 +773,7 @@ dynamic_info.patient.actions.no_gp_available = "Esperando a que construyas una consulta" dynamic_info.staff.actions.heading_for = "Dirigiéndose a %s" dynamic_info.staff.actions.fired = "Despedido" +dynamic_info.patient.actions.epidemic_vaccinated = "Ya no soy contagioso" progress_report.free_build = "CONSTRUCCIÓN LIBRE" @@ -258,10 +790,20 @@ vip_visit_result = { remarks = { free_build = { - "¡Tienes un muy buen hospital! No es difícil mantenerlo sin limitaciones económicas, ¿eh?", - "No soy economista, pero hasta yo podría dirigir este hospital, si me entiendes...", - "Un hospital muy bien cuidado. ¡Pero ojo con la crisis financiera! Ah... que no tienes que preocuparte de eso.", - } + "¡Su hospital es muy bueno! No es difícil mantenerlo sin limitaciones económicas, ¿eh?", + "No soy economista, pero hasta yo podría dirigir este hospital, si usted me entiende...", + "Un hospital muy bien cuidado. ¡Pero ojo con la crisis financiera! Ah... que a usted no le afecta.", + }, + mediocre = { + [1] = "Bueno, los he visto peores. Pero debería hacer algunas mejoras.", + [2] = "¡Oh, cielos! No es un lugar agradable para ir si estás pachucho.", + [3] = "Si le soy sincero, es un hospital normalucho. Francamente, yo esperaba más.", + }, + very_bad = { + [1] = "¡Vaya tugurio! Voy a intentar clausurarlo.", + [2] = "Nunca he visto un hospital tan espantoso. ¡Qué vergüenza!", + [3] = "Estoy horrorizado. ¡Y a esto lo llama un hospital! Me voy de cañas...", + }, } } } @@ -270,6 +812,9 @@ dear_player = "Estimado %s,", custom_level_completed = "¡Bien hecho! ¡Has completado todos los objetivos de este nivel personalizado!", return_to_main_menu = "¿Quieres volver al menú principal o seguir jugando?", + campaign_level_completed = "¡Buen trabajo! Has superado este nivel, ¡pero aún no has acabado!\n ¿Te interesaría aceptar un puesto en el hospital %s?", + campaign_completed = "¡Increíble! Has conseguido superar todos los niveles. Ya puedes relajarte y disfrutar mientras hablas de tus logros en los foros de Internet. ¡Buena suerte!", + campaign_level_missing = "Parece que el siguiente nivel de esta campaña está desaparecido. (Nombre: %s)", } install = { @@ -281,13 +826,16 @@ } misc.not_yet_implemented = "(aún no implementado)" -misc.no_heliport = "O no se han descubierto enfermedades, o no hay un helipuerto en este nivel. Quizás necesitas comprar una mesa de recepción y contratar a una recepcionista." +misc.no_heliport = "O no se han descubierto enfermedades, o no hay un helipuerto en este nivel. Quizás te haga falta comprar una mesa de recepción y contratar a una recepcionista." main_menu = { new_game = "Campaña", + custom_campaign = "Campaña personalizada", custom_level = "Misión individual", + continue = "Continuar partida", load_game = "Cargar partida", options = "Opciones", + map_edit = "Editor de mapas", savegame_version = "Versión del guardado: ", version = "Versión: ", exit = "Salir", @@ -295,9 +843,12 @@ tooltip.main_menu = { new_game = "Empezar el primer nivel de la campaña.", + custom_campaign = "Juega una campaña creada por la comunidad.", custom_level = "Construir tu hospital en un nivel concreto.", + continue = "Reanuda tu última partida guardada.", load_game = "Cargar una partida guardada.", options = "Ajustar la configuración.", + map_edit = "Crear un mapa personalizado.", exit = "¡No, no, por favor, no te vayas!", quit = "Estás a punto de salir de CorsixTH. ¿Seguro que quieres continuar?", } @@ -315,11 +866,23 @@ custom_game_window = { caption = "Partida personalizada", free_build = "Construcción libre", + load_selected_level = "Comenzar", } tooltip.custom_game_window = { - start_game_with_name = "Información de este escenario, que utiliza: %s Informe: %s", + choose_game = "Haz clic en un nivel para ver más información sobre el mismo.", free_build = "Marca esta casilla si quieres jugar sin dinero ni condiciones para ganar o perder.", + load_selected_level = "Cargar e iniciar el nivel seleccionado.", +} + +custom_campaign_window = { + caption = "Campaña personalizada", + start_selected_campaign = "Comenzar campaña", +} + +tooltip.custom_campaign_window = { + choose_campaign = "Selecciona una campaña para ver más información sobre la misma.", + start_selected_campaign = "Cargar el primer nivel de esta campaña.", } save_game_window = { @@ -329,7 +892,17 @@ tooltip.save_game_window = { save_game = "Sobrescribir guardado %s", - new_save_game = "Introduce el nombre de la nueva partida guardada", + new_save_game = "Introduce el nombre de la partida guardada.", +} + +save_map_window = { + caption = "Guardar mapa (%1%)", + new_map = "Nuevo mapa", +} + +tooltip.save_map_window = { + map = "Sobrescribir el mapa %s.", + new_map = "Introduce el nombre del mapa guardado.", } menu_list_window = { @@ -350,7 +923,7 @@ option_off = "No", fullscreen = "Pantalla completa", resolution = "Resolución", - custom_resolution = "Personalizada...", + custom_resolution = "Personalizar...", width = "Ancho", height = "Alto", audio = "Sonido", @@ -363,7 +936,7 @@ } tooltip.options_window = { - fullscreen = "Hace que el juego se ejecute en pantalla completa o en una ventana.", + fullscreen = "Ejecuta el juego en pantalla completa o en una ventana.", fullscreen_button = "Pulsa aquí para activar el modo de pantalla completa.", resolution = "Cambia la resolución en la que funcionará el juego.", select_resolution = "Selecciona una nueva resolución.", @@ -372,12 +945,12 @@ apply = "Aplica la resolución seleccionada.", cancel = "Vuelve sin cambiar la resolución.", audio_button = "Activa o desactiva todos los sonidos del juego.", - audio_toggle = "Activar o desactivar", + audio_toggle = "Activa o desactiva el sonido.", customise_button = "Más opciones para personalizar tu experiencia de juego.", - folder_button = "Opciones de carpeta", + folder_button = "Opciones de carpetas.", language = "Selecciona el idioma de los textos.", select_language = "Selecciona el idioma del juego.", - language_dropdown_item = "Utilizar el idioma %s.", + language_dropdown_item = "Seleccionar el idioma %s.", back = "Cierra la ventana de opciones.", } @@ -386,33 +959,33 @@ option_on = "Activado", option_off = "Desactivado", back = "Volver", - movies = "Control global de vídeos", - intro = "Reproducir introducción", - paused = "Construir durante una pausa", - volume = "Tecla para bajar el volumen", + movies = "Control de vídeos", + intro = "Mostrar introducción", + paused = "Construir en pausa", + volume = "Tecla de volumen", aliens = "Pacientes alienígenas", fractured_bones = "Fracturas óseas", - average_contents = "Contenidos normales", + average_contents = "Contenidos habituales", } tooltip.customise_window = { - movies = "Control global de vídeos, esto permite desactivar todos los vídeos.", - intro = "Activa o desactiva el vídeo de introducción, necesitas tener activado el control global de vídeos si quieres ver la introducción cada vez que arranques CorsixTH.", - paused = "En Theme Hospital, el jugador solo podía utilizar el menú superior si la partida estaba en pausa. Esto también se hace en CorsixTH de forma predeterminada, pero al activar esta opción, podrás acceder a ese menú mientras el juego esté en pausa.", + movies = "Control global de vídeos, permite desactivar todos los vídeos.", + intro = "Activa o desactiva el vídeo de introducción. Necesitas activar el control global de vídeos si quieres ver la introducción cada vez que arranques CorsixTH.", + paused = "En Theme Hospital el jugador solo podía utilizar el menú superior si la partida estaba en pausa. CorsixTH funciona así de forma predeterminada, pero al activar esta opción se puede acceder a todo mientras el juego esté en pausa.", volume = "Si la tecla de bajar volumen abre también el botiquín, utiliza esta opción para cambiar el acceso directo a Mayúsculas + C.", aliens = "Debido a la falta de animaciones decentes disponibles, hemos hecho que los pacientes con ADN alienígena solo aparezcan en una emergencia. Para permitir que los pacientes con ADN alienígena puedan visitar tu hospital, desactiva esta opción.", fractured_bones = "Debido a una animación deficiente, hemos hecho que no existan pacientes con Fracturas óseas femeninas. Para permitir que las pacientes con Fracturas óseas visiten tu hospital, desactiva esta opción.", - average_contents = "Activa esta opción si quieres que el juego recuerde que objetos adicionales sueles añadir cuando construyes habitaciones.", - back = "Cerrar este menú y volver al menú de Opciones", + average_contents = "Activa esta opción si quieres que el juego recuerde los objetos adicionales que sueles añadir cuando construyes habitaciones.", + back = "Cerrar este menú y volver al menú de opciones.", } folders_window = { caption = "Ubicación de carpetas", data_label = "Datos de TH", font_label = "Fuente", - music_label = "MP3s", - savegames_label = "Partidas guardadas", - screenshots_label = "Capturas de pantalla", + music_label = "MP3", + savegames_label = "Part. guardadas", + screenshots_label = "Capt. de pantalla", -- next four are the captions for the browser window, which are called from the folder setting menu new_th_location = "Aquí puedes especificar una nueva carpeta de instalación de Theme Hospital. El juego se reiniciará en cuanto selecciones la nueva carpeta.", savegames_location = "Selecciona la carpeta que quieres utilizar para tus partidas guardadas.", @@ -425,16 +998,16 @@ browse = "Buscar la ubicación de la carpeta", data_location = "La carpeta con la instalación del Theme Hospital original, necesario para ejecutar CorsixTH.", font_location = "La ubicación de una fuente de letra capaz de mostrar caracteres Unicode necesarios para tu idioma. Si no se indica, no podrás seleccionar idiomas que tengan más caracteres de los que puede dar el juego original, por ejemplo, ruso y chino.", - savegames_location = "La carpeta de partidas guardadas está junto al archivo de configuración de forma predeterminada, y se utilizará para almacenar las partidas guardadas. En caso de que no sea lo más adecuado, puedes seleccionar otra carpeta buscando la carpeta que quieres usar.", - screenshots_location = "Las capturas de pantalla se guardan de forma predeterminada en una carpeta junto al archivo de configuración. En caso de que no sea lo más adecuado, puedes seleccionar otra carpeta buscando la carpeta que quieres usar.", + savegames_location = "La carpeta de partidas guardadas se ubica de forma predeterminada junto al archivo de configuración y se utilizará para almacenar las partidas guardadas. Si no te gusta, puedes seleccionar otra buscando la carpeta que quieres usar.", + screenshots_location = "Las capturas de pantalla se guardan de forma predeterminada en una carpeta junto al archivo de configuración. Si no te gusta, puedes seleccionar otra buscando la carpeta que quieres usar.", music_location = "Selecciona una carpeta con tus archivos de música en formato MP3. Necesitas una carpeta ya existente, entonces podrás buscarla.", browse_data = "Buscar otra ubicación con una instalación de Theme Hospital. (Ubicación actual: %1%)", browse_font = "Buscar otro archivo de fuente de letra. (Ubicación actual: %1%)", browse_saves = "Buscar otra ubicación para tu carpeta de partidas guardadas. (Ubicación actual: %1%)", browse_screenshots = "Buscar otra ubicación para tu carpeta de capturas de pantalla. (Ubicación actual: %1%)", browse_music = "Buscar otra ubicación para tu carpeta de música. (Ubicación actual: %1%)", - no_font_specified = "¡Aún no has especificado la ubicación de la fuente!", - not_specified = "¡Aún no has especificado una carpeta!", + no_font_specified = "¡No se ha especificado una carpeta de fuentes!", + not_specified = "¡No se ha especificado una carpeta!", default = "Ubicación predeterminada", reset_to_default = "Vuelve a asignar la carpeta a su ubicación predeterminada.", -- original_path = "Carpeta actual con la instalación del Theme Hospital original", -- where is this used, I have left if for the time being? @@ -457,8 +1030,8 @@ new_game_window = { caption = "Campaña", player_name = "Nombre", - option_on = "Activada", - option_off = "Desactivada", + option_on = "Activado", + option_off = "Desactivado", difficulty = "Dificultad", easy = "Novato (Fácil)", medium = "Médico (Normal)", @@ -469,7 +1042,7 @@ } tooltip.new_game_window = { - player_name = "Introduce el nombre con el que te llamará el juego.", + player_name = "Introduce el nombre que usará el juego para dirigirse a ti.", difficulty = "Selecciona el nivel de dificultad con el que quieres jugar.", easy = "Si acabas de conocer los juegos de simulación, esta dificultad es para ti.", medium = "Esta es la dificultad intermedia, si no estás seguro de a dónde quieres ir.", @@ -486,7 +1059,7 @@ tooltip.lua_console = { textbox = "Introduce aquí el código Lua que quieres ejecutar", - execute_code = "Ejecutar el códugo Lua que has introducido", + execute_code = "Ejecutar el código Lua que has introducido", close = "Cerrar la consola", } @@ -494,28 +1067,36 @@ dialog_missing_graphics = "Los archivos de datos de la demo no contienen esta ventana.", save_prefix = "Error al guardar la partida: ", load_prefix = "Error al cargar la partida: ", + no_games_to_contine = "No hay partidas guardadas.", load_quick_save = "Error, no existe el guardado rápido y por tanto no se puede cargar, pero tranquilo, que acabamos de generar uno para ti.", map_file_missing = "¡No se ha podido encontrar el archivo de mapa %s de este nivel!", minimum_screen_size = "Introduce un tamaño de pantalla como mínimo de 640x480.", unavailable_screen_size = "El tamaño de pantalla que has seleccionado no está disponible en el modo de pantalla completa.", alien_dna = "NOTA: Los pacientes alienígenas no tienen animaciones para sentarse, abrir puertas, llamar a puertas, etc. Por lo tanto, al igual que en Theme Hospital, para hacer estas cosas aparentarán cambiar a una imagen normal y luego volverán a su estado. Los pacientes con ADN alienígena solo aparecerán si el archivo del nivel lo indica.", fractured_bones = "NOTA: La animación de las pacientes femeninas con Fracturas óseas no es perfecta.", + could_not_load_campaign = "Error al cargar la campaña %s.", + could_not_find_first_campaign_level = "No se ha encontrado el primer nivel de la campaña %s.", +} + +warnings = { + levelfile_variable_is_deprecated = "Aviso: El nivel %s contiene una definición de variable obsoleta en el archivo del nivel." .. + "'%LevelFile' ha sido renombrado como '%MapFile'. Avisa al creador del mapa para que actualice el nivel.", } confirmation = { - needs_restart = "Para cambiar este ajuste, antes debes reiniciar CorsixTH. Se perderá todo el progreso que no hayas guardado. ¿Seguro que quieres continuar?", + needs_restart = "Para cambiar este ajuste debes reiniciar CorsixTH. Se perderá todo el progreso que no hayas guardado. ¿Seguro que quieres continuar?", abort_edit_room = "Ahora mismo estás construyendo o editando una habitación. Si has colocado todos los objetos necesarios será terminada, de lo contrario se borrará. ¿Quieres continuar?", - maximum_screen_size = "El tamaño de pantalla que has introducido es mayor que 3000 x 2000. Es posible utilizar una resolución más grande, pero necesitará de un ordenador mejor para que la velocidad de fotogramas sea aceptable. ¿Seguro que quieres continuar?", - music_warning = "Antes de seleccionar el uso de MP3s para tu música dentro del juego, necesitarás tener el archivo smpeg.dll, o el equivalente para tu sistema operativo, o de lo contrario no tendrás música en el juego. Actualmente no existe un archivo equivalente para sistemas de 64 bits. ¿Quieres continuar?", + maximum_screen_size = "El tamaño de pantalla que has introducido es mayor que 3000x2000. Es posible utilizar una resolución más grande, pero necesitarás un ordenador potente para que la velocidad de fotogramas sea aceptable. ¿Seguro que quieres continuar?", + music_warning = "Nota: Necesitas el archivo smpeg.dll o el equivalente para tu sistema operativo, de lo contrario no tendrás música en el juego. ¿Quieres continuar?", } information = { custom_game = "Bienvenido a CorsixTH. ¡Diviértete con este mapa personalizado!", no_custom_game_in_demo = "La versión demo no permite jugar a mapas personalizados.", cannot_restart = "Esta partida personalizada se guardó antes de que se implementara la característica de reiniciar.", - very_old_save = "Desde que empezaste a jugar en este nivel, el juego ha recibido muchas actualizaciones. Para asegurarte de que todas las características funcionen como es debido, considera empezarlo de nuevo.", + very_old_save = "Desde que empezaste a jugar en este nivel, el juego ha recibido muchas actualizaciones. Para asegurarte de que todas las características funcionen como es debido, deberías pensar en volver a empezar.", level_lost = { - "¡Qué pena! Has fracasado en este nivel. ¡Mejor suerte la próxima vez!", + "¡Qué pena! Has fracasado en este nivel. ¡Ya tendrás más suerte la próxima vez!", "La razón por la que has perdido es:", reputation = "Tu reputación ha caído por debajo de %d.", balance = "Tu cuenta bancaria ha llegado a tener menos de %d.", @@ -531,25 +1112,25 @@ totd_window = { tips = { - "Todo hospital necesita una mesa de recepción y una consulta para empezar a funcionar. Después de eso, depende del tipo de pacientes que visite tu hospital. Eso sí, una farmacia siempre es una buena opción.", - "Las máquinas como el inflador necesitan mantenimiento. Utiliza a un bedel o dos para reparar tus máquinas, o te arriesgarás a herir a tus pacientes y a tu personal.", - "Tras un tiempo, tu personal se cansará. Asegúrate de construir una sala de personal, para que puedan relajarse.", - "Coloca varios radiadores para mantener calentitos a tu personal y empleados, o se enfadarán. Usa el mapa superior para buscar los puntos de tu hospital que no tengan calefacción.", - "El nivel de habilidad de un doctor influye significativamente la calidad y la velocidad de sus diagnósticos. Coloca a un doctor habilidoso en tu consulta, y no necesitarás tantas salas de diagnóstico adicionales.", - "Los doctores pueden mejorar sus habilidades aprendiendo de un asesor en la sala de entrenamiento. Si el asesor tiene una calificación especial (cirujano, psiquiatra o investigador), también pasará sus conocimientos a sus pupilos.", + "Todo hospital necesita una mesa de recepción y una consulta para empezar a funcionar. A partir de ahí depende del tipo de pacientes que visite tu hospital. Eso sí, una farmacia siempre es una buena opción.", + "Las máquinas como el inflador necesitan mantenimiento. Contrata a un par de bedeles para que reparen tus máquinas o podrías herir a tus pacientes y a tu personal.", + "Tu personal se cansará pasado un tiempo. Procura construir una sala de personal para que puedan relajarse.", + "Coloca varios radiadores para mantener calentitos a tu personal y empleados o se enfadarán. Usa el mapa de la ciudad para buscar las zonas que no tienen calefacción en tu hospital.", + "El nivel de cualificación de un médico influye en la calidad y la velocidad de sus diagnósticos. Si asignas un médico cualificado a tu consulta no necesitarás tantas consultas de diagnosis.", + "Los principiantes y los médicos pueden mejorar su cualificación si un especialista les enseña en la sala de formación. Si el especialista tiene una cualificación especial (cirujano, psiquiatra o investigador), también enseñará sus conocimientos a sus alumnos.", "¿Has probado a meter el número de emergencias (112) en el fax? ¡Asegúrate de tener el sonido activado!", - "Puedes ajustar algunos parámetros como la resolución y el idioma del juego en la ventana de Opciones que encontrarás tanto en el menú principal como dentro del juego.", - "¿Has seleccionado el Castellano, pero sigues viendo textos en inglés en algún lugar? ¡Ayúdanos avisando de las líneas de texto que estén en inglés para que podamos traducirlas!", + "Puedes ajustar algunos parámetros como la resolución y el idioma del juego en la ventana de opciones, que se encuentra tanto en el menú principal como dentro del juego.", + "¿Has seleccionado el castellano, pero sigues viendo textos en inglés en algún lugar? ¡Avísanos de qué líneas de texto están en inglés para que podamos traducirlas!", "¡El equipo de CorsixTH busca refuerzos! ¿Te interesa programar, traducir o crear gráficos para CorsixTH? Contáctanos en nuestro foro, lista de correo o canal IRC (corsix-th en freenode).", - "Si encuentras un fallo, infórmalo en nuestro registro de fallos: th-issues.corsix.org", - "Cada nivel tiene unos requisitos concretos que debes conseguir antes de poder continuar al siguiente nivel. Mira en la ventana de estado para ver como llevas los objetivos del nivel.", - "Si quieres editar o quitar una habitación ya existente, puedes hacerlo con el botón de Editar habitación que verás en la barra de herramientas inferior.", - "Cuando tengas muchos pacientes esperando, puedes averiguar rápidamente quienes están esperando para una habitación en concreto pasando el cursor del ratón por encima de la habitación.", - "Pulsa en la puerta de una habitación para ver su cola. Aquí puedes manipular ciertos aspectos, como reordenar la cola o mandar a un paciente hacia otra habitación.", + "Si encuentras un fallo, puedes enviarnos un informe en nuestro registro de fallos: th-issues.corsix.org", + "Cada nivel tiene unos requisitos concretos que debes conseguir antes de poder avanzar al siguiente nivel. Mira en la ventana de estado para ver como llevas los objetivos del nivel.", + "Si quieres editar o quitar una habitación ya existente, puedes hacerlo con el botón Editar habitación, en la barra de herramientas inferior.", + "Cuando tengas muchos pacientes esperando, puedes averiguar quienes están esperando para una habitación en concreto pasando el cursor por encima de la habitación.", + "Pulsa en la puerta de una habitación para ver su cola. Aquí puedes afinar ciertas cosas, como el orden la cola o mandar a un paciente hacia otra habitación.", "El personal que no esté contento pedirá aumentos de sueldo con frecuencia. Asegúrate de que tu personal trabaja en un entorno cómodo para evitar que esto ocurra.", - "Los pacientes tendrán sed mientras esperan en tu hospital, ¡y aún más si subes la calefacción! Coloca máquinas de bebidas en lugares estratégicos para ganar un dinerillo extra.", - "Puedes cancelar el progreso del diagnóstico de un paciente de forma prematura y adivinar la cura si ya has descubierto la enfermedad. Ten en cuenta que esto aumentará el riesgo de darle el tratamiento equivocado, lo que matará al paciente.", - "Las emergencias pueden ser una buena forma de llevarte algo de dinero extra, siempre y cuando tengas la capacidad suficiente para ocuparte de los pacientes de la emergencia a tiempo.", + "Los pacientes tendrán sed mientras esperan en tu hospital, ¡y más si subes la calefacción! Coloca máquinas de bebidas en lugares estratégicos para ganar un dinerillo extra.", + "Puedes cancelar el progreso del diagnóstico de un paciente y adivinar la cura si ya has descubierto la enfermedad. Ten en cuenta que esto aumentará el riesgo de darle el tratamiento equivocado, lo que matará al paciente.", + "Las emergencias pueden ser una buena forma de ganar un dinerillo extra, siempre y cuando tengas la capacidad suficiente para ocuparte de los pacientes de la emergencia a tiempo.", }, previous = "Siguiente consejo", next = "Consejo anterior", @@ -577,11 +1158,15 @@ emergency = "Crear una emergencia", vip = "Crear un VIP", earthquake = "Crear terremoto", + epidemic = "Generar un paciente contagioso", + toggle_infected = "Mostrar/ocultar iconos de infección", create_patient = "Crear un paciente", end_month = "Fin de mes", end_year = "Fin del año", lose_level = "Perder el nivel", win_level = "Ganar el nivel", + increase_prices = "Subir precios", + decrease_prices = "Bajar precios", }, close = "Cerrar", } @@ -594,23 +1179,26 @@ emergency = "Crea una emergencia.", vip = "Crea un VIP.", earthquake = "Crea un terremoto.", + epidemic = "Crea un paciente contagioso que podría provocar una epidemia.", + toggle_infected = "Muestra u oculta los iconos de infección para la epidemia activa.", create_patient = "Crea un paciente en el borde del mapa.", end_month = "Avanza hasta el fin del mes actual.", end_year = "Avanza hasta el final del año actual.", lose_level = "Hace que pierdas el nivel actual.", win_level = "Hace que ganes el nivel actual.", + increase_prices = "Aumenta los precios en un 50% (200% máximo).", + decrease_prices = "Reduce los precios en un 50% (50% mínimo).", } } introduction_texts = { - demo = { - "¡Bienvenido al hospital de demostración!", - "Por desgracia, la versión de demostración solo contiene este nivel. Sin embargo, tienes más que suficiente para estar entretenido por un rato.", - "Te enfrentarás a varias enfermedades que necesitan de ciertas habitaciones para su cura. De vez en cuando pueden surgir emergencias. Y necesitarás investigar sobre las enfermedades construyendo un Departamento de investigación.", - "Tu objetivo es ganar 100.000 dólares, que el valor de tu hospital llegue hasta 70.000 dólares y tengas una reputación de 700, con un porcentaje de pacientes curados del 75%.", - "Procura que tu reputación no caiga por debajo de 300 y que no mates a más del 40% de tus pacientes, o fracasarás.", - "¡Buena suerte!", - }, + demo = + "¡Bienvenido al hospital de demostración!" .. + "Por desgracia, la demo sólo contiene este nivel. ¡Pero tiene más que suficiente para distraerte un buen rato!" .. + "Te enfrentarás a varias enfermedades que deberás curar construyendo varias salas. De vez en cuando pueden aparecer emergencias. Necesitarás investigar varios tipos de consultas utilizando una consulta de investigación." .. + "Tu objetivo es ganar 100.000 dólares, una reputación de 700, que tu hospital tenga un valor de 70.000 dólares y que hayas curado al menos al 75% de tus pacientes." .. + "Procura que tu reputación no caiga por debajo de 300 y no mates a más del 40% de tus pacientes o perderás el nivel." .. + "¡Suerte!", } calls_dispatcher = { @@ -623,7 +1211,7 @@ } tooltip.calls_dispatcher = { - task = "Lista de tareas - puslsa en una tarea para abrir la ventana del personal asignado y desplázate hasta la posición de la tarea.", + task = "Lista de tareas: Pulsa en una tarea para abrir la ventana del personal asignado y desplázate hasta la posición de la tarea.", assigned = "Esta opción está activada si alguien ha sido asignado a la tarea correspondiente.", close = "Cerrar la ventana de llamadas de control.", } @@ -641,6 +1229,40 @@ ignore = "Ignorar esta actualización por el momento. Volverás a ser notificado la próxima vez que ejecutes CorsixTH.", } +map_editor_window = { + pages = { + inside = "Interior", + outside = "Exterior", + foliage = "Vegetación", + hedgerow = "Setos", + pond = "Estaque", + road = "Camino", + north_wall = "Muro norte", + west_wall = "Muro oeste", + helipad = "Helipuerto", + delete_wall = "Borrar muros", + parcel_0 = "Parcela 0", + parcel_1 = "Parcela 1", + parcel_2 = "Parcela 2", + parcel_3 = "Parcela 3", + parcel_4 = "Parcela 4", + parcel_5 = "Parcela 5", + parcel_6 = "Parcela 6", + parcel_7 = "Parcela 7", + parcel_8 = "Parcela 8", + parcel_9 = "Parcela 9", + camera_1 = "Cámara 1", + camera_2 = "Cámara 2", + camera_3 = "Cámara 3", + camera_4 = "Cámara 4", + heliport_1 = "Helipuerto 1", + heliport_2 = "Helipuerto 2", + heliport_3 = "Helipuerto 3", + heliport_4 = "Helipuerto 4", + paste = "Pegar zona", + } +} + -------------------------------- UNUSED ----------------------------------- ------------------- (kept for backwards compatibility) ---------------------- diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/swedish.lua corsix-th-0.62/CorsixTH/Lua/languages/swedish.lua --- corsix-th-0.30/CorsixTH/Lua/languages/swedish.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/swedish.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2010 Manuel "Roujin" Wolf, Edvin "Lego3" Linge +--[[ Copyright (c) 2010-2016 Manuel "Roujin" Wolf, Edvin "Lego3" Linge Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -37,7 +37,10 @@ "Patienter som får diagnosen psykisk sjukdom måste uppsöka den psykiatriska avdelningen för att få behandling. Psykiatriker kan också ställa diagnoser, ta reda på vilken typ av sjukdom patienterna har och, i det fall det är mentalt behandla dem på den pålitliga gamla britsen.//", "Här behövs en läkare utbildad i psykiatri. " } -introduction_texts.level1[4] = "En bra ide vore att bygga en psykiatrisk avdelning och anställa en läkare med psykiatrisk kompetens." +introduction_texts.level1 = "Välkommen till ditt första sjukhus!//Sätt igång genom att placera ut en reception och bygga en allmänpraktik, anställ en receptionist och en läkare. " .. + "Vänta därefter på att jobben ska trilla in. En bra idé vore att bygga en psykmottagning och anställa en läkare med psykiatrisk kompetens. " .. + "Ett apotek och en syster behövs också för att du ska kunna bota dina patienter. Se upp för svåra fall av pöshuvud - ett pumprum behövs för att greja dessa. " .. + "Försök bota 10 personer och se till att ditt anseende inte sjunker under 200." tooltip.staff_list.next_person = "Visa nästa sida" tooltip.staff_list.prev_person = "Visa föregående sida" @@ -48,6 +51,9 @@ confirmation.restart_level = "Är du säker på att du vill starta om nivån?" +-- In English the squits becomes the the squits, see issue 1646. In Swedish it stays the same, but it +-- still needs to be defined. +adviser.research.drug_improved_1 = "Medicinen mot %s har förbättrats av din forskaravdelning." ------------------------------- NEW STRINGS ------------------------------- object.litter = "Skräp" tooltip.objects.litter = "Skräp: Lämnat åt sitt öde eftersom patienten inte kunde hitta någon papperskorg." @@ -67,12 +73,15 @@ tooltip.new_game_window.player_name = "Skriv in det namn du vill kallas i spelet" new_game_window.player_name = "Namn" +menu.player_count = "ANTAL SPELARE" + menu_options = { lock_windows = " LÅS FÖNSTER ", edge_scrolling = " KANTRULLNING ", - settings = " INSTÄLLNINGAR ", adviser_disabled = " MEDHJÄLPARE ", warmth_colors = " VÄRMEFÄRGER ", + wage_increase = " LÖNFÖRFRÅGNINGAR ", + twentyfour_hour_clock = " 24-TIMMARSKLOCKA " } menu_options_game_speed = { @@ -90,6 +99,11 @@ choice_3 = " GUL ORANGE RÖD ", } +menu_options_wage_increase = { + grant = " BEVIJLA ", + deny = " NEKA ", +} + -- Add F-keys to entries in charts menu (except briefing), also town_map was added. menu_charts = { bank_manager = " (F1) BANKKAMRER ", @@ -107,6 +121,7 @@ menu_debug = { jump_to_level = " HOPPA TILL NIVÅ ", + connect_debugger = " (CTRL + C) KOPPLA LUA DBGp SERVER ", transparent_walls = " (X) TRANSPARENTA VÄGGAR ", limit_camera = " BEGRÄNSA KAMERAN ", disable_salary_raise = " STÄNG AV LÖNEÖKNINGAR ", @@ -114,6 +129,7 @@ make_debug_patient = " SKAPA DEBUGPATIENT ", cheats = " (F11) FUSK ", lua_console = " (F12) LUATERMINAL ", + debug_script = " (SHIFT + D) KÖR DEBUGSKRIPT ", calls_dispatcher = " ANROPSKLARERARE ", dump_strings = " SKAPA TEXTFILER ", dump_gamelog = " (CTRL+D) DUMPA SPELLOGG ", @@ -135,6 +151,13 @@ parcel = " TOMT ", } +menu_player_count = { + players_1 = " 1 SPELARE ", + players_2 = " 2 SPELARE ", + players_3 = " 3 SPELARE ", + players_4 = " 4 SPELARE ", +} + adviser = { room_forbidden_non_reachable_parts = "Rummet kan inte placeras här eftersom delar av sjukhuset då blir oåtkomliga.", warnings = { @@ -142,7 +165,12 @@ no_desk_1 = "Om du vill att det ska komma patienter till sjukhuset så behövs en receptionist och en reception där hon kan jobba!", no_desk_2 = "Snyggt jobbat, det måste vara ett världsrekord: nästan ett år och inte en enda patient! Om du vill fortsätta som chef på det här sjukhuset så måste du anställa en receptionist och bygga en reception som hon kan jobba i!", no_desk_3 = "Helt otroligt, nästan ett år och du har fortfarande ingen bemannad reception! Tror du det kommer några patienter då? Sluta leka omkring och fixa till det här nu!", + no_desk_4 = "En receptionist behöver ha en egen disk som hon kan hälsa patienterna välkomna vid", + no_desk_5 = "Det var på tiden, nu borde det snart börja dyka upp patienter!", + no_desk_6 = "Du har en receptionist, det kanske är dags att bygga en reception som hon kan arbeta vid?", + no_desk_7 = "Nu har du en reception, vad sägs om att anlita en receptionist också? Det lär inte komma några patienter förrän du gjort det!", cannot_afford = "Du har inte tillräckligt med pengar på banken för att anställa den personen!", + cannot_afford_2 = "du har inte tillräckligt med pengar på banken för att genomföra det köpet!", falling_1 = "Nämen! Det där inte kul, om du inte ser dig för var du klickar så kan någon skada sig!", falling_2 = "Sluta strula omkring, hur tror du det känns?", falling_3 = "Ajaj, det måste ha gjort ont. Ring en läkare!", @@ -151,30 +179,34 @@ falling_6 = "Det här är inte en bowlinghall, sjuka människor ska inte behandlas så!", research_screen_open_1 = "Du behöver bygga en forskningsavdelning innan du får tillgång till forskningsskärmen.", research_screen_open_2 = "På den här nivån finns det ingen möjlighet till forskning.", + researcher_needs_desk_1 = "Varje forskare behöver ett skrivbord att jobba vid.", + researcher_needs_desk_2 = "Din forskare är nöjd över att få en välbehövlig paus. Om du ville ha flera forskare aktiva samtidigt så behöver de få var sitt skrivbord.", + researcher_needs_desk_3 = "En forskare behöver alltid ett skrivbord.", + nurse_needs_desk_1 = "Varje sköterska behöver ett eget skrivbord.", + nurse_needs_desk_2 = "Din sköterska är glad att få en paus. Du kanske ville ha flera personer att jobba på avdelningen? Då behöver de var sitt skrivbord.", + low_prices = "Du tar för lite betalt för %s. Det lockar visserligen fler patienter, men du kommer inte att tjäna så mycket på var och en.", + high_prices = "Avgiften på %s är hög. Du tjänar mycket kortsiktigt, men till slut kommer du att driva iväg folk.", + fair_prices = "Avgiften på %s verkar rimlig och balanserad.", + patient_not_paying = "En patient lämnade just sjukhuset utan att betala för %s eftersom det är alldeles för dyrt!", }, cheats = { th_cheat = "Ojoj, nån vill fuska sig till segern!", - crazy_on_cheat = "Åh nej!! Alla läkare har blivit galna!", - crazy_off_cheat = "Vilken tur... läkarna har återfått förståndet.", roujin_on_cheat = "Roujin's utmaning aktiverad! Lycka till...", roujin_off_cheat = "Roujin's utmaning avaktiverad.", - hairyitis_cheat = "Pälssyndromsfusket aktiverat!", - hairyitis_off_cheat = "Pälssyndromsfusket avaktiverat.", - bloaty_cheat = "Pöshuvudsfusket aktiverat!", - bloaty_off_cheat = "Pöshuvudsfusket avaktiverat.", }, } dynamic_info.patient.actions.no_gp_available = "Väntar på att du ska bygga en allmänpraktik" dynamic_info.staff.actions.heading_for = "På väg till %s" dynamic_info.staff.actions.fired = "Sparkad" +dynamic_info.patient.actions.epidemic_vaccinated = "Jag smittar inte längre" progress_report.free_build = "FRITT BYGGANDE" fax = { choices = { return_to_main_menu = "Gå till huvudmenyn", - accept_new_level = "Gå vidare till nästa bana", + accept_new_level = "Gå vidare till nästa nivå", decline_new_level = "Fortsätt spela ett tag till", }, emergency = { @@ -194,35 +226,46 @@ letter = { dear_player = "Käre %s", - custom_level_completed = "Bra gjort! Du klarade alla mål på den här specialbanan!", + custom_level_completed = "Bra gjort! Du klarade alla mål på den här specialnivån!", return_to_main_menu = "Vill du gå tillbaka till huvudmenyn eller fortsätta spela?", + campaign_level_completed = "Bra jobbat! Du klarade nivån, men det är inte över än!\n Vill du ha jobbet som chef vid %s?", + campaign_completed = "Otroligt! Du lyckades med alla nivåer. Nu är det bara att mysa och njuta av att fylla forum överallt på nätet om dina bedrifter. Lycka till!", + campaign_level_missing = "Ledsen, men det verkar som att nästa nivå på den här kampanjen saknas. (Namn: %s)", } install = { title = "--------------------------------- CorsixTH Setup ---------------------------------", th_directory = "CorsixTH behöver en kopia av filerna från det ursprungliga spelet (eller dess demo) för att kunna köras. Använd väljaren nedan för att lokalisera mappen där Theme Hospital installerats.", + ok = "OK", exit = "Avsluta", + cancel = "Avbryt", } misc.not_yet_implemented = "(ej tillgänglig ännu)" -misc.no_heliport = "Antingen har inga sjukdomar upptäckts ännu, eller så finns det ingen helikopterplatta på den här banan." +misc.no_heliport = "Antingen har inga sjukdomar upptäckts ännu, eller så finns det ingen helikopterplatta på den här nivån." main_menu = { - new_game = "Kampanj", + new_game = "Originalkampanjen", + custom_campaign = "Nya kampanjer", custom_level = "Enskild nivå", + continue = "Fortsätt spel", load_game = "Ladda spel", options = "Alternativ", + map_edit = "Kartredigerare", savegame_version = "Sparningsversion: ", version = "Version: ", exit = "Avsluta", } tooltip.main_menu = { - new_game = "Starta bana ett i kampanjen", + new_game = "Starta nivå ett i originalkampanjen från Theme Hospital", + custom_campaign = "Spela en kampanj som är skapad av andra spelare", custom_level = "Bygg ditt sjukhus på en valfri nivå", load_game = "Ladda ett sparat spel", options = "Fixa till dina inställningar", + map_edit = "Starta kartredigeraren för att skapa din egen karta", exit = "Nej! Du vill väl inte sluta redan?", + quit = "Du håller på att avsluta CorsixTH. Är du säker på att du vill det?" } load_game_window = { @@ -236,13 +279,25 @@ } custom_game_window = { - caption = "Specialbanor", + caption = "Enskilda nivåer", free_build = "Bygg fritt", + load_selected_level = "Starta", } tooltip.custom_game_window = { - start_game_with_name = "Ladda banan %s", + choose_game = "Välj en nivå för att läsa mer om den", free_build = "Bocka för den här rutan om du vill spela utan pengar och vinst- och förlustkriterier", + load_selected_level = "Ladda och spela den valda nivån", +} + +custom_campaign_window = { + caption = "Nya kampanjer", + start_selected_campaign = "Starta kampanj", +} + +tooltip.custom_campaign_window = { + choose_campaign = "Välj en kampanj för att läsa mer om den", + start_selected_campaign = "Ladda den första nivån på den valda kampanjen", } save_game_window = { @@ -255,6 +310,16 @@ new_save_game = "Skriv namnet på den nya filen", } +save_map_window = { + caption = "Spara karta (%1%)", + new_map = "Ny karta", +} + +tooltip.save_map_window = { + map = "Skriv över kartan %s", + new_map = "Skriv ett kartnamn", +} + menu_list_window = { name = "Namn", save_date = "Senast ändrad", @@ -269,44 +334,100 @@ options_window = { caption = "Alternativ", - fullscreen = "Helskärm", option_on = "På", option_off = "Av", - data_location = "Speldatakälla", - font_location = "Typsnittsplats", + fullscreen = "Helskärm", + resolution = "Upplösning", + custom_resolution = "Anpassad...", width = "Bredd", height = "Höjd", - resolution = "Upplösning", + audio = "Globalt ljud", + customise = "Anpassa", + folder = "Mappar", language = "Spelspråk", apply = "Tillämpa", - browse = "Bläddra...", - custom_resolution = "Anpassad...", - new_th_directory = "Här kan du välja en ny plats här Theme Hospital installerats. Så fort du väljer den nya mappen kommer spelet att startas om.", - back = "Tillbaka", cancel = "Avbryt", + back = "Tillbaka", } tooltip.options_window = { + fullscreen = "Om spelet ska köras i fullskärmsläge eller fönsterläge", fullscreen_button = "Klicka för att gå mellan fönster och helskärm", + resolution = "Upplösning spelet ska köras i", + select_resolution = "Välj en ny upplösning", width = "Fyll i önskad skärmbredd", height = "Fyll i önskad skärmhöjd", - data_location = "Mapp som en installation av Theme Hospital finns i, krävs för att köra CorsixTH", - font_location = "För att kunna använda språk som inte fanns i originalspelet och som kräver fler Unicodebokstäver måste en typsnittsfil väljas. Annars går det inte att välja språk som till exempel ryska och kinesiska", - fullscreen = "Om spelet ska köras i fullskärmsläge eller fönsterläge", - language = "Text i spelet kommer att visas på det här språket", apply = "Tillämpa den valda upplösningen", - resolution = "Upplösning spelet ska köras i", + cancel = "Återvänd utan att ändra upplösning", + audio_button = "Stäng av eller sätt på allt ljud i spelet", + audio_toggle = "Slå av eller på", + customise_button = "Fler inställningar som kan ändras för att anpassa din spelupplevelse", + folder_button = "Mappinställningar", + language = "Text i spelet kommer att visas på det här språket", select_language = "Väljs spelspråk", language_dropdown_item = "Ändra till %s som språk", - select_resolution = "Välj en ny upplösning", - cancel = "Återvänd utan att ändra upplösning", - original_path = "Den just nu valda mappen där Theme Hospital installerats", - browse = "Bläddra efter en annan Theme Hospital installation. (Nuvarande: %1%)", - browse_font = "Bläddra efter en (annan) typsnittsfil. (Nuvarande: %1%)", - no_font_specified = "Ingen sökväg har valts ännu!", back = "Stäng alternativmenyn", } +customise_window = { + caption = "Extra inställningar", + option_on = "På", + option_off = "Av", + back = "Tillbaka", + movies = "Global filmkontroll", + intro = "Spela introfilmen", + paused = "Bygg i pausläge", + volume = "Tangent: volym ner", + aliens = "Utomjordingar", + fractured_bones = "Krossad patient", + average_contents = "Genomsnittsinnehåll", +} + +tooltip.customise_window = { + movies = "Välj om filmer ska spelas överhuvudtaget", + intro = "Skippa introfilmen när du startar spelet. Global filmkontroll måste vara påslagen om du spela introfilmen varje gång du laddar CorsixTH", + paused = "I Theme Hospital fick spelaren bara använda verktygsfältet längst upp när spelet var pausat. Så är det i CorsixTH också såvida du inte aktiverar funktionen att bygga även när spelet är pausat här", + volume = "Om du råkat ut för att tangenten som sänker volymen även öppnar medicinjournalen, slå på det här alternativet för att ändra snabbkommando till medicinjournalen till Shift + C", + aliens = "Eftersom det inte finns ordentliga animeringar har vi gjort så att patienter med utomjordiskt DNA endast dyker upp som akutfall. Stäng av det här för att kunna få utomjordiskt DNA-fall även som vanliga besök", + fractured_bones = "På grund av en dålig animering har vi stängt av kvinnliga patienter med frakturer (Krossad patient). Stäng av det här, så kommer det att dyka upp även kvinnor med den åkomman", + average_contents = "Om du vill att spelet ska komma ihåg vilka extra föremål du normalt sett brukar handla till nya rum, slå på detta alternativ", + back = "Stäng den här menyn och gå tillbaka till Alternativmenyn", +} + +folders_window = { + caption = "Mappinställningar", + data_label = "TH Data", + font_label = "Typsnitt", + music_label = "MP3", + savegames_label = "Sparningar", + screenshots_label = "Skärmbilder", + -- next four are the captions for the browser window, which are called from the folder setting menu + new_th_location = "Här kan du välja en ny sökväg där Theme Hospital ligger. Så fort du väljer en ny mapp kommer spelet att startas om!", + savegames_location = "Välj var sparade spel ska läggas.", + music_location = "Välj en mapp med musik i för att spela den i spelet.", + screenshots_location = "Välj vilken mapp du vill spara skärmbilder till.", + back = "Tillbaka", +} + +tooltip.folders_window = { + browse = "Bläddra efter mappsökväg", + data_location = "Mapp där originalspelet Theme Hospital finns. Krävs för att spela CorsixTH", + font_location = "Sökväg till en typsnittsfil som kan visa Unicode-tecken som krävs för ditt språk. Om detta inte är specificerat kommer du inte att kunna välja sådana språk, till exempel ryska och kinesiska", + savegames_location = "Som standard läggs sparade spel i en mapp som ligger bredvid konfigurationsfilen. Om det inte fungerar kan du välja en egen här", + screenshots_location = "Skärmbilder sparas som standard i en mapp bredvid konfigurationsfilen. Här kan du välja en annan mapp istället", + music_location = "Välj en sökväg där du har mp3-filer. Mappen måste redan finnas", + browse_data = "Bläddra efter en ny sökväg till Theme Hospital ( nuvarande sökväg: %1% )", + browse_font = "Bläddra efter en annan typsnittsfil ( nuvarande sökväg:: %1% )", + browse_saves = "Bläddra efter en annan mapp att lägga sparade spel i ( nuvarande sökväg:: %1% ) ", + browse_screenshots = "Bläddra efter en annan mapp för skärmbilder ( nuvarande sökväg:: %1% ) ", + browse_music = "Bläddra efter en annan mapp med musik ( nuvarande sökväg:: %1% ) ", + no_font_specified = "Ingen typsnittsfil vald än!", + not_specified = "Ingen sökväg vald än!", + default = "Standardsökväg", + reset_to_default = "Återställ mappen till standardsökvägen", + back = "Stäng den här dialogen och återgå till alternativmenyn", +} + font_location_window = { caption = "Välj typsnitt (%1%)", } @@ -349,22 +470,34 @@ dialog_missing_graphics = "Tyvärr innehåller demon inte den här dialogrutan.", save_prefix = "Fel när spelet skulle sparas: ", load_prefix = "Fel när spelet skulle laddas: ", + no_games_to_contine = "Det finns inga sparade spel.", + load_quick_save = "Fel, kan inte ladda en snabbsparning eftersom det inte finns någon. Men oroa dig inte, nu har vi skapat en åt dig!", map_file_missing = "Kunde inte hitta kartfilen %s till den här nivån!", minimum_screen_size = "Skärmupplösningen måste vara åtminstone 640x480.", - maximum_screen_size = "Skärmupplösningen kan inte vara större än 3000x2000.", unavailable_screen_size = "Skärmupplösningen du valde finns inte i fullskärmsläge.", + alien_dna = "NOTERA: Det finns inga animeringar för patienter med utomjordiskt DNA när de sitter ner, öppnar dörrar osv. Precis som i Theme Hospital gör de därför det i mänsklig skepnad. Dessa patienter anländer som vanligt endast om nivån du spelar definierat att sjukdomen ska finnas", + fractured_bones = "NOTERA: Animeringen för kvinnliga Krossade patienter är inte perfekt", + could_not_load_campaign = "Kunde inte ladda kampanjen %s", + could_not_find_first_campaign_level = "Kunde inte hitta den första nivån på den här kampanjen: %s", +} + +warnings = { + levelfile_variable_is_deprecated = "Notera: Nivån '%s' innehåller en föråldrad variabeldefinition i nivåfilen." .. + "'%LevelFile' har bytt namn till '%MapFile'. Meddela nivåskaparen att uppdatera nivån.", } confirmation = { needs_restart = "Att ändra denna inställning kräver en omstart av spelet. Osparad data kommer att gå förlorad. Är du säker på att du vill göra detta?", abort_edit_room = "Du håller på att bygga eller ändra ett rum. Om alla obligatoriska föremål är placerade kommer rummet att färdigställas som det är, annars tas det bort. Fortsätta?", + maximum_screen_size = "Upplösningen du valt är större än 3000 x 2000. Större upplösningar är möjliga, men kräver bättre hårdvara. Är du säker på att du vill fortsätta?", + music_warning = "Notera: När du väljer att använda mp3-filer som spelmusik behövs smpeg.dll eller motsvarande för ditt operativsystem, annars blir det ingen musik i spelet. Vill du fortsätta?", } information = { - custom_game = "Välkommen till CorsixTH. Ha nu riktigt kul med den här specialbanan!", + custom_game = "Välkommen till CorsixTH. Ha nu riktigt kul med den här specialnivån!", no_custom_game_in_demo = "Ledsen, men det går inte att spela enskilda nivåer med demofilerna.", cannot_restart = "Tyvärr sparades detta spel innan funktionen att starta om hade implementerats.", - very_old_save = "Det har hänt en hel del med spelet sedan du startade den här banan. För att vara säker på att allt fungerar som det är tänkt kan det vara bra att överväga att starta om banan.", + very_old_save = "Det har hänt en hel del med spelet sedan du startade den här nivån. För att vara säker på att allt fungerar som det är tänkt kan det vara bra att överväga att starta om nivån.", level_lost = { "Attans! Du förlorade. Bättre lycka nästa gång!", "Anledning till att du förlorade:", @@ -393,7 +526,7 @@ "Hittar du en massa text på engelska i spelet? Hjälp oss översätta färdigt till Svenska!", "Teamet bakom CorsixTH söker förstärkning! Vill du koda, översätta eller skapa grafik till spelet? Kontakta oss i forumet, på mejllistan eller i IRC-kanalen (corsix-th at freenode).", "Om du hittar en bugg, rapportera den gärna i vår bugghanterare på adressen th-issues.corsix.org.", - "Varje bana har vissa krav som ska uppfyllas innan du kan gå vidare till nästa. Kolla statusfönstret för att se hur nära målen du är.", + "Varje nivå har vissa krav som ska uppfyllas innan du kan gå vidare till nästa. Kolla statusfönstret för att se hur nära målen du är.", "Om du vill ändra eller ta bort ett existerande rum kan du göra det med hjälp av ändra rum-knappen i panelen längst ner (saxen).", "Om du ur högen av patienter vill ta reda på vilka som köar till ett visst rum är det bara att föra muspekaren över rummet.", "Klicka på dörren till ett rum för att se kön till det. Sedan går det att genomföra finlir som att ändra ordning eller skicka en patient till ett annat likadant rum.", @@ -428,11 +561,15 @@ emergency = "Skapa akutfall", vip = "Skapa VIP", earthquake = "Skapa jordbävning", + epidemic = "Skapa en smittande patient", + toggle_infected = "Visa infekterad-ikonen", create_patient = "Skapa patient", end_month = "Månadsslut", end_year = "Hoppa till nyår", lose_level = "Förlora nivå", win_level = "Vinn nivå", + increase_prices = "Öka priser", + decrease_prices = "Minska priser", }, close = "Stäng", } @@ -445,23 +582,27 @@ emergency = "Skapar ett akutfall.", vip = "Skapar en Mycket Viktig Person (VIP)", earthquake = "Skapar en jordbävning med slumpad styrka", + epidemic = "Skapar en person som smittar så att en epidemi kan starta", + toggle_infected = "Växlar mellan att visa ikoner vid en upptäckt, aktiv epidemi", create_patient = "Skapar en patient vid kanten av kartan.", end_month = "Hoppar till slutet av månaden.", end_year = "Hoppar till slutet av året.", lose_level = "Förlora nuvarande nivå.", win_level = "Vinn nuvarande nivå.", + increase_prices = "Öka alla priser med 50% (max. 200%)", + decrease_prices = "Minska alla priser med 50% (min. 50%)", } } introduction_texts = { - demo = { - "Välkommen till demosjukhuset!", - "Tyvärr innehåller demon bara denna nivå. Ändå finns det garanterat tillräckligt att göra ett tag framöver!", - "Du kommer att råka ut för diverse sjukdomar som kräver olika rum för att botas. Ibland kan olyckor hända, så att det kommer akutfall till sjukhuset. Dessutom behöver du forska för att upptäcka fler rum.", - "Målet är att tjäna $100,000, ha ett sjukhusvärde av $70,000 och 700 i anseende, samtidigt som du botar minst 75% av patienterna.", - "Se till att ditt anseende inte sjunker under 300 och att du inte dödar mer än 40% av dina patienter, annars förlorar du.", + demo = + "Välkommen till demosjukhuset!//" .. + "Tyvärr innehåller demon bara denna nivå. Ändå finns det garanterat tillräckligt att göra ett tag framöver! " .. + "Du kommer att råka ut för diverse sjukdomar som kräver olika rum för att botas. " .. + "Ibland kan olyckor hända, så att det kommer akutfall till sjukhuset. Dessutom behöver du forska för att upptäcka fler rum. " .. + "Målet är att tjäna $100,000, ha ett sjukhusvärde av $70,000 och 700 i anseende, samtidigt som du botar minst 75% av patienterna. " .. + "Se till att ditt anseende inte sjunker under 300 och att du inte dödar mer än 40% av dina patienter, annars förlorar du.//" .. "Lycka till!", - }, } calls_dispatcher = { @@ -479,6 +620,53 @@ close = "Stäng anropsklarerardialogen", } +update_window = { + caption = "Updatering tillgänglig!", + new_version = "Ny version:", + current_version = "Din version:", + download = "Gå till nedladdningssidan", + ignore = "Skippa och gå till huvudmenyn", +} + +tooltip.update_window = { + download = "gå till nedladdningssidan där du hittar den absolut senaste versionen av CorsixTH", + ignore = "Skippa updateringen just nu. Du kommer att få en ny notis nästa gång du öppnar CorsixTH", +} + +map_editor_window = { + pages = { + inside = "Inomhus", + outside = "Utomhus", + foliage = "Grönska", + hedgerow = "Häck", + pond = "Damm", + road = "Väg", + north_wall = "Nordlig vägg", + west_wall = "Västlig vägg", + helipad = "Helikopterplatta", + delete_wall = "Ta bort väggar", + parcel_0 = "Tomt 0", + parcel_1 = "Tomt 1", + parcel_2 = "Tomt 2", + parcel_3 = "Tomt 3", + parcel_4 = "Tomt 4", + parcel_5 = "Tomt 5", + parcel_6 = "Tomt 6", + parcel_7 = "Tomt 7", + parcel_8 = "Tomt 8", + parcel_9 = "Tomt 9", + camera_1 = "Kamera 1", + camera_2 = "Kamera 2", + camera_3 = "Kamera 3", + camera_4 = "Kamera 4", + heliport_1 = "Heliport 1", + heliport_2 = "Heliport 2", + heliport_3 = "Heliport 3", + heliport_4 = "Heliport 4", + paste = "Klistra in", + } +} + date_format.daymonth = "%1% %2:months%" original_credits[301] = ":Operations" diff -Nru corsix-th-0.30/CorsixTH/Lua/languages/traditional_chinese.lua corsix-th-0.62/CorsixTH/Lua/languages/traditional_chinese.lua --- corsix-th-0.30/CorsixTH/Lua/languages/traditional_chinese.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/languages/traditional_chinese.lua 2018-07-21 11:13:17.000000000 +0000 @@ -316,14 +316,13 @@ }, } introduction_texts = { - demo = { - [1] = "Welcome to the demo hospital!", - [2] = "Unfortunately the demo version only contains this level. However, there is more than enough to do here to keep you busy for a while!", - [3] = "You will encounter various diseases that require different rooms to cure. From time to time, emergencies may occur. And you will need to research additional rooms using a research room.", - [4] = "Your goal is to earn $100,000, have a hospital value of $70,000 and a reputation of 700, while having cured at least 75% of your patients.", - [5] = "Make sure your reputation does not fall below 300 and that you don't kill off more than 40% of your patients, or you will lose.", - [6] = "Good luck!", - }, + demo = + "Welcome to the demo hospital!//" .. + "Unfortunately the demo version only contains this level. However, there is more than enough to do here to keep you busy for a while! " .. + "You will encounter various diseases that require different rooms to cure. From time to time, emergencies may occur. And you will need to research additional rooms using a research room. " .. + "Your goal is to earn $100,000, have a hospital value of $70,000 and a reputation of 700, while having cured at least 75% of your patients." .. + "Make sure your reputation does not fall below 300 and that you don't kill off more than 40% of your patients, or you will lose.//" .. + "Good luck!", } object = { litter = "Litter", @@ -2820,127 +2819,109 @@ }, } introduction_texts = { - level17 = { - [1] = "最後的警告-隨時關注您的聲望-這是真正吸引病人前來就診的關鍵。", - [2] = "如果您沒有醫死太多的病人,且使就診病人保持快樂,則不必太擔心聲望!", - [3] = "決定權就在您的手中。祝您好運。", - }, - level1 = { - [1] = "歡迎來到您的第一座醫院!//", - [2] = "首先要擺放服務台,建造一般診斷室,並雇用一名接待員和一名醫生。", - [3] = "隨後就可以等待開張了。", - [4] = "建造精神病診斷治療室並雇用一名精神病醫生是一個好主意。", - [5] = "藥房和護士也是治療病人所必需的。", - [6] = "建造一個充氣機房間就可以治療頭部腫脹患者。", - [7] = "您需要治癒10個病人,並使聲望保持在200以上。", - }, - level9 = { - [1] = "當填滿了衛生署的銀行帳戶並為部長大人購買了一輛轎車後,您現在又要開始新的工作了。", - [2] = "在這裡您要面對很多問題。", - [3] = "只有擁有足夠經驗充分的員工和房間,您才能夠順利過關。", - [4] = "醫院價值需要達到$200,000,且銀行帳戶上要有$400,000。", - [5] = "如果無法達到上述要求,則無法勝利完成任務。", - }, - level2 = { - [1] = "在該區域內還有一些其它的疾病。", - [2] = "建造醫院從而可以治療更多的病人,並應該考慮建造研究部門。", - [3] = "記住保持內部的清潔,從而使聲望盡可能地高-您將遇到患有舌頭鬆弛症的病人,因此需要建造舌頭診治房間。", - [4] = "您也可以建造心電圖房間來幫助診斷疾病。", - [5] = "這些房間都需要經過研究才能夠被建造。現在你可以購買其它土地擴展醫院-使用城鎮地圖就可以購買土地。", - [6] = "目標是聲望300,銀行現金為10000,且治癒40個病人。", - }, - level7 = { - [1] = "在這裡您將受到衛生署的密切監察,因此要在賺錢的同時,努力提高自己的聲望。", - [2] = "我們無法處理太多的醫療事故-這對於醫院的運營是十分不利的。", - [3] = "確認所有員工都很快樂,並確認已經購買了所有需要的儀器裝備。", - [4] = "聲望需要達到600,且銀行裡需要有$200,000。", - }, - level5 = { - [1] = "醫院將非常繁忙,處理各種各樣的病人。", - [2] = "醫生都是剛剛畢業的實習醫生,因此需要建造一間培訓室對他們進行培訓,提高能力。", - [3] = "您只有3名專家可以幫助培訓這些員工,因此一定要讓專家快樂。", - [4] = "另外要注意的是,醫院的位置不是很好。", - [5] = "經常會發生地震。", - [6] = "地震將對醫院中的機器產生損壞,從而影響醫院的運營。", - [7] = "使您聲望達到400以上,現金達到$50,000。另外需要治癒200個病人。", - }, - level4 = { - [1] = "使所有的病人快樂,保持治療的高效率並儘量降低死亡人數。", - [2] = "聲望是十分重要的,因此儘量贏得更高的聲望。", - [3] = "不要太多擔心收入情況-當聲望提高了,收入也自然會提高。", - [4] = "您需要培訓您的醫生,拓寬他們的能力。", - [5] = "這樣他們就可以更好的為病人服務。", - [6] = "勝利條件是聲望達到500以上。", - }, - level14 = { - [1] = "這裡還有一個挑戰-一個充滿驚奇的醫院。", - [2] = "如果您能夠成功完成這個任務,則您將成為所有勝利者中的佼佼者。", - [3] = "不要認為完成這個任務就像吃蛋糕一樣,這將是您所遇到的最艱苦的工作。", - [4] = "祝您好運!", - }, - level15 = { - [1] = "好的,下面是管理醫院的一些技巧。//", - [2] = "醫生需要各種幫助來診斷病人。您可以", - [3] = "建造另一個診斷類房間,例如高級診斷室。", - }, - level8 = { - [1] = "需要您來建造一座高效的醫院。", - [2] = "很多人都無事可做,因此需要適量的裁員以保持高效。", - [3] = "記住治癒病人是很重要的一件事情,但是您更要從中賺錢。", - [4] = "讓噁心嘔吐的病人靠近清潔工人。", - [5] = "需要賺取$300,000就可以過關。", - }, - level13 = { - [1] = "您的高超管理技能被特殊機密部門獲知。", - [2] = "他們將向您提高特別獎金,因為他們有一座被老鼠困擾的醫院需要有效管理。", - [3] = "您必須殺死盡可能多的老鼠,並讓清潔工人打掃乾淨。", - [4] = "接受這個任務?", - }, - level16 = { - [1] = "當對病人完成診斷後,需要建造處理和治療類房間完成對病人的治療工作。可以從", - [2] = "建造藥房開始。在藥房中需要一名護士分配各種藥品。", - }, - level6 = { - [1] = "使用您的所有知識來建造一個運行平穩的醫院,從而可以賺取利潤並處理任何問題。", - [2] = "您需要注意一點,醫院周圍的空氣對細菌繁殖,傳染病流行非常適宜。", - [3] = "如果您沒有保持醫院的清潔,則將面對傳染病的流行。", - [4] = "賺取$150,000,並使醫院價值超過$140,000。", - }, - level12 = { - [1] = "您現在遇到了最大的挑戰。", - [2] = "我們為您的成功感到由衷地高興,衛生署為您準備了一項頂級工作;他們需要有人建造另一個超級醫院,賺錢的同時獲取較高的聲望。", - [3] = "您可以購買任何需要的土地,治療各種疾病贏得各種獎勵。", - [4] = "動心了嗎?", - [5] = "賺取$650,000,治癒750個病人,使聲望達到800就可以勝利過關。", - }, - level3 = { - [1] = "這次您將在一個富裕地區建造醫院。", - [2] = "衛生署希望您能夠在這裡賺取更多的利潤。", - [3] = "開始時您被要求獲取好的聲望,但是一旦醫院步入正軌,就可以集中精力賺取更多的錢。", - [4] = "有可能會發生緊急事件。", - [5] = "也就是說一次會有大量病人就診,且他們的病情都一樣。", - [6] = "在時間限制內如果能夠治癒他們,則不僅可以拿到獎金,聲望也會提高。", - [7] = "一些疾病如貓王症侯群等有可能發生,因此最好建造一間手術中心和附屬病房。", - [8] = "勝利條件是賺取$20,000。", - }, - level10 = { - [1] = "隨著您的經驗不斷增長,衛生署要求您集中精力提高藥品的治療效果。", - [2] = "有人對您頗有微辭,為此您必須使所有的藥物都非常有效。", - [3] = "另外,一定要降低醫療事故的發生次數,減少死亡人數。", - [4] = "作為提示,您需要為建造膠桶留一些空地。", - [5] = "使所有藥物的療效都達到80%%,聲望達到650且在銀行帳戶上有$500,000,這樣就可以勝利過關。", - }, - level11 = { - [1] = "現在您有機會建造一座終極醫院。", - [2] = "該地區享有極高的聲望,因此衛生署希望能夠看到最好的醫院建造在這裡。", - [3] = "我們希望您能夠賺取大量的金錢,獲得很高的聲望,並能夠成功地處理任何事件。", - [4] = "這是一項非常重要的工作。", - [5] = "這需要您的努力工作。", - [6] = "注意一點,該區域常常會看到不明飛行物。因此請讓您的員工做好準備迎接不速之客。", - [7] = "您的醫院價值需要達到$240,000,在銀行帳戶內需要$500,000,且聲望需要達到700。", - }, - level18 = { - }, + level17 = + "最後的警告-隨時關注您的聲望-這是真正吸引病人前來就診的關鍵。 " .. + "如果您沒有醫死太多的病人,且使就診病人保持快樂,則不必太擔心聲望! " .. + "決定權就在您的手中。祝您好運。", + level1 = + "歡迎來到您的第一座醫院!// " .. + "首先要擺放服務台,建造一般診斷室,並雇用一名接待員和一名醫生。 " .. + "隨後就可以等待開張了。 " .. + "建造精神病診斷治療室並雇用一名精神病醫生是一個好主意。 " .. + "藥房和護士也是治療病人所必需的。 " .. + "建造一個充氣機房間就可以治療頭部腫脹患者。 " .. + "您需要治癒10個病人,並使聲望保持在200以上。", + level9 = + "當填滿了衛生署的銀行帳戶並為部長大人購買了一輛轎車後,您現在又要開始新的工作了。 " .. + "在這裡您要面對很多問題。 " .. + "只有擁有足夠經驗充分的員工和房間,您才能夠順利過關。 " .. + "醫院價值需要達到$200,000,且銀行帳戶上要有$400,000。 " .. + "如果無法達到上述要求,則無法勝利完成任務。", + level2 = + "在該區域內還有一些其它的疾病。//" .. + "建造醫院從而可以治療更多的病人,並應該考慮建造研究部門。 " .. + "記住保持內部的清潔,從而使聲望盡可能地高-您將遇到患有舌頭鬆弛症的病人,因此需要建造舌頭診治房間。 " .. + "您也可以建造心電圖房間來幫助診斷疾病。 " .. + "這些房間都需要經過研究才能夠被建造。現在你可以購買其它土地擴展醫院-使用城鎮地圖就可以購買土地。 " .. + "目標是聲望300,銀行現金為10000,且治癒40個病人。", + level7 = + "在這裡您將受到衛生署的密切監察,因此要在賺錢的同時,努力提高自己的聲望。 " .. + "我們無法處理太多的醫療事故-這對於醫院的運營是十分不利的。 " .. + "確認所有員工都很快樂,並確認已經購買了所有需要的儀器裝備。 " .. + "聲望需要達到600,且銀行裡需要有$200,000。", + level5 = + "醫院將非常繁忙,處理各種各樣的病人。 " .. + "醫生都是剛剛畢業的實習醫生,因此需要建造一間培訓室對他們進行培訓,提高能力。 " .. + "您只有3名專家可以幫助培訓這些員工,因此一定要讓專家快樂。 " .. + "另外要注意的是,醫院的位置不是很好。 " .. + "經常會發生地震。 " .. + "地震將對醫院中的機器產生損壞,從而影響醫院的運營。 " .. + "使您聲望達到400以上,現金達到$50,000。另外需要治癒200個病人。", + level4 = + "使所有的病人快樂,保持治療的高效率並儘量降低死亡人數。 " .. + "聲望是十分重要的,因此儘量贏得更高的聲望。 " .. + "不要太多擔心收入情況-當聲望提高了,收入也自然會提高。 " .. + "您需要培訓您的醫生,拓寬他們的能力。 " .. + "這樣他們就可以更好的為病人服務。 " .. + "勝利條件是聲望達到500以上。", + level14 = + "這裡還有一個挑戰-一個充滿驚奇的醫院。 " .. + "如果您能夠成功完成這個任務,則您將成為所有勝利者中的佼佼者。 " .. + "不要認為完成這個任務就像吃蛋糕一樣,這將是您所遇到的最艱苦的工作。 " .. + "祝您好運!", + level15 = + "好的,下面是管理醫院的一些技巧。// " .. + "醫生需要各種幫助來診斷病人。您可以 " .. + "建造另一個診斷類房間,例如高級診斷室。", + level8 = + "需要您來建造一座高效的醫院。 " .. + "很多人都無事可做,因此需要適量的裁員以保持高效。 " .. + "記住治癒病人是很重要的一件事情,但是您更要從中賺錢。 " .. + "讓噁心嘔吐的病人靠近清潔工人。 " .. + "需要賺取$300,000就可以過關。", + level13 = + "您的高超管理技能被特殊機密部門獲知。 " .. + "他們將向您提高特別獎金,因為他們有一座被老鼠困擾的醫院需要有效管理。 " .. + "您必須殺死盡可能多的老鼠,並讓清潔工人打掃乾淨。 " .. + "接受這個任務?", + level16 = + "當對病人完成診斷後,需要建造處理和治療類房間完成對病人的治療工作。可以從 " .. + "建造藥房開始。在藥房中需要一名護士分配各種藥品。", + level6 = + "使用您的所有知識來建造一個運行平穩的醫院,從而可以賺取利潤並處理任何問題。 " .. + "您需要注意一點,醫院周圍的空氣對細菌繁殖,傳染病流行非常適宜。 " .. + "如果您沒有保持醫院的清潔,則將面對傳染病的流行。 " .. + "賺取$150,000,並使醫院價值超過$140,000。", + level12 = + "您現在遇到了最大的挑戰。 " .. + "我們為您的成功感到由衷地高興,衛生署為您準備了一項頂級工作;他們需要有人建造另一個超級醫院,賺錢的同時獲取較高的聲望。 " .. + "您可以購買任何需要的土地,治療各種疾病贏得各種獎勵。 " .. + "動心了嗎? " .. + "賺取$650,000,治癒750個病人,使聲望達到800就可以勝利過關。", + level3 = + "這次您將在一個富裕地區建造醫院。 " .. + "衛生署希望您能夠在這裡賺取更多的利潤。 " .. + "開始時您被要求獲取好的聲望,但是一旦醫院步入正軌,就可以集中精力賺取更多的錢。 " .. + "有可能會發生緊急事件。 " .. + "也就是說一次會有大量病人就診,且他們的病情都一樣。 " .. + "在時間限制內如果能夠治癒他們,則不僅可以拿到獎金,聲望也會提高。 " .. + "一些疾病如貓王症侯群等有可能發生,因此最好建造一間手術中心和附屬病房。 " .. + "勝利條件是賺取$20,000。", + level10 = + "隨著您的經驗不斷增長,衛生署要求您集中精力提高藥品的治療效果。 " .. + "有人對您頗有微辭,為此您必須使所有的藥物都非常有效。 " .. + "另外,一定要降低醫療事故的發生次數,減少死亡人數。 " .. + "作為提示,您需要為建造膠桶留一些空地。 " .. + "使所有藥物的療效都達到80%%,聲望達到650且在銀行帳戶上有$500,000,這樣就可以勝利過關。", + level11 = + "現在您有機會建造一座終極醫院。 " .. + "該地區享有極高的聲望,因此衛生署希望能夠看到最好的醫院建造在這裡。 " .. + "我們希望您能夠賺取大量的金錢,獲得很高的聲望,並能夠成功地處理任何事件。 " .. + "這是一項非常重要的工作。 " .. + "這需要您的努力工作。 " .. + "注意一點,該區域常常會看到不明飛行物。因此請讓您的員工做好準備迎接不速之客。 " .. + "您的醫院價值需要達到$240,000,在銀行帳戶內需要$500,000,且聲望需要達到700。", + level18 = "", } humanoid_name_starts = { [1] = "歐得", diff -Nru corsix-th-0.30/CorsixTH/Lua/map.lua corsix-th-0.62/CorsixTH/Lua/map.lua --- corsix-th-0.30/CorsixTH/Lua/map.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/map.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,10 +20,14 @@ --! Lua extensions to the C++ THMap class class "Map" + +---@type Map +local Map = _G["Map"] + local pathsep = package.config:sub(1, 1) local math_floor, tostring, table_concat = math.floor, tostring, table.concat -local thMap = require"TH".map +local thMap = require("TH").map function Map:Map(app) self.width = false @@ -38,14 +42,51 @@ end local flag_cache = {} + +--! Get the value of the given flag from the tile at x, y in the map. +--!param x (int) Horizontal position of the tile to query in the map. +--!param x (int) Vertical position of the tile to query in the map. +--!param flag (string) Name of the queried flag. +--!return (?) value of the queried flag. function Map:getCellFlag(x, y, flag) - return self.th:getCellFlags(x, y, flag_cache)[flag] + return self.th:getCellFlags(math.floor(x), math.floor(y), flag_cache)[flag] end +--! Get the ID of the room of the tile at x, y in the map. +--!param x (int) Horizontal position of the tile to query in the map. +--!param x (int) Vertical position of the tile to query in the map. +--!return ID of the room at the queried tile. function Map:getRoomId(x, y) - return self.th:getCellFlags(x, y).roomId + return self.th:getCellFlags(math.floor(x), math.floor(y)).roomId +end + +function Map:setPlayerCount(count) + self.th:setPlayerCount(count) +end + +function Map:getPlayerCount(count) + self.th:getPlayerCount(count) +end + +--! Set the camera tile for the given player on the map +--!param x (int) Horizontal position of tile to set camera on +--!param y (int) Vertical position of the tile to set the camera on +--!param player (int) Player number (1-4) +function Map:setCameraTile(x, y, player) + self.th:setCameraTile(x, y, player) +end + +--! Set the heliport tile for the given player on the map +--!param x (int) Horizontal position of tile to set heliport on +--!param y (int) Vertical position of the tile to set the heliport on +--!param player (int) Player number (1-4) +function Map:setHeliportTile(x, y, player) + self.th:setHeliportTile(x, y, player) end +--! Set how to display the room temperature in the hospital map. +--!param method (int) Way of displaying the temperature. See also THMapTemperatureDisplay enum. +--! 1=red gradients, 2=blue/green/red colour shifts, 3=yellow/orange/red colour shifts function Map:setTemperatureDisplayMethod(method) if method ~= 1 and method ~= 2 and method ~= 3 then method = 1 @@ -55,6 +96,7 @@ self.th:setTemperatureDisplay(method) end +--! Copy the temperature display method from the Lua data, if available, else use the default. function Map:registerTemperatureDisplayMethod() if not self.temperature_display_method then self:setTemperatureDisplayMethod(self.app.config.warmth_colors_display_default) @@ -84,9 +126,16 @@ -- 1/64 1/32 -- -1/64 1/32 -- And then adjust origin from (0, 0) to (1, 1) - y = (y / 32) + 1 + y = y / 32 + 1 x = x / 64 - return y + x, y - x + local tile_x, tile_y = y + x, y - x + if self.width ~= nil and self.height ~= nil then + if tile_x < 1 then tile_x = 1 end + if tile_x > self.width then tile_x = self.width end + if tile_y < 1 then tile_y = 1 end + if tile_y > self.height then tile_y = self.height end + end + return tile_x, tile_y end local function bits(n) @@ -107,30 +156,33 @@ end --[[! Loads the specified level. If a string is passed it looks for the file with the same name - in the "Levels" folder of CorsixTH, if it is a number it tries to load that level from - the original game. -!param level The name (or number) of the level to load. If this is a number the game assumes + in the "Levels" and/or "Campaigns" folder of CorsixTH, if it is a number it tries to load + that level from the original game. +!param level (string or int) The name (or number) of the level to load. If this is a number the game assumes the original game levels are considered. -!param level_name The name of the actual map/area/hospital as written in the config file. -!param level_file The path to the map file as supplied by the config file. +!param level_name (string) The name of the actual map/area/hospital as written in the config file. +!param map_file (string) The path to the map file as supplied by the config file. +!param level_intro (string) If loading a custom level this message will be shown as soon as the level +has been loaded. ]] -function Map:load(level, difficulty, level_name, level_file, level_intro) - local objects, i +function Map:load(level, difficulty, level_name, map_file, level_intro, map_editor) + local objects if not difficulty then difficulty = "full" end -- Load CorsixTH base configuration for all levels. - -- We want to load the file a new each time. + -- We want to load the file again each time. local function file (filename) local f = assert(loadfile(filename)) return f() end - local path = debug.getinfo(1, "S").source:sub(2, -8) - local result = file(path .. "base_config.lua") + local path = debug.getinfo(1, "S").source:sub(2, -12) + local result = file(path .. "Lua" .. pathsep .. "base_config.lua") local base_config = result - local errors + local _ if type(level) == "number" then + local errors, data -- Playing the original campaign. -- Add TH's base config if possible, otherwise our own config -- roughly corresponds to "full". @@ -141,10 +193,9 @@ end self.difficulty = difficulty self.level_number = level - local data - data, errors = self:getRawData(level_file) + data, errors = self:getRawData(map_file) if data then - i, objects = self.th:load(data) + _, objects = self.th:load(data) else return nil, errors end @@ -164,20 +215,25 @@ level_no = "0" .. level end -- Override with the specific configuration for this level - errors, result = self:loadMapConfig(difficulty .. level_no .. ".SAM", base_config) - -- Finally load additional CorsixTH config per level (currently only for level 5) + _, result = self:loadMapConfig(difficulty .. level_no .. ".SAM", base_config) + -- Finally load additional CorsixTH config per level local p = debug.getinfo(1, "S").source:sub(2, -12) .. "Levels" .. pathsep .. "original" .. level_no .. ".level" - errors, result = self:loadMapConfig(p, result, true) + _, result = self:loadMapConfig(p, result, true) self.level_config = result end - elseif _MAP_EDITOR then + elseif map_editor then -- We're being fed data by the map editor. self.level_name = "MAP EDITOR" self.level_number = "MAP EDITOR" if level == "" then - i, objects = self.th:loadBlank() + _, objects = self.th:loadBlank() else - i, objects = self.th:load(level) + local data, errors = self:getRawData(level) + if data then + _, objects = self.th:load(data) + else + return nil, errors + end end assert(base_config, "No base config has been loaded!") @@ -187,15 +243,18 @@ self.level_name = level_name self.level_intro = level_intro self.level_number = level - self.level_file = level_file - local data, errors = self:getRawData(level_file) + self.map_file = map_file + local data, errors = self:getRawData(map_file) if data then - i, objects = self.th:load(data) + _, objects = self.th:load(data) else return nil, errors end assert(base_config, "No base config has been loaded!") - errors, result = self:loadMapConfig(level, base_config, true) + errors, result = self:loadMapConfig(self.app:getAbsolutePathToLevelFile(level), base_config, true) + if errors then + print(errors) + end self.level_config = result end @@ -204,19 +263,83 @@ self.parcelTileCounts = {} for plot = 1, self.th:getPlotCount() do self.parcelTileCounts[plot] = self.th:getParcelTileCount(plot) - if plot > 1 and not _MAP_EDITOR then - -- TODO: On multiplayer maps, assign plots 2-N to players 2-N - self.th:setPlotOwner(plot, 0) + if not map_editor then + self:setPlotOwner(plot, plot <= self.th:getPlayerCount() and plot or 0) end end return objects end +--[[! Sets the plot owner of the given plot number to the given new owner. Makes sure + that any room adjacent to the new plot have walls in all directions after the purchase. +!param plot_number (int) Number of the plot to change owner of. Plot 0 is the outside and + should never change owner. +!param new_owner (int) The player number that should own plot_number. 0 means no owner. +]] +function Map:setPlotOwner(plot_number, new_owner) + local split_tiles = self.th:setPlotOwner(plot_number, new_owner) + for _, coordinates in ipairs(split_tiles) do + local x = coordinates[1] + local y = coordinates[2] + + local _, north_wall, west_wall = self.th:getCell(x, y) + local cell_flags = self.th:getCellFlags(x, y) + local north_cell_flags = self.th:getCellFlags(x, y - 1) + local west_cell_flags = self.th:getCellFlags(x - 1, y) + local wall_dirs = { + south = { layer = north_wall, + block_id = 2, + room_cell_flags = cell_flags, + adj_cell_flags = north_cell_flags, + tile_cat = 'inside_tiles', + wall_dir = 'north' + }, + north = { layer = north_wall, + block_id = 2, + room_cell_flags = north_cell_flags, + adj_cell_flags = cell_flags, + tile_cat = 'outside_tiles', + wall_dir = 'north' + }, + east = { layer = west_wall, + block_id = 3, + room_cell_flags = cell_flags, + adj_cell_flags = west_cell_flags, + tile_cat = 'inside_tiles', + wall_dir = 'west' + }, + west = { layer = west_wall, + block_id = 3, + room_cell_flags = west_cell_flags, + adj_cell_flags = cell_flags, + tile_cat = 'outside_tiles', + wall_dir = 'west' + }, + } + for _, dir in pairs(wall_dirs) do + if dir.layer == 0 and dir.room_cell_flags.roomId ~= 0 and + dir.room_cell_flags.parcelId ~= dir.adj_cell_flags.parcelId then + local room = self.app.world.rooms[dir.room_cell_flags.roomId] + local wall_type = self.app.walls[room.room_info.wall_type][dir.tile_cat][dir.wall_dir] + self.th:setCell(x, y, dir.block_id, wall_type) + end + end + end + self.th:updatePathfinding() +end + +--[[! Saves the map to a .map file +!param filename (string) Name of the file to save the map in +]] +function Map:save(filename) + self.th:save(filename) +end + --[[! Loads map configurations from files. Returns nil as first result if no configuration could be loaded and config as second result no matter what. -!param filename -!param config If a base config already exists and only some values should be overridden +!param filename (string) The absolute path to the config file to load +!param config (string) If a base config already exists and only some values should be overridden this is the base config !param custom If true The configuration file is searched for where filename points, otherwise it is assumed that we're looking in the theme_hospital_install path. @@ -266,7 +389,7 @@ end return nil, config else - return "Error: Could not find the configuration file", config + return "Error: Could not find the configuration file, only 'Base Config' will be loaded for this level.", config end end @@ -305,13 +428,13 @@ self.updateDebugOverlay = nil end -function Map:getRawData(level_file) +function Map:getRawData(map_file) if not self.thData then local data, errors - if not level_file then + if not map_file then data, errors = self.app:readDataFile("Levels", "Level.L".. self.level_number) else - data, errors = self.app:readDataFile("Levels", level_file) + data, errors = self.app:readDataFile("Levels", map_file) end if data then self.thData = data @@ -340,6 +463,50 @@ end end +function Map:updateDebugOverlayParcels() + for x = 1, self.width do + for y = 1, self.height do + local xy = (y - 1) * self.width + x - 1 + self.debug_text[xy] = self.th:getCellFlags(x, y).parcelId + if self.debug_text[xy] == 0 then + self.debug_text[xy] = '' + end + end + end +end + +function Map:updateDebugOverlayCamera() + for x = 1, self.width do + for y = 1, self.height do + local xy = (y - 1) * self.width + x - 1 + self.debug_text[xy] = '' + end + end + for p = 1, self.th:getPlayerCount() do + local x, y = self.th:getCameraTile(p) + if x and y then + local xy = (y - 1) * self.width + x - 1 + self.debug_text[xy] = 'C'..p + end + end +end + +function Map:updateDebugOverlayHeliport() + for x = 1, self.width do + for y = 1, self.height do + local xy = (y - 1) * self.width + x - 1 + self.debug_text[xy] = '' + end + end + for p = 1, self.th:getPlayerCount() do + local x, y = self.th:getHeliportTile(p) + if x and y then + local xy = (y - 1) * self.width + x - 1 + self.debug_text[xy] = 'H'..p + end + end +end + function Map:loadDebugText(base_offset, xy_offset, first, last, bits_) self.debug_text = false self.debug_flags = false @@ -366,6 +533,18 @@ self.debug_text = {} self.updateDebugOverlay = self.updateDebugOverlayHeat self:updateDebugOverlay() + elseif base_offset == "parcel" then + self.debug_text = {} + self.updateDebugOverlay = self.updateDebugOverlayParcels + self:updateDebugOverlay() + elseif base_offset == "camera" then + self.debug_text = {} + self.updateDebugOverlay = self.updateDebugOverlayCamera + self:updateDebugOverlay() + elseif base_offset == "heliport" then + self.debug_text = {} + self.updateDebugOverlay = self.updateDebugOverlayHeliport + self:updateDebugOverlay() else local thData = self:getRawData() for x = 1, self.width do @@ -393,6 +572,8 @@ end end +--! Set the sprites to be used by the map. +--!param blocks (object) Sprite sheet for the map. function Map:setBlocks(blocks) self.blocks = blocks self.th:setSheet(blocks) @@ -424,10 +605,14 @@ self.debug_text[(y - 1) * self.width + x - 1] = text end ---[[! - @arguments canvas, screen_x, screen_y, screen_width, screen_height, destination_x, destination_y - - Draws the rectangle of the map given by (sx, sy, sw, sh) at position (dx, dy) on the canvas +--! Draws the rectangle of the map given by (sx, sy, sw, sh) at position (dx, dy) on the canvas +--!param canvas +--!param sx Horizontal start position at the screen. +--!param sy Vertical start position at the screen. +--!param sw (int) Width of the screen. +--!param sh (int) Height of the screen. +--!param dx (jnt) Horizontal destination at the canvas. +--!param dy (int) Vertical destination at the canvas. --]] function Map:draw(canvas, sx, sy, sw, sh, dx, dy) -- All the heavy work is done by C code: @@ -460,42 +645,42 @@ if screenX < -32 then elseif screenX < sw + 32 then local xy = y * self.width + x - local x = dx + screenX - 32 - local y = dy + screenY + local xpos = dx + screenX - 32 + local ypos = dy + screenY if self.debug_flags then local flags = self.debug_flags[xy] if flags.passable then - self.cell_outline:draw(canvas, 3, x, y) + self.cell_outline:draw(canvas, 3, xpos, ypos) end if flags.hospital then - self.cell_outline:draw(canvas, 8, x, y) + self.cell_outline:draw(canvas, 8, xpos, ypos) end if flags.buildable then - self.cell_outline:draw(canvas, 9, x, y) + self.cell_outline:draw(canvas, 9, xpos, ypos) end if flags.travelNorth and self.debug_flags[xy - self.width].passable then - self.cell_outline:draw(canvas, 4, x, y) + self.cell_outline:draw(canvas, 4, xpos, ypos) end if flags.travelEast and self.debug_flags[xy + 1].passable then - self.cell_outline:draw(canvas, 5, x, y) + self.cell_outline:draw(canvas, 5, xpos, ypos) end if flags.travelSouth and self.debug_flags[xy + self.width].passable then - self.cell_outline:draw(canvas, 6, x, y) + self.cell_outline:draw(canvas, 6, xpos, ypos) end if flags.travelWest and self.debug_flags[xy - 1].passable then - self.cell_outline:draw(canvas, 7, x, y) + self.cell_outline:draw(canvas, 7, xpos, ypos) end if flags.thob ~= 0 then - self.debug_font:draw(canvas, "T"..flags.thob, x, y, 64, 16) + self.debug_font:draw(canvas, "T"..flags.thob, xpos, ypos, 64, 16) end if flags.roomId ~= 0 then - self.debug_font:draw(canvas, "R"..flags.roomId, x, y + 16, 64, 16) + self.debug_font:draw(canvas, "R"..flags.roomId, xpos, ypos + 16, 64, 16) end else local msg = self.debug_text[xy] if msg and msg ~= "" then - self.cell_outline:draw(canvas, 2, x, y) - self.debug_font:draw(canvas, msg, x, y, 64, 32) + self.cell_outline:draw(canvas, 2, xpos, ypos) + self.debug_font:draw(canvas, msg, xpos, ypos, 64, 32) end end else @@ -518,6 +703,9 @@ end end +--! Get the price of a parcel +--!param parcel (int) Parcel number being queried. +--!return Price of the queried parcel. function Map:getParcelPrice(parcel) local conf = self.level_config conf = conf and conf.gbv @@ -525,6 +713,9 @@ return self:getParcelTileCount(parcel) * (conf or 25) end +--! Get the number of tiles in a parcel. +--!param parcel (int) Parcel number being queried. +--!return Number of tiles in the queried parcel. function Map:getParcelTileCount(parcel) return self.parcelTileCounts[parcel] or 0 end @@ -583,4 +774,8 @@ end end end + if old < 120 then + -- Issue #1105 update pathfinding (rebuild walls) potentially broken by side object placement + self.th:updatePathfinding() + end end diff -Nru corsix-th-0.30/CorsixTH/Lua/movie_player.lua corsix-th-0.62/CorsixTH/Lua/movie_player.lua --- corsix-th-0.30/CorsixTH/Lua/movie_player.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/movie_player.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,14 +20,76 @@ --! Layer which handles the Lua-facing side of loading and playing video. -local TH = require "TH" +local TH = require("TH") local pathsep = package.config:sub(1, 1) class "MoviePlayer" -function MoviePlayer:MoviePlayer(app, audio) +---@type MoviePlayer +local MoviePlayer = _G["MoviePlayer"] + +--! Calculate the position and size for a movie +--! +--! Returns x and y position and width and height for the movie to be displayed +--! based on the native size of the movie and the current screen dimensions +local calculateSize = function(me) + -- calculate target dimensions + local x, y, w, h + local screen_w, screen_h = me.app.config.width, me.app.config.height + local native_w = me.moviePlayer:getNativeWidth() + local native_h = me.moviePlayer:getNativeHeight() + if native_w ~= 0 and native_h ~= 0 then + local ar = native_w / native_h + if math.abs((screen_w / screen_h) - ar) < 0.001 then + x, y = 0, 0 + w, h = screen_w, screen_h + else + if screen_w > screen_h / native_h * native_w then + w = math.floor(screen_h / native_h * native_w) + h = screen_h + x = math.floor((screen_w - w) / 2) + y = 0 + else + w = screen_w + h = math.floor(screen_w / native_w * native_h) + x = 0 + y = math.floor((screen_h - h) / 2) + end + end + else + x, y = 0, 0 + w, h = screen_w, screen_h + end + + return x, y, w, h +end + +local destroyMovie = function(me) + me.moviePlayer:unload() + if me.opengl_mode_index then + me.app.modes[me.opengl_mode_index] = "opengl" + end + if me.channel >= 0 then + me.audio:releaseChannel(me.channel) + me.channel = -1 + end + if me.holding_bg_music then + -- If possible we want to continue playing music where we were + me.audio:pauseBackgroundTrack() + else + me.audio:playRandomBackgroundTrack() + end + me.playing = false + if me.callback_on_destroy_movie then + me.callback_on_destroy_movie() + me.callback_on_destroy_movie = nil + end +end + +function MoviePlayer:MoviePlayer(app, audio, video) self.app = app self.audio = audio + self.video = video self.playing = false self.holding_bg_music = false self.channel = -1 @@ -42,33 +104,32 @@ function MoviePlayer:init() self.moviePlayer = TH.moviePlayer() + self.moviePlayer:setRenderer(self.video) --find movies in Anims folder - local num - local movie - local movies = self.app.fs:listFiles("Anims"); + local movies = self.app.fs:listFiles("Anims") if movies then - for _,movie in pairs(movies) do - --lose level movies - if movie:upper():match(pathsep .. "LOSE%d+%.[^" .. pathsep .."]+$") then + for _, movie in pairs(movies) do + --lose level movies + if movie:upper():match(pathsep .. "LOSE%d+%.[^" .. pathsep .. "]+$") then table.insert(self.lose_movies, movie) - end - --advance level movies - num = tonumber(movie:upper():match(pathsep .. "AREA(%d+)V%.[^" .. pathsep .."]+$"), 10) - if(num ~= nil) then - self.advance_movies[num] = movie - end - --win game movie - if movie:upper():match(pathsep .. "WINGAME%.[^" .. pathsep .. "]+$") then + end + --advance level movies + local num = movie:upper():match(pathsep .. "AREA(%d+)V%.[^" .. pathsep .. "]+$") + if num ~= nil and tonumber(num, 10) ~= nil then + self.advance_movies[tonumber(num, 10)] = movie + end + --win game movie + if movie:upper():match(pathsep .. "WINGAME%.[^" .. pathsep .. "]+$") then self.win_movie = movie - end + end end end --find intro movies = self.app.fs:listFiles("Intro") if movies then - for _,movie in pairs(movies) do + for _, movie in pairs(movies) do if movie:upper():match(pathsep .. "INTRO%.SM4$") then self.intro_movie = movie end @@ -87,8 +148,9 @@ function MoviePlayer:playAdvanceMovie(level) local filename = self.advance_movies[level] - if(not self.moviePlayer:getEnabled() or not self.app.config.movies or filename == nil) then - return + if self.moviePlayer == nil or not self.moviePlayer:getEnabled() or + not self.app.config.movies or filename == nil then + return end if self.audio.background_music then @@ -112,12 +174,10 @@ end function MoviePlayer:playMovie(filename, wait_for_stop, can_skip, callback) - local x, y, w, h = 0 - local screen_w, screen_h = self.app.config.width, self.app.config.height - local ar local success, warning - if(not self.moviePlayer:getEnabled() or not self.app.config.movies or filename == nil) then + if self.moviePlayer == nil or not self.moviePlayer:getEnabled() or + not self.app.config.movies or filename == nil then if callback then callback() end @@ -149,35 +209,9 @@ end end - -- calculate target dimensions - local native_w = self.moviePlayer:getNativeWidth() - local native_h = self.moviePlayer:getNativeHeight() - if(native_w ~= 0 and native_h ~= 0) then - ar = native_w / native_h - if(math.abs((screen_w / screen_h) - ar) < 0.001) then - x, y = 0, 0 - w, h = screen_w, screen_h - else - if(screen_w > screen_h / native_h * native_w) then - w = screen_h / native_h * native_w - h = screen_h - x = (screen_w - w) / 2 - y = 0 - else - w = screen_w - h = screen_w / native_w * native_h - x = 0 - y = (screen_h - h) / 2 - end - end - else - x, y = 0, 0 - w, h = screen_w, screen_h - end - - self.app.video:startFrame() - self.app.video:fillBlack() - self.app.video:endFrame() + self.video:startFrame() + self.video:fillBlack() + self.video:endFrame() self.can_skip = can_skip self.wait_for_stop = wait_for_stop @@ -196,7 +230,7 @@ end --TODO: Add text e.g. for newspaper headlines - warning = self.moviePlayer:play(x, y, w, h, self.channel) + warning = self.moviePlayer:play(self.channel) if warning ~= nil and warning ~= "" then local message = "MoviePlayer:playMovie - Warning: " .. warning if self.app.world then @@ -210,57 +244,48 @@ --NB: Call after any changes to TH.surface function MoviePlayer:allocatePictureBuffer() + if self.moviePlayer == nil then return end + self.moviePlayer:allocatePictureBuffer() end --NB: Call before any changes to TH.surface function MoviePlayer:deallocatePictureBuffer() + if self.moviePlayer == nil then return end + self.moviePlayer:deallocatePictureBuffer() end function MoviePlayer:onMovieOver() - self.moviePlayer:unload() + if self.moviePlayer == nil then return end + self.wait_for_over = false if not self.wait_for_stop then - self:_destroyMovie() + destroyMovie(self) end end function MoviePlayer:stop() + if self.moviePlayer == nil then return end + if self.can_skip then self.moviePlayer:stop() end self.wait_for_stop = false if not self.wait_for_over then - self:_destroyMovie() - end -end - -function MoviePlayer:_destroyMovie() - if self.opengl_mode_index then - self.app.modes[self.opengl_mode_index] = "opengl" - end - if(self.moviePlayer:requiresVideoReset()) then - self.app.ui:resetVideo() - end - if self.channel >= 0 then - self.audio:releaseChannel(self.channel) - self.channel = -1 - end - if self.holding_bg_music then - -- If possible we want to continue playing music where we were - self.audio:pauseBackgroundTrack() - else - self.audio:playRandomBackgroundTrack() - end - self.playing = false - if self.callback_on_destroy_movie then - self.callback_on_destroy_movie() - self.callback_on_destroy_movie = nil + destroyMovie(self) end end function MoviePlayer:refresh() - self.moviePlayer:refresh() + if self.moviePlayer == nil then return end + + local x, y, w, h = calculateSize(self) + self.moviePlayer:refresh(x, y, w, h) end +function MoviePlayer:updateRenderer() + if self.moviePlayer == nil then return end + + self.moviePlayer:setRenderer(self.video) +end diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/analyser.lua corsix-th-0.62/CorsixTH/Lua/objects/analyser.lua --- corsix-th-0.30/CorsixTH/Lua/objects/analyser.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/analyser.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -58,6 +58,9 @@ class "AtomAnalyser" (Object) +---@type AtomAnalyser +local AtomAnalyser = _G["AtomAnalyser"] + function AtomAnalyser:AtomAnalyser(...) self:Object(...) end diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/bench.lua corsix-th-0.62/CorsixTH/Lua/objects/bench.lua --- corsix-th-0.30/CorsixTH/Lua/objects/bench.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/bench.lua 2018-07-21 11:13:17.000000000 +0000 @@ -126,25 +126,28 @@ object.orientations = { north = { render_attach_position = { {0, 0}, {-1, 0}, {0, -1} }, - footprint = { {0, 0, complete_cell = true}, {0, -1, only_passable = true, invisible = true} }, + footprint = { {0, 0, complete_cell = true}, {0, -1, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, east = { - footprint = { {0, 0, complete_cell = true}, {1, 0, only_passable = true, invisible = true} }, + footprint = { {0, 0, complete_cell = true}, {1, 0, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, south = { - footprint = { {0, 0, complete_cell = true}, {0, 1, only_passable = true, invisible = true} }, + footprint = { {0, 0, complete_cell = true}, {0, 1, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, west = { - footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true, invisible = true} }, + footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, } class "Bench" (Object) +---@type Bench +local Bench = _G["Bench"] + function Bench:Bench(...) self:Object(...) end @@ -154,7 +157,7 @@ function Bench:removeUser(user) if user then local has_idle = false - for i, action in pairs(user.action_queue) do + for _, action in pairs(user.action_queue) do if action.name == "idle" then has_idle = true end @@ -191,4 +194,12 @@ Object.onDestroy(self) end +--! This function is automatically called after loading a game and serves for compatibility. +function Bench:afterLoad(old, new) + if old < 119 then + self.footprint = object.orientations[self.direction].footprint + end + Object.afterLoad(self, old, new) +end + return object diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/bin.lua corsix-th-0.62/CorsixTH/Lua/objects/bin.lua --- corsix-th-0.30/CorsixTH/Lua/objects/bin.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/bin.lua 2018-07-21 11:13:17.000000000 +0000 @@ -24,6 +24,7 @@ object.name = _S.object.bin object.tooltip = _S.tooltip.objects.bin object.ticks = false +object.corridor_object = 6 object.class = "SideObject" object.build_preview_animation = 5096 object.idle_animations = { @@ -41,6 +42,9 @@ class "SideObject" (Object) +---@type SideObject +local SideObject = _G["SideObject"] + function SideObject:SideObject(...) self:Object(...) end @@ -62,7 +66,7 @@ return 8 end else --south - return 9; + return 9 end end end diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/chair.lua corsix-th-0.62/CorsixTH/Lua/objects/chair.lua --- corsix-th-0.30/CorsixTH/Lua/objects/chair.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/chair.lua 2018-07-21 11:13:17.000000000 +0000 @@ -32,12 +32,12 @@ object.walk_in_to_use = true local function make_list(not_talking, nodding, talking) local list = {} - for i = 1, 16 do list[#list+1] = not_talking end + for _ = 1, 16 do list[#list+1] = not_talking end if nodding then - for i = 1, 3 do list[#list+1] = nodding end + for _ = 1, 3 do list[#list+1] = nodding end end if talking then - for i = 1, 1 do list[#list+1] = talking end + for _ = 1, 1 do list[#list+1] = talking end end return list end @@ -136,21 +136,38 @@ } object.orientations = { north = { - footprint = { {0, 0, complete_cell = true}, {0, -1, only_passable = true} }, + footprint = { {0, 0, complete_cell = true}, {0, -1, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, east = { - footprint = { {0, 0, complete_cell = true}, {1, 0, only_passable = true} }, + footprint = { {0, 0, complete_cell = true}, {1, 0, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, south = { - footprint = { {0, 0, complete_cell = true}, {0, 1, only_passable = true} }, + footprint = { {0, 0, complete_cell = true}, {0, 1, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, west = { - footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true} }, + footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, } +class "Chair" (Object) + +---@type Chair +local Chair = _G["Chair"] + +function Chair:Chair(...) + self:Object(...) +end + +--! This function is automatically called after loading a game and serves for compatibility. +function Chair:afterLoad(old, new) + if old < 119 then + self.footprint = object.orientations[self.direction].footprint + end + Object.afterLoad(self, old, new) +end + return object diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/computer.lua corsix-th-0.62/CorsixTH/Lua/objects/computer.lua --- corsix-th-0.30/CorsixTH/Lua/objects/computer.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/computer.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/console.lua corsix-th-0.62/CorsixTH/Lua/objects/console.lua --- corsix-th-0.30/CorsixTH/Lua/objects/console.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/console.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/desk.lua corsix-th-0.62/CorsixTH/Lua/objects/desk.lua --- corsix-th-0.30/CorsixTH/Lua/objects/desk.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/desk.lua 2018-07-21 11:13:17.000000000 +0000 @@ -37,7 +37,7 @@ Nurse = 3240, }, in_use = { - -- Note: 72 (normal usage) should happen alot more often than 718 (head + -- Note: 72 (normal usage) should happen a lot more often than 718 (head -- scratching), hence it appears in the list many times. Doctor = {72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 718}, Nurse = 3256, diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/door.lua corsix-th-0.62/CorsixTH/Lua/objects/door.lua --- corsix-th-0.30/CorsixTH/Lua/objects/door.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/door.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,10 +30,13 @@ west = 106, } -dofile "queue" +corsixth.require("queue") class "Door" (Object) +---@type Door +local Door = _G["Door"] + function Door:Door(...) self:Object(...) self.queue = Queue() @@ -61,7 +64,7 @@ self:setDynamicInfo('text', { self.room.room_info.name, _S.dynamic_info.object.queue_size:format(self.queue:reportedSize()), - _S.dynamic_info.object.queue_expected:format(self.queue.expected_count) + _S.dynamic_info.object.queue_expected:format(self.queue:expectedSize()) }) end end @@ -142,7 +145,7 @@ function Door:closeDoor() if self.queue then - self.queue:rerouteAllPatients({name = "seek_room", room_type = self:getRoom().room_info.id}) + self.queue:rerouteAllPatients(SeekRoomAction(self:getRoom().room_info.id)) self.queue = nil end self:clearDynamicInfo(nil) diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/doors/entrance_right_door.lua corsix-th-0.62/CorsixTH/Lua/objects/doors/entrance_right_door.lua --- corsix-th-0.30/CorsixTH/Lua/objects/doors/entrance_right_door.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/doors/entrance_right_door.lua 2018-07-21 11:13:17.000000000 +0000 @@ -33,6 +33,9 @@ class "EntranceDoor" (Object) +---@type EntranceDoor +local EntranceDoor = _G["EntranceDoor"] + function EntranceDoor:EntranceDoor(world, object_type, x, y, direction, etc) self.is_master = object_type == object self:Object(world, object_type, x, y, direction, etc) @@ -71,7 +74,7 @@ self.occupant_count = self.occupant_count + count_delta local is_open = self.occupant_count > 0 if is_open ~= self.is_open then - self:playSound "eledoor2.wav" + self:playSound("eledoor2.wav") self.is_open = is_open self.ticks = true end diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/doors/swing_door_right.lua corsix-th-0.62/CorsixTH/Lua/objects/doors/swing_door_right.lua --- corsix-th-0.30/CorsixTH/Lua/objects/doors/swing_door_right.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/doors/swing_door_right.lua 2018-07-21 11:13:17.000000000 +0000 @@ -32,6 +32,9 @@ class "SwingDoor" (Door) +---@type SwingDoor +local SwingDoor = _G["SwingDoor"] + function SwingDoor:SwingDoor(world, object_type, x, y, direction, etc) self.is_master = object_type == object self:Door(world, object_type, x, y, direction, etc) diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/gates_to_hell.lua corsix-th-0.62/CorsixTH/Lua/objects/gates_to_hell.lua --- corsix-th-0.30/CorsixTH/Lua/objects/gates_to_hell.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/gates_to_hell.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,67 @@ +--[[ Copyright (c) 2013 Luís "Driver" Duarte + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +local object = {} + +object.id = "gates_to_hell" +object.name = "Gates to Hell" +object.thob = 48 +object.ticks = true +object.walk_in_to_use = true + +object.idle_animations = { + south = 1602, + east = 1602 +} + +object.usage_animations = { + south = { + in_use = { + ["Standard Male Patient"] = 4560, + }, + }, + east = { + in_use = { + ["Standard Male Patient"] = 4560, + }, + } +} + +local anim_mgr = TheApp.animation_manager +anim_mgr:setMarker(object.usage_animations.south.in_use, 0, {0,0}) +anim_mgr:setMarker(object.usage_animations.east.in_use, 0, {0,0}) + +-- Orientation directions are relative to the patient's death location: +object.orientations = { + south = { + use_position = {0, 0}, + footprint = { {1, 0, only_passable = true}, + {0, 0, complete_cell = true}, + {-1, 0, only_passable = true} }, + use_animate_from_use_position = false + }, + east = { + use_position = {0, 0}, + footprint = { {0, -1, only_passable = true}, {0, 0, complete_cell = true}, {0, 1, only_passable = true} }, + use_animate_from_use_position = false + } +} + +return object diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/helicopter.lua corsix-th-0.62/CorsixTH/Lua/objects/helicopter.lua --- corsix-th-0.30/CorsixTH/Lua/objects/helicopter.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/helicopter.lua 2018-07-21 11:13:17.000000000 +0000 @@ -37,8 +37,13 @@ --! An `Object` which drops of emergency patients. class "Helicopter" (Object) +---@type Helicopter +local Helicopter = _G["Helicopter"] + function Helicopter:Helicopter(world, object_type, hospital, direction, etc) local x, y = hospital:getHeliportPosition() + -- Helicoptor needs to land below tile to be positioned correctly + y = y + 1 self:Object(world, object_type, x, y, direction, etc) self.th:makeInvisible() self:setPosition(0, -600) @@ -77,22 +82,17 @@ local patient = self.world:newEntity("Patient", 2) patient:setDisease(hospital.emergency.disease) patient.diagnosis_progress = 1 - patient:setDiagnosed(true) + patient:setDiagnosed() patient:setMood("emergency", "activate") patient.is_emergency = self.spawned_patients hospital.emergency_patients[#hospital.emergency_patients + 1] = patient local x, y = hospital:getHeliportSpawnPosition() - patient:setNextAction{ - name = "spawn", - mode = "spawn", - point = {x = x, y = y}, - offset = {y = 1}, - } + patient:setNextAction(SpawnAction("spawn", {x = x, y = y}):setOffset({y = 1})) patient:setHospital(hospital) - -- TODO: If new combinated diseases are added this will not work correctly anymore. + -- TODO: If new combined diseases are added this will not work correctly anymore. patient.cure_rooms_visited = #patient.disease.treatment_rooms - 1 local no_of_rooms = #patient.disease.treatment_rooms - patient:queueAction{name = "seek_room", room_type = patient.disease.treatment_rooms[no_of_rooms]} + patient:queueAction(SeekRoomAction(patient.disease.treatment_rooms[no_of_rooms])) end return object diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/litter.lua corsix-th-0.62/CorsixTH/Lua/objects/litter.lua --- corsix-th-0.30/CorsixTH/Lua/objects/litter.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/litter.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,7 +18,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" +local TH = require("TH") local object = {} object.id = "litter" @@ -50,20 +50,22 @@ class "Litter" (Entity) +---@type Litter +local Litter = _G["Litter"] + function Litter:Litter(world, object_type, x, y, direction, etc) local th = TH.animation() self:Entity(th) + self.ticks = object_type.ticks self.object_type = object_type self.world = world self:setTile(x, y) end function Litter:setTile(x, y) - local map = self.world.map.th Entity.setTile(self, x, y) if x then self.world:addObjectToTile(self, x, y) - map:setCellFlags(x, y, {buildable = false}) end end -- Litter is an Entity and not an Object so it does not inherit this method @@ -81,21 +83,33 @@ if anim then self:setAnimation(anim, mirrorFlag) else - error "Unknown litter type" + error("Unknown litter type") end if self:isCleanable() then - local hospital = self.world:getLocalPlayerHospital() + local hospital = self.world:getHospital(self.tile_x, self.tile_y) hospital:addHandymanTask(self, "cleaning", 1, self.tile_x, self.tile_y) end end end -function Litter:getDrawingLayer() - return 0 +--! Remove the litter from the world. +function Litter:remove() + assert(self:isCleanable()) + + if self.tile_x then + self.world:removeObjectFromTile(self, self.tile_x, self.tile_y) + + local hospital = self.world:getHospital(self.tile_x, self.tile_y) + local taskIndex = hospital:getIndexOfTask(self.tile_x, self.tile_y, "cleaning", self) + hospital:removeHandymanTask(taskIndex, "cleaning") + else + print("Warning: Removing litter that has already been removed.") + end + self.world:destroyEntity(self) end -function Litter:randomiseLitter() - self:setAnimation(litter_types[math.random(1, 4)], math.random(0, 1)) +function Litter:getDrawingLayer() + return 0 end function Litter:vomitInducing() @@ -134,11 +148,15 @@ end if old < 54 then if not self:isCleanable() then - local hospital = self.world:getLocalPlayerHospital() - local taskIndex = hospital:getIndexOfTask(self.tile_x, self.tile_y, "cleaning") + local hospital = self.world:getHospital(self.tile_x, self.tile_y) + local taskIndex = hospital:getIndexOfTask(self.tile_x, self.tile_y, "cleaning", self) hospital:removeHandymanTask(taskIndex, "cleaning") end end + + if old < 121 then + self.ticks = object.ticks + end end return object diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/machines/blood_machine.lua corsix-th-0.62/CorsixTH/Lua/objects/machines/blood_machine.lua --- corsix-th-0.30/CorsixTH/Lua/objects/machines/blood_machine.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/machines/blood_machine.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/machines/cardio.lua corsix-th-0.62/CorsixTH/Lua/objects/machines/cardio.lua --- corsix-th-0.30/CorsixTH/Lua/objects/machines/cardio.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/machines/cardio.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/machines/inflator.lua corsix-th-0.62/CorsixTH/Lua/objects/machines/inflator.lua --- corsix-th-0.30/CorsixTH/Lua/objects/machines/inflator.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/machines/inflator.lua 2018-07-21 11:13:17.000000000 +0000 @@ -77,7 +77,7 @@ local anim_mgr = TheApp.animation_manager local kf1, kf2 = {0, 1}, {0, 0} anim_mgr:setMarker(object.multi_usage_animations["Standard Male Patient - Doctor"].north.begin_use, 0, kf1, 5, kf2) -local kf1, kf2 = {0, 0}, {1, 0} +kf1, kf2 = {0, 0}, {1, 0} anim_mgr:setMarker(object.multi_usage_animations["Standard Male Patient - Doctor"].north.finish_use, 1, kf1, 11, kf2) anim_mgr:setMarker(object.idle_animations.north, {-0.9, -1.0}) diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/machines/operating_table.lua corsix-th-0.62/CorsixTH/Lua/objects/machines/operating_table.lua --- corsix-th-0.30/CorsixTH/Lua/objects/machines/operating_table.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/machines/operating_table.lua 2018-07-21 11:13:17.000000000 +0000 @@ -115,6 +115,10 @@ } class "OperatingTable" (Machine) + +---@type OperatingTable +local OperatingTable = _G["OperatingTable"] + OperatingTable:slaveMixinClass() function OperatingTable:machineUsed(...) diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/machines/scanner.lua corsix-th-0.62/CorsixTH/Lua/objects/machines/scanner.lua --- corsix-th-0.30/CorsixTH/Lua/objects/machines/scanner.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/machines/scanner.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/machines/ultrascanner.lua corsix-th-0.62/CorsixTH/Lua/objects/machines/ultrascanner.lua --- corsix-th-0.30/CorsixTH/Lua/objects/machines/ultrascanner.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/machines/ultrascanner.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/machines/x_ray.lua corsix-th-0.62/CorsixTH/Lua/objects/machines/x_ray.lua --- corsix-th-0.30/CorsixTH/Lua/objects/machines/x_ray.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/machines/x_ray.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/op_sink1.lua corsix-th-0.62/CorsixTH/Lua/objects/op_sink1.lua --- corsix-th-0.30/CorsixTH/Lua/objects/op_sink1.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/op_sink1.lua 2018-07-21 11:13:17.000000000 +0000 @@ -64,6 +64,10 @@ } class "OperatingSink" (Object) + +---@type OperatingSink +local OperatingSink = _G["OperatingSink"] + OperatingSink:slaveMixinClass() return object diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/plant.lua corsix-th-0.62/CorsixTH/Lua/objects/plant.lua --- corsix-th-0.30/CorsixTH/Lua/objects/plant.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/plant.lua 2018-07-21 11:13:17.000000000 +0000 @@ -25,7 +25,7 @@ object.class = "Plant" object.tooltip = _S.tooltip.objects.plant object.ticks = false -object.corridor_object = 6 +object.corridor_object = 7 object.build_preview_animation = 934 object.idle_animations = { @@ -70,11 +70,13 @@ -- For litter: put broom back 356 -- take broom out: 1874 -- swoop: 1878 --- For plant: droop down: 1950 --- back up again: 1952 +-- Frames for plant states are +-- * healthy: 1950 +-- * drooping1: 1951 +-- * drooping2: 1952 +-- * dying: 1953 +-- * dead: 1954 --- The states specify which frame to show -local states = {"healthy", "drooping1", "drooping2", "dying", "dead"} local days_between_states = 75 @@ -84,6 +86,9 @@ --! An `Object` which needs watering now and then. class "Plant" (Object) +---@type Plant +local Plant = _G["Plant"] + function Plant:Plant(world, object_type, x, y, direction, etc) -- It doesn't matter which direction the plant is facing. It will be rotated so that an approaching -- handyman uses the correct usage animation when appropriate. @@ -98,16 +103,14 @@ --! Goes one step forward (or backward) in the states of the plant. --!param restoring (boolean) If true the plant improves its health instead of drooping. function Plant:setNextState(restoring) - local change = 0 if restoring then if self.current_state > 0 then - change = -1 + self.current_state = self.current_state - 1 end elseif self.current_state < 5 then - change = 1 + self.current_state = self.current_state + 1 end - self.current_state = self.current_state + change self.th:setFrame(self.base_frame + self.current_state) end @@ -163,63 +166,26 @@ end end -function Plant:getWateringTile() - local map = self.world.map.th - local lx, ly = self.tile_x, self.tile_y - - if not lx or self.picked_up then - -- The plant might be picked up - return nil, nil - end - - if self:getRoom() then - lx, ly = self:getRoom():getEntranceXY() - else - ly = ly + 1 - if not map:getCellFlags(lx, ly).passable then - ly = ly - 2 - if not map:getCellFlags(lx, ly).passable then - ly = ly + 1 - lx = lx + 1 - if not map:getCellFlags(lx, ly).passable then - lx = lx - 2 - if not map:getCellFlags(lx, ly).passable then - lx, ly = nil, nil - end - end - end - end - end - return lx, ly -end - ---! When the plant needs water it preiodically calls for a nearby handyman. +--! When the plant needs water it periodically calls for a nearby handyman. function Plant:callForWatering() - - if self.unreachable then - local ux, uy = self:getBestUsageTileXY(handyman.tile_x, handyman.tile_y) - if ux and uy then - self.unreachable = nil - end - end -- If self.ticks is true it means that a handyman is currently watering the plant. -- If there are no tiles to water from, just die. - if not self.ticks and not self.unreachable then - local index = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "watering") - if index == -1 then - local call = self.world.dispatcher:callForWatering(self) - if self.current_state > 1 and not self.plant_announced then - self.world.ui.adviser:say(_A.warnings.plants_thirsty) - self.plant_announced = true + if not self.ticks then + if not self.unreachable then + local index = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "watering") + if index == -1 then + local call = self.world.dispatcher:callForWatering(self) + self.hospital:addHandymanTask(self, "watering", self.current_state + 1, self.tile_x, self.tile_y, call) + else + self.hospital:modifyHandymanTaskPriority(index, self.current_state + 1, "watering") + end end - self.hospital:addHandymanTask(self, "watering", self.current_state + 1, self.tile_x, self.tile_y, call) - else + + -- If very thirsty, make user aware of it. if self.current_state > 1 and not self.plant_announced then self.world.ui.adviser:say(_A.warnings.plants_thirsty) self.plant_announced = true end - self.hospital:modifyHandymanTaskPriority(index, self.current_state + 1, "watering") - end end end @@ -236,74 +202,63 @@ -- The plant cannot be reached. self.unreachable = true self.unreachable_counter = days_unreachable - local index = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "watering") - if index ~= -1 then - self.hospital:removeHandymanTask(index, "watering") - end + local index = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "watering") + if index ~= -1 then + self.hospital:removeHandymanTask(index, "watering") + end -- Release Handyman handyman:setCallCompleted() if handyman_room then handyman:setNextAction(handyman_room:createLeaveAction()) - handyman:queueAction{name = "meander"} + handyman:queueAction(MeanderAction()) else - handyman:setNextAction{name = "meander"} + handyman:setNextAction(MeanderAction()) end return end self.reserved_for = handyman - local action = {name = "walk", x = ux, y = uy, is_entering = this_room and true or false} - local water_action = { - name = "use_object", - object = self, - watering_plant = true, - } + local walk_action = WalkAction(ux, uy):setIsEntering(this_room and true or false) if handyman_room and handyman_room ~= this_room then handyman:setNextAction(handyman_room:createLeaveAction()) - handyman:queueAction(action) + handyman:queueAction(walk_action) else - handyman:setNextAction(action) + handyman:setNextAction(walk_action) end - handyman:queueAction(water_action) + handyman:queueAction(UseObjectAction(self):enableWateringPlant()) CallsDispatcher.queueCallCheckpointAction(handyman) - handyman:queueAction{name = "answer_call"} + handyman:queueAction(AnswerCallAction()) end --! When a handyman should go to the plant he should approach it from the closest reachable tile. --!param from_x (integer) The x coordinate of tile to calculate from. --!param from_y (integer) The y coordinate of tile to calculate from. function Plant:getBestUsageTileXY(from_x, from_y) - local lx, ly = self.tile_x, self.tile_y + 1 - local rx, ry - local shortest_path = 1000 - local world = self.world - local direction = "north" - local res_dir = direction - local function shortest(distance) - if distance and distance < shortest_path then - -- Only take this route if there is no wall between the plant and the tile. - local room_here = self:getRoom() - local room_there = self.world:getRoom(lx, ly) - if room_here == room_there or (not room_here and not room_there) then - shortest_path = distance - rx = lx - ry = ly - res_dir = direction + local access_points = {{dx = 0, dy = 1, direction = "north"}, + {dx = 0, dy = -1, direction = "south"}, + {dx = -1, dy = 0, direction = "east"}, + {dx = 1, dy = 0, direction = "west"}} + local shortest + local best_point = nil + local room_here = self:getRoom() + for _, point in ipairs(access_points) do + local dest_x, dest_y = self.tile_x + point.dx, self.tile_y + point.dy + local room_there = self.world:getRoom(dest_x, dest_y) + if room_here == room_there then + local distance = self.world:getPathDistance(from_x, from_y, self.tile_x + point.dx, self.tile_y + point.dy) + if distance and (not best_point or shortest > distance) then + best_point = point + shortest = distance end end end - shortest(world:getPathDistance(from_x, from_y, lx, ly)) - ly = ly - 2 - direction = "south" - shortest(world:getPathDistance(from_x, from_y, lx, ly)) - lx = lx - 1 - ly = ly + 1 - direction = "east" - shortest(world:getPathDistance(from_x, from_y, lx, ly)) - lx = lx + 2 - direction = "west" - shortest(world:getPathDistance(from_x, from_y, lx, ly)) - self.direction = res_dir - return rx, ry + + if best_point then + self.direction = best_point.direction + return self.tile_x + best_point.dx, self.tile_y + best_point.dy + else + self.direction = "north" + return + end end --! Counts down to eventually let the plant droop. diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/radiation_shield.lua corsix-th-0.62/CorsixTH/Lua/objects/radiation_shield.lua --- corsix-th-0.30/CorsixTH/Lua/objects/radiation_shield.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/radiation_shield.lua 2018-07-21 11:13:17.000000000 +0000 @@ -71,6 +71,10 @@ } class "RadiationShield" (Object) + +---@type RadiationShield +local RadiationShield = _G["RadiationShield"] + RadiationShield:slaveMixinClass() return object diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/rathole.lua corsix-th-0.62/CorsixTH/Lua/objects/rathole.lua --- corsix-th-0.30/CorsixTH/Lua/objects/rathole.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/rathole.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,62 @@ +--[[ Copyright (c) 2016 Albert "Alberth" Hofkamp + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +local object = {} +object.id = "rathole" +object.thob = 64 +object.name = _S.object.rathole +object.class = "Rathole" +object.tooltip = _S.tooltip.objects.rathole +object.ticks = false +object.idle_animations = { + north = 1904, +} +object.orientations = { + -- Empty footprint, so you can build any other object on top of it. + north = { footprint = {} }, + south = { footprint = {} }, + west = { footprint = {} }, + east = { footprint = {} }, +} + +-- For ratholes: +-- 1904: hole in north wall +-- 1908: rat moving north +-- 1910: rat moving north-east +-- 1912: rat moving east +-- 1914: rat moving south-east +-- 1916: rat moving south +-- 1918: rat moving south-west +-- 1920: rat moving west +-- 1922: rat moving north-west +-- 1924: rat entering hole north wall +-- 1926: rat entering hole west wall +-- 1928: rat leaving hole north wall + +class "Rathole" (Object) + +---@type Rathole +local Rathole = _G["Rathole"] + +function Rathole:Rathole(world, oject_type, x, y, direction, etc) + self:Object(world, oject_type, x, y, direction, etc) +end + +return object diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/reception_desk.lua corsix-th-0.62/CorsixTH/Lua/objects/reception_desk.lua --- corsix-th-0.30/CorsixTH/Lua/objects/reception_desk.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/reception_desk.lua 2018-07-21 11:13:17.000000000 +0000 @@ -66,10 +66,13 @@ }, } -dofile "queue" +corsixth.require("queue") class "ReceptionDesk" (Object) +---@type ReceptionDesk +local ReceptionDesk = _G["ReceptionDesk"] + function ReceptionDesk:ReceptionDesk(...) self:Object(...) self.queue = Queue() @@ -92,25 +95,44 @@ local queue_front = self.queue:front() local reset_timer = true if self.receptionist and queue_front then - if queue_front.action_queue[1].name == "idle" then + if queue_front:getCurrentAction().name == "idle" then self.queue_advance_timer = self.queue_advance_timer + 1 reset_timer = false - if self.queue_advance_timer >= 4 + self.world.hours_per_day * (1.0 - self.receptionist.profile.skill) then + if self.queue_advance_timer >= 4 + Date.hoursPerDay() * (1.0 - self.receptionist.profile.skill) then reset_timer = true if queue_front.next_room_to_visit then - queue_front:queueAction{name = "seek_room", room_type = queue_front.next_room_to_visit.room_info.id} + queue_front:queueAction(SeekRoomAction(queue_front.next_room_to_visit.room_info.id)) else - -- VIP has his own list, don't add the gp office twice - if queue_front.humanoid_class ~= "VIP" then - queue_front:queueAction{name = "seek_room", room_type = "gp"} + if class.is(queue_front, Inspector) then + local inspector = queue_front + if not inspector.going_home then + local epidemic = self.world:getLocalPlayerHospital().epidemic + if epidemic then + -- The result of the epidemic may already by determined + -- i.e if an infected patient has left the hospital + if not epidemic.result_determined then + epidemic:finishCoverUp() + end + epidemic:applyOutcome() + inspector:goHome() + end + end + -- VIP has his own list, don't add the gp office twice + elseif queue_front.humanoid_class ~= "VIP" then + if queue_front:agreesToPay("diag_gp") then + queue_front:queueAction(SeekRoomAction("gp")) + else + queue_front:goHome("over_priced", "diag_gp") + end else -- the VIP will realise that he is idle, and start going round rooms - queue_front:queueAction{name = "idle"} + queue_front:queueAction(IdleAction()) queue_front.waiting = 1 end end self.queue:pop() self.queue.visitor_count = self.queue.visitor_count + 1 + queue_front.has_passed_reception = true end end end @@ -120,6 +142,8 @@ return Object.tick(self) end +--! Reception desk looks for a receptionist. +--!return (boolean) Desk has a receptionist attached to it (may still be on her way to the desk). function ReceptionDesk:checkForNearbyStaff() if self.receptionist or self.reserved_for then -- Already got staff, or a staff member is on the way @@ -183,8 +207,7 @@ end end) end - self.queue:rerouteAllPatients({name = "seek_reception"}) - self.world:getLocalPlayerHospital().reception_desks[self] = nil + self.queue:rerouteAllPatients(SeekReceptionAction()) self.being_destroyed = nil return Object.onDestroy(self) @@ -199,9 +222,10 @@ if not self.receptionist and not self.reserved_for then self.reserved_for = receptionist receptionist.associated_desk = self + local use_x, use_y = self:getSecondaryUsageTile() - receptionist:setNextAction{name = "walk", x = use_x, y = use_y, must_happen = true} - receptionist:queueAction{name = "staff_reception", object = self, must_happen = true} + receptionist:setNextAction(WalkAction(use_x, use_y):setMustHappen(true)) + receptionist:queueAction(StaffReceptionAction(self)) return true end end diff -Nru corsix-th-0.30/CorsixTH/Lua/objects/surgeon_screen.lua corsix-th-0.62/CorsixTH/Lua/objects/surgeon_screen.lua --- corsix-th-0.30/CorsixTH/Lua/objects/surgeon_screen.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/objects/surgeon_screen.lua 2018-07-21 11:13:17.000000000 +0000 @@ -39,6 +39,10 @@ } class "SurgeonScreen" (Object) + +---@type SurgeonScreen +local SurgeonScreen = _G["SurgeonScreen"] + function SurgeonScreen:SurgeonScreen(...) self:Object(...) self.num_green_outfits = 2 diff -Nru corsix-th-0.30/CorsixTH/Lua/persistance.lua corsix-th-0.62/CorsixTH/Lua/persistance.lua --- corsix-th-0.30/CorsixTH/Lua/persistance.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/persistance.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,12 +18,35 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local persist = require "persist" +local persist = require("persist") local saved_permanents = {} strict_declare_global "permanent" strict_declare_global "unpermanent" +local th_getfenv +local th_getupvalue +if _G._VERSION == "Lua 5.2" or _G._VERSION == "Lua 5.3" then + th_getfenv = function(f) + local _, val = nil, nil + if type(f) == "function" then + _, val = debug.getupvalue(f, 1) + elseif type(f) == "userdata" then + val = debug.getuservalue(f) + else + print('Unhandled argument to th_getfenv') + end + return val + end + + th_getupvalue = function(f, n) + return debug.getupvalue(f, n + 1) + end +else + th_getfenv = debug.getfenv + th_getupvalue = debug.getupvalue +end + function permanent(name, ...) if select('#', ...) == 0 then return function (...) return permanent(name, ...) end @@ -42,7 +65,7 @@ local --[[persistable:persistance_global_fetch]] function global_fetch(...) local val = _G - for _, k in ipairs{...} do + for _, k in ipairs({...}) do val = val[k] end return val @@ -77,7 +100,12 @@ permanent[class_mt] = name .. ".2" for k, v in pairs(class) do if type(v) == "function" then - permanent[v] = name ..".".. k + permanent[v] = name .. "." .. k + end + end + for k, v in pairs(class._metatable) do + if type(v) == "function" then + permanent[v] = name .. "._metatable." .. k end end until true end @@ -89,12 +117,13 @@ end if type(lib) == "table" then for k, v in pairs(lib) do - local type = type(v) - if type == "function" or type == "table" or type == "userdata" then - permanent[v] = name ..".".. k - if name == "TH" and type == "table" then + local type_of_lib = type(v) + if type_of_lib == "function" or type_of_lib == "table" or type_of_lib == "userdata" then + permanent[v] = name .. "." .. k + if name == "TH" and type_of_lib == "table" then -- C class metatables - permanent[debug.getfenv(getmetatable(v).__call)] = name ..".".. k .."." + local callenv = th_getfenv(getmetatable(v).__call) + permanent[callenv] = name .. "." .. k .. "." end end end @@ -105,13 +134,13 @@ -- Bits of the app permanent[TheApp] = "TheApp" - for _, key in ipairs{"config", "modes", "video", "strings", "audio", "gfx", "fs"} do - permanent[TheApp[key]] = inverted and "TheApp.".. key or {global_fetch, "TheApp", key} + for _, key in ipairs({"config", "modes", "video", "strings", "audio", "gfx", "fs"}) do + permanent[TheApp[key]] = inverted and "TheApp." .. key or {global_fetch, "TheApp", key} end - for _, collection in ipairs{"walls", "objects", "rooms", "humanoid_actions", "diseases"} do + for _, collection in ipairs({"walls", "objects", "rooms", "humanoid_actions", "diseases"}) do for k, v in pairs(TheApp[collection]) do if type(k) == "string" then - permanent[v] = inverted and "TheApp.".. collection ..".".. k or {global_fetch, "TheApp", collection, k} + permanent[v] = inverted and "TheApp." .. collection .. "." .. k or {global_fetch, "TheApp", collection, k} end end end @@ -127,7 +156,7 @@ if inverted then -- as the object was persisted as a table, we need to add some magic to -- the __index metamethod to interpret this table as a function call - getmetatable(return_val).__index = function(t, k) + getmetatable(return_val).__index = function(_, k) if type(k) == "table" then return k[1](unpack(k, 2)) end @@ -164,7 +193,7 @@ if type(exploring) == "table" then for key, val in pairs(exploring) do if not explored[val] then - to_explore[val] = name .."."..tostring(key) + to_explore[val] = name .. "." ..tostring(key) explored[val] = true end end @@ -172,24 +201,24 @@ local i = 0 while true do i = i + 1 - local name, val = debug.getupvalue(exploring, i) - if not name then + local dbg_name, val = debug.getupvalue(exploring, i) + if not dbg_name then break end if val ~= nil and not explored[val] then - to_explore[val] = name .."." + to_explore[val] = name .. "." explored[val] = true end end end local mt = debug.getmetatable(exploring) if mt and not explored[mt] then - to_explore[mt] = name .."." + to_explore[mt] = name .. "." explored[mt] = true end - mt = debug.getfenv(exploring) + mt = th_getfenv(exploring) if mt and not explored[mt] then - to_explore[mt] = name .."." + to_explore[mt] = name .. "." explored[mt] = true end end @@ -222,6 +251,8 @@ --end, persist.errcatch) end +--! Save a game to disk. +--!param filename (string) Path of the file to write. function SaveGameFile(filename) local data = SaveGame() local f = assert(io.open(filename, "wb")) @@ -231,7 +262,8 @@ function LoadGame(data) --local status, res = xpcall(function() - local state = assert(persist.load(data, MakePermanentObjectsTable(true))) + local objtable = MakePermanentObjectsTable(true) + local state = assert(persist.load(data, objtable)) state.ui:resync(TheApp.ui) TheApp.ui = state.ui TheApp.world = state.world @@ -260,7 +292,7 @@ function LoadGameFile(filename) local f = assert(io.open(filename, "rb")) - local data = f:read"*a" + local data = f:read("*a") f:close() LoadGame(data) end diff -Nru corsix-th-0.30/CorsixTH/Lua/queue.lua corsix-th-0.62/CorsixTH/Lua/queue.lua --- corsix-th-0.30/CorsixTH/Lua/queue.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/queue.lua 2018-07-21 11:13:17.000000000 +0000 @@ -30,16 +30,22 @@ -- a queue via its methods rather than directly. class "Queue" +---@type Queue +local Queue = _G["Queue"] + +--! Constructor of a queue. function Queue:Queue() - self.reported_size = 0 - self.expected = {} + self.reported_size = 0 -- Number of real patients + self.expected = {} -- Expected patients self.callbacks = {} - self.expected_count = 0 + self.expected_count = 0 -- Number of expected patients self.visitor_count = 0 - self.max_size = 6 + self.max_size = 6 -- Maximum queue length (default value) self.bench_threshold = 0 end +--! A humanoid is expected in a queue. +--!param humanoid New patient that is expected. function Queue:expect(humanoid) if not self.expected[humanoid] and not class.is(humanoid, Vip) then self.expected[humanoid] = true @@ -47,6 +53,8 @@ end end +--! A humanoid is canceled as expected in a queue. +--!param humanoid Patient that is not coming to this queue. function Queue:unexpect(humanoid) if self.expected[humanoid] then self.expected[humanoid] = nil @@ -54,10 +62,14 @@ end end +--! Lower the max queue length. +--!param amount (int) Decrement length value of the queue. function Queue:decreaseMaxSize(amount) self.max_size = math.max(0, self.max_size - amount) end +--! Increase max queue length. +--!param amount (int) Increment length value of the queue. function Queue:increaseMaxSize(amount) self.max_size = math.min(30, self.max_size + amount) end @@ -66,10 +78,15 @@ self.bench_threshold = standing_count end +--! Set max queue length. +--!param queue_count (int) New max queue length to set. function Queue:setMaxQueue(queue_count) self.max_size = queue_count end +--! Total size of the queue, which are various people wanting in or out of the room. +--! For a true patient queue count, use Queue:reportedSize. +--!return (int) Number of various people in the queue. function Queue:size() -- Rememeber, the size includes people waiting to leave and staff waiting to enter -- For just the patients waiting to enter, use Queue:reportedSize() @@ -79,21 +96,28 @@ return #self end +--! Retrieve whether the queue is full. +--!return (boolean) Whether the queue is full. function Queue:isFull() return #self >= self.max_size end +--! Get the number of real patients in the queue. +--!return (int) Number of real patients in the queue. function Queue:reportedSize() return self.reported_size end +--! Get the number of expected patients. +--!return (int) Number of expected patients (in the near future). function Queue:expectedSize() return self.expected_count end +--! Check if the queue has an emergency patient. +--!return (boolean) Whether an emergency patient was found in the queue. function Queue:hasEmergencyPatient() - local index = #self - for i, humanoid in ipairs(self) do + for _, humanoid in ipairs(self) do if humanoid.is_emergency then return true end @@ -101,12 +125,15 @@ return false end --- Returns how many patients are queued or expected +--! Retrieve the total number of queued and expected patients. +--return (int) Number of patients. function Queue:patientSize() return self.reported_size + self.expected_count end - +--! Get the 'index' real patient. +--!param index (int) Index of the patient to retrieve (runs up to Queue:reportedSize). +--!return Patient at the queried point in the queue. function Queue:reportedHumanoid(index) return self[#self - self.reported_size + index] end @@ -145,7 +172,8 @@ end increment_reported_size = false end - if humanoid.is_emergency or class.is(humanoid, Vip)then -- Emergencies and any VIP's get put before all the other patients, but AFTER currently queued emergencies. + -- Emergencies and any VIP's get put before all the other patients, but AFTER currently queued emergencies. + if humanoid.is_emergency or class.is(humanoid, Vip) or class.is(humanoid, Inspector) then while index > 1 do local before = self[index - 1] if before.is_emergency then @@ -160,22 +188,30 @@ self.callbacks[humanoid] = callbacks_on table.insert(self, index, humanoid) for i = index + 1, #self do - local humanoid = self[i] - local callbacks = self.callbacks[humanoid] + local queued_humanoid = self[i] + local callbacks = self.callbacks[queued_humanoid] if callbacks then - callbacks:onChangeQueuePosition(humanoid) + callbacks:onChangeQueuePosition(queued_humanoid) end end end +--! Get the first person in the queue (queue is not changed). +--! Note that first person may not be a patient, use Queue:reportedHumanoid to get patients +--!return First person in the queue. function Queue:front() return self[1] end +--! Get the last person in the queue (queue is not changed). +--!return Last person in the queue. function Queue:back() return self[#self] end +--! Pop first person from the queue. +--! Note that first person may not be a patient, use Queue:reportedHumanoid to get patients +--!return First person in the queue. function Queue:pop() if self.reported_size == #self then self.reported_size = self.reported_size - 1 @@ -189,7 +225,7 @@ end self.callbacks[oldfront] = nil for _, humanoid in ipairs(self) do - local callbacks = self.callbacks[humanoid] + callbacks = self.callbacks[humanoid] if callbacks then callbacks:onChangeQueuePosition(humanoid) end @@ -197,6 +233,10 @@ return oldfront end +--! Remove person from the queue by index number. +--! Note that the person may not be a patient. +--!param index (jnt) Index in the queue of the person to remove. +--!return The removed person. function Queue:remove(index) if self[index] == nil then return @@ -217,6 +257,9 @@ return value end +--! Remove a person by value from the queue. +--!param value Person to remove. +--!return Whether the person could be found (and was removed). function Queue:removeValue(value) for i = 1, #self do if self[i] == value then @@ -227,6 +270,10 @@ return false end +--! Move the person at position 'index' to position 'new_index'. +--! Persons between 'index' and 'new_index' move one place to 'index'. +--!param index (int) Index number of the person to move. +--!param new_index (int) Destination of the person being moved. function Queue:move(index, new_index) if self[index] == nil or self[new_index] == nil or index == new_index then return @@ -247,19 +294,18 @@ end end --- Called when reception desk is destroyed. May be extended later to handle removed rooms, too. --- Update: Now also used when a room is destroyed from a crashed machine. +--! Called when reception desk is destroyed, or when a room is destroyed from a crashed machine. function Queue:rerouteAllPatients(action) - for i, humanoid in ipairs(self) do + for _, humanoid in ipairs(self) do -- slight delay so the desk is really destroyed before rerouting - humanoid:setNextAction({name = "idle", count = 1}) + humanoid:setNextAction(IdleAction():setCount(1)) -- Don't queue the same action table, but clone it for each patient. local clone = {} for k, v in pairs(action) do clone[k] = v end humanoid:queueAction(clone) end for humanoid in pairs(self.expected) do - humanoid:setNextAction({name = "idle", count = 1}) + humanoid:setNextAction(IdleAction():setCount(1)) humanoid:queueAction(action) self:unexpect(humanoid) end diff -Nru corsix-th-0.30/CorsixTH/Lua/research_department.lua corsix-th-0.62/CorsixTH/Lua/research_department.lua --- corsix-th-0.30/CorsixTH/Lua/research_department.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/research_department.lua 2018-07-21 11:13:17.000000000 +0000 @@ -31,35 +31,38 @@ --! Manages all things related to research for one hospital. class "ResearchDepartment" +---@type ResearchDepartment +local ResearchDepartment = _G["ResearchDepartment"] + function ResearchDepartment:ResearchDepartment(hospital) self.hospital = hospital self.world = hospital.world + -- This list contains a lot of information. -- Progress of object discovery, object improvement, drug improvement -- dito costs and room build costs. self.research_progress = {} - self.level_config = hospital.world.map.level_config self:initResearch() end -- Initialize research for the level. function ResearchDepartment:initResearch() local hospital = self.hospital - local config = self.level_config.objects + local cfg_objects = self.world.map.level_config.objects local cure, diagnosis, improve, drug -- Initialize object research for _, object in ipairs(TheApp.objects) do - if config[object.thob] and (config[object.thob].AvailableForLevel == 1) - and object.research_category then + if cfg_objects[object.thob] and cfg_objects[object.thob].AvailableForLevel == 1 and + object.research_category then self.research_progress[object] = { points = 0, - start_strength = config[object.thob].StartStrength, - cost = not self.world.free_build_mode and config[object.thob].StartCost or 0, - discovered = config[object.thob].StartAvail == 1, + start_strength = cfg_objects[object.thob].StartStrength, + cost = not self.world.free_build_mode and cfg_objects[object.thob].StartCost or 0, + discovered = cfg_objects[object.thob].StartAvail == 1, strength_imp = 0, cost_imp = 0, } - if config[object.thob].StartAvail == 0 then + if cfg_objects[object.thob].StartAvail == 0 then if object.research_category == "cure" then cure = object elseif object.research_category == "diagnosis" then @@ -68,7 +71,7 @@ end -- TODO: Do we want some kind of specific order here, e.g. -- the same as in the original? - if object.default_strength and config[object.thob].StartAvail == 1 then + if object.default_strength and cfg_objects[object.thob].StartAvail == 1 then improve = object end end @@ -131,7 +134,7 @@ for object, progress in pairs(self.research_progress) do -- Only check objects if object.default_strength then - local avail_at = self.level_config.objects[object.thob].WhenAvail + local avail_at = self.world.map.level_config.objects[object.thob].WhenAvail if not progress.discovered and avail_at ~= 0 and month >= avail_at then self:discoverObject(object, true) end @@ -237,8 +240,8 @@ end elseif category == "improvements" then -- Find the object which needs improvements the most. - local min_strength = self.level_config.gbv.MaxObjectStrength - local max_strength = self.level_config.gbv.MaxObjectStrength + local max_strength = self.world.map.level_config.gbv.MaxObjectStrength + local min_strength = max_strength for object, progress in pairs(self.research_progress) do if object.default_strength then -- Don't improve those that already have the max strength @@ -292,30 +295,29 @@ --]] function ResearchDepartment:getResearchRequired(thing) local required - local level_config = self.level_config - local objects = level_config.objects + local level_config = self.world.map.level_config local expert = level_config.expertise - local research_info = self.research_progress[thing] if thing.thob then -- An object - required = objects[thing.thob].RschReqd + required = level_config.objects[thing.thob].RschReqd if not required then -- It didn't know, so use the fallback instead. if not thing.research_fallback then -- This object is not researchable! - print(("Warning: %s has been defined as "):format(thing.id) - .. "researchable, but no requirements to fulfil could be found.") + print(("Warning: %s has been defined as "):format(thing.id) .. + "researchable, but no requirements to fulfil could be found.") else required = expert[thing.research_fallback].RschReqd end end -- Actually want to know how much to improve? + local research_info = self.research_progress[thing] if research_info.discovered then local improve_percent = level_config.gbv.RschImproveCostPercent local increment = level_config.gbv.RschImproveIncrementPercent - improve_percent = improve_percent + increment*research_info.cost_imp - required = required * improve_percent/100 + improve_percent = improve_percent + increment * research_info.cost_imp + required = required * improve_percent / 100 end elseif thing.drug then -- A drug @@ -336,23 +338,19 @@ ]] function ResearchDepartment:addResearchPoints(points, autopsy_room) - local level_config = self.level_config - local objects = level_config.objects - local expert = level_config.expertise - local areas = self.research_policy - local hospital = self.hospital + local level_config = self.world.map.level_config ---------------------- An autopsy has been done --------------------------- if autopsy_room then -- Do something only if the room is among those not yet discovered. - for room, value in pairs(hospital.undiscovered_rooms) do + for room, _ in pairs(self.hospital.undiscovered_rooms) do if room.id == autopsy_room then -- Find an object within this room that needs research points. for object, _ in pairs(room.objects_needed) do local research = self.research_progress[TheApp.objects[object]] if research and not research.discovered then local required = self:getResearchRequired(TheApp.objects[object]) - local advance = required * level_config.gbv.AutopsyRschPercent/100 + local advance = required * level_config.gbv.AutopsyRschPercent / 100 research.points = research.points + advance -- Maybe we now have enough to discover the object? @@ -372,11 +370,12 @@ -- Fetch the level research divisor. local divisor = level_config.gbv.ResearchPointsDivisor or 5 - points = math.ceil(points*self.research_policy.global/(100*divisor)) + points = math.ceil(points * self.research_policy.global / (100 * divisor)) -- Divide the points into the different categories and check if -- it is time to discover something - for name, info in pairs(areas) do + local areas = self.research_policy + for _, info in pairs(areas) do -- Don't touch the value "global". if type(info) == "table" then -- Some categories may be finished @@ -385,7 +384,7 @@ local research_info = self.research_progress[info.current] local stored = research_info.points -- Add just a little randomness - research_info.points = stored + math.n_random(1, 0.2)*points*info.frac/100 + research_info.points = stored + math.n_random(1, 0.2) * points * info.frac / 100 local required = self:getResearchRequired(info.current) if required and required < research_info.points then research_info.points = 0 @@ -431,9 +430,8 @@ end else -- Time to improve effectiveness - local improve_rate = self.level_config.gbv.DrugImproveRate - disease.cure_effectiveness = math.min(100, - disease.cure_effectiveness + improve_rate) + local improve_rate = self.world.map.level_config.gbv.DrugImproveRate + disease.cure_effectiveness = math.min(100, disease.cure_effectiveness + improve_rate) research_info.effect_imp = research_info.effect_imp + 1 end if self.hospital == self.world.ui.hospital then @@ -472,7 +470,7 @@ end end research_info.cost_imp = research_info.cost_imp + 1 - local max = self.level_config.gbv.MaxObjectStrength + local max = self.world.map.level_config.gbv.MaxObjectStrength if research_info.start_strength >= max then if self.research_policy.specialisation.current == machine then self.research_policy.specialisation.current = self.drain @@ -485,7 +483,7 @@ end else -- Time to improve strength - local improve_rate = self.level_config.gbv.ResearchIncrement + local improve_rate = self.world.map.level_config.gbv.ResearchIncrement research_info.start_strength = research_info.start_strength + improve_rate research_info.strength_imp = research_info.strength_imp + 1 @@ -510,8 +508,8 @@ for room, _ in pairs(self.hospital.undiscovered_rooms) do local discovery = true for needed, _ in pairs(room.objects_needed) do - if self.research_progress[TheApp.objects[needed]] - and not self.research_progress[TheApp.objects[needed]].discovered then + local obj = self.research_progress[TheApp.objects[needed]] + if obj and not obj.discovered then discovery = false break end @@ -521,26 +519,24 @@ self.hospital.undiscovered_rooms[room] = nil if self.hospital == self.world.ui.hospital then if automatic then - self.world.ui.adviser:say(_A.research.new_available - :format(object.name)) + self.world.ui.adviser:say(_A.research.new_available:format(object.name)) else - self.world.ui.adviser:say(_A.research.new_machine_researched - :format(object.name)) + self.world.ui.adviser:say(_A.research.new_machine_researched:format(object.name)) end end -- It may now be possible to continue researching machine improvements local current_improvement_research = self.research_policy.improvements.current - local min_strength = self.level_config.gbv.MaxObjectStrength - local max_strength = self.level_config.gbv.MaxObjectStrength + local max_strength = self.world.map.level_config.gbv.MaxObjectStrength + local min_strength = max_strength -- If we're not researching any improvement right now, and the newest discovery was -- a machine that requires an improvement, switch the current policy. if (not current_improvement_research or current_improvement_research.dummy) then - for object, progress in pairs(self.research_progress) do - if object.default_strength then - -- Don't improve those that already have the max strength + for research_object, progress in pairs(self.research_progress) do + if research_object.default_strength then + -- Don't improve those that already have the max strength if progress.start_strength < max_strength then if progress.discovered and progress.start_strength < min_strength then - self.research_policy["improvements"].current = object + self.research_policy["improvements"].current = research_object min_strength = progress.start_strength end end @@ -582,8 +578,8 @@ local current_drug_research = self.research_policy.drugs.current -- If we're not researching any drug right now, and the newest discovery was -- a disease that requires a drug, switch the current policy. - if (not current_drug_research or current_drug_research.dummy) - and casebook_disease.drug then + if (not current_drug_research or current_drug_research.dummy) and + casebook_disease.drug then self.research_policy.drugs.current = casebook_disease end self:setResearchConcentration() @@ -681,3 +677,9 @@ end end end + +function ResearchDepartment:afterLoad(old, new) + if old < 106 then + self.level_config = nil + end +end diff -Nru corsix-th-0.30/CorsixTH/Lua/room.lua corsix-th-0.62/CorsixTH/Lua/room.lua --- corsix-th-0.30/CorsixTH/Lua/room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,10 +18,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" - class "Room" +---@type Room +local Room = _G["Room"] + function Room:Room(x, y, w, h, id, room_info, world, hospital, door, door2) self.id = id self.world = world @@ -61,8 +62,13 @@ self.objects = {--[[a set rather than a list]]} -- the set of humanoids walking to this room self.humanoids_enroute = {--[[a set rather than a list]]} + + self.world:prepareRectangleTilesForBuild(self.x, self.y, self.width, self.height) end +--! Get the tile next to the door. +--!param inside (bool) If set, get the tile inside the room, else get the tile outside. +--!return x,y (tile coordinates) of the tile next to the door. function Room:getEntranceXY(inside) local door = self.door local x, y = door.tile_x, door.tile_y @@ -76,15 +82,11 @@ return x, y end +--! Construct an 'walk' action to the tile next to the door, just outside the room. +--!return Action to move to the tile just outside the room. function Room:createLeaveAction() local x, y = self:getEntranceXY(false) - return { - name = "walk", - x = x, - y = y, - is_leaving = true, - truncate_only_on_high_priority = true, - } + return WalkAction(x, y):setIsLeaving(true):truncateOnHighPriority() end function Room:createEnterAction(humanoid_entering, callback) @@ -92,16 +94,16 @@ if not callback then if class.is(humanoid_entering, Patient) then callback = --[[persistable:room_patient_enroute_cancel]] function() - humanoid_entering:setNextAction({name = "seek_room", room_type = self.room_info.id}) + humanoid_entering:setNextAction(SeekRoomAction(self.room_info.id)) end elseif class.is(humanoid_entering, Vip) then callback = --[[persistable:room_vip_enroute_cancel]] function() - humanoid_entering:setNextAction({name = "idle"}) - humanoid_entering.waiting = 1; + humanoid_entering:setNextAction(IdleAction()) + humanoid_entering.waiting = 1 end else callback = --[[persistable:room_humanoid_enroute_cancel]] function() - humanoid_entering:setNextAction({name = "meander"}) + humanoid_entering:setNextAction(MeanderAction()) end end end @@ -109,10 +111,11 @@ self.humanoids_enroute[humanoid_entering] = {callback = callback} end - return {name = "walk", x = x, y = y, - is_entering = humanoid_entering and self or true} + return WalkAction(x, y):setIsEntering(true) end +--! Get a patient in the room. +--!return A patient (humanoid) if there is a patient, nil otherwise. function Room:getPatient() for humanoid in pairs(self.humanoids) do if class.is(humanoid, Patient) then @@ -121,6 +124,8 @@ end end +--! Count the number of patients in the room. +--!return Number of patients in the room. function Room:getPatientCount() local count = 0 for humanoid in pairs(self.humanoids) do @@ -144,7 +149,7 @@ -- If the patient was sent home while in the room, don't -- do anything apart from removing any leading idle action. if not patient.hospital then - if patient.action_queue[1].name == "idle" then + if patient:getCurrentAction().name == "idle" then patient:finishAction() end return @@ -155,28 +160,34 @@ self:setStaffMembersAttribute("dealing_with_patient", false) end - if patient.disease and not patient.diagnosed then - -- Patient not yet diagnosed, hence just been in a diagnosis room. - -- Increment diagnosis_progress, and send patient back to GP. - - patient:completeDiagnosticStep(self) - patient:queueAction{name = "seek_room", room_type = "gp"} - self.hospital:receiveMoneyForTreatment(patient) - elseif patient.disease and patient.diagnosed then - -- Patient just been in a cure room, so either patient now cured, or needs - -- to move onto next cure room. - patient.cure_rooms_visited = patient.cure_rooms_visited + 1 - local next_room = patient.disease.treatment_rooms[patient.cure_rooms_visited + 1] - if next_room then - -- Do not say that it is a treatment room here, since that check should already have been made. - patient:queueAction{name = "seek_room", room_type = next_room} + if patient.disease then + if not patient.diagnosed then + -- Patient not yet diagnosed, hence just been in a diagnosis room. + -- Increment diagnosis_progress, and send patient back to GP. + + patient:completeDiagnosticStep(self) + self.hospital:receiveMoneyForTreatment(patient) + if patient:agreesToPay("diag_gp") then + patient:queueAction(SeekRoomAction("gp")) + else + patient:goHome("over_priced", "diag_gp") + end else - -- Patient is "done" at the hospital - patient:treated() + -- Patient just been in a cure room, so either patient now cured, or needs + -- to move onto next cure room. + patient.cure_rooms_visited = patient.cure_rooms_visited + 1 + local next_room = patient.disease.treatment_rooms[patient.cure_rooms_visited + 1] + if next_room then + -- Do not say that it is a treatment room here, since that check should already have been made. + patient:queueAction(SeekRoomAction(next_room)) + else + -- Patient is "done" at the hospital + patient:treatDisease() + end end else - patient:queueAction{name = "meander", count = 2} - patient:queueAction{name = "idle"} + patient:queueAction(MeanderAction():setCount(2)) + patient:queueAction(IdleAction()) end if self.dealt_patient_callback then @@ -247,26 +258,29 @@ end return false else - for attribute, count in pairs(missing) do - return false - end - return true + return next(missing) == nil end end -local no_staff = {} +local no_staff = {} -- Constant denoting 'no staff at all' in a room. + +--! Get the type and number of maximum staff for the room. +--!return (table) Type and number of maximum staff. function Room:getMaximumStaffCriteria() -- Some rooms have dynamic criteria (i.e. dependent upon the number of items -- in the room), so this method is provided for such rooms to override it. return self.room_info.maximum_staff or self.room_info.required_staff or no_staff end +--! Get the type and number of required staff for the room. +--!return (table) Type and number of required staff. function Room:getRequiredStaffCriteria() return self.room_info.required_staff or no_staff end function Room:onHumanoidEnter(humanoid) assert(not self.humanoids[humanoid], "Humanoid entering a room that they are already in") + humanoid.in_room = self humanoid.last_room = self -- Remember where the staff was for them to come back after staffroom rest -- Do not set humanoids[humanoid] here, because it affect staffFitsInRoom test @@ -279,14 +293,14 @@ -- If this humanoid for some strange reason happens to enter a non-active room, -- just leave. if not self.is_active then - print ('Warning: humanoid entering non-active room') + print('Warning: humanoid entering non-active room') self.humanoids[humanoid] = true if class.is(humanoid, Patient) then self:makeHumanoidLeave(humanoid) - humanoid:queueAction({name = "seek_room", room_type = self.room_info.id}) + humanoid:queueAction(SeekRoomAction(self.room_info.id)) else humanoid:setNextAction(self:createLeaveAction()) - humanoid:queueAction({name = "meander"}) + humanoid:queueAction(MeanderAction()) end return end @@ -299,7 +313,7 @@ assert(humanoid.on_call.object:getRoom() == self, "Handyman arrived is on call but not arriving to the designated room") else -- If the handyman was not assigned for the job (e.g. drop by manual pickup), do answer a call - humanoid:setNextAction{name = "answer_call"} + humanoid:setNextAction(AnswerCallAction()) end return end @@ -327,7 +341,7 @@ end if not staff_member.dealing_with_patient then staff_member:setNextAction(self:createLeaveAction()) - staff_member:queueAction{name = "meander"} + staff_member:queueAction(MeanderAction()) self.staff_member = humanoid humanoid:setCallCompleted() self:commandEnteringStaff(humanoid) @@ -335,16 +349,16 @@ if self.waiting_staff_member then self.waiting_staff_member.waiting_on_other_staff = nil self.waiting_staff_member:setNextAction(self:createLeaveAction()) - self.waiting_staff_member:queueAction{name = "meander"} + self.waiting_staff_member:queueAction(MeanderAction()) end self:createDealtWithPatientCallback(humanoid) humanoid.waiting_on_other_staff = true - humanoid:setNextAction{name = "meander"} + humanoid:setNextAction(MeanderAction()) end else self.humanoids[humanoid] = true humanoid:setNextAction(self:createLeaveAction()) - humanoid:queueAction{name = "meander"} + humanoid:queueAction(MeanderAction()) humanoid:adviseWrongPersonForThisRoom() end else @@ -358,6 +372,16 @@ self.humanoids[humanoid] = true self:tryAdvanceQueue() if class.is(humanoid, Patient) then + -- An infect patient's disease may have changed so they might have + -- been sent to an incorrect diagnosis room, they should leave and go + -- back to the gp for redirection + if (humanoid.infected) and not humanoid.diagnosed and + not self:isDiagnosisRoomForPatient(humanoid) then + humanoid:queueAction(self:createLeaveAction()) + humanoid.needs_redirecting = true + humanoid:queueAction(SeekRoomAction("gp")) + return + end -- Check if the staff requirements are still fulfilled (the staff might have left / been picked up meanwhile) if self:testStaffCriteria(self:getRequiredStaffCriteria()) then if self.staff_member then @@ -372,38 +396,44 @@ end function Room:createDealtWithPatientCallback(humanoid) - self.dealt_patient_callback = --[[persistable:room_dealt_with_patient_callback]] function (humanoid) - if not humanoid.waiting_on_other_staff then + self.dealt_patient_callback = --[[persistable:room_dealt_with_patient_callback]] function (staff_humanoid) + if not staff_humanoid.waiting_on_other_staff then return end local staff_member = self:getStaffMember() if staff_member then staff_member:setNextAction(self:createLeaveAction()) - staff_member:queueAction{name = "meander"} + staff_member:queueAction(MeanderAction()) staff_member:setMood("staff_wait", "deactivate") staff_member:setDynamicInfoText("") end - humanoid:setCallCompleted() - humanoid.waiting_on_other_staff = nil - self:commandEnteringStaff(humanoid) - self:setStaffMember(humanoid) + staff_humanoid:setCallCompleted() + staff_humanoid.waiting_on_other_staff = nil + self:commandEnteringStaff(staff_humanoid) + self:setStaffMember(staff_humanoid) self.waiting_staff_member = nil self.dealt_patient_callback = nil end self.waiting_staff_member = humanoid end --- Returns the current staff member. Can be overriden in rooms with multiples staff members to return the desired one. +--! Get the current staff member. +-- Can be overridden in rooms with multiple staff members to return the desired one. +--!return (staff) The current staff member. function Room:getStaffMember() return self.staff_member end +--! Set the current staff member. +--!param staff (staff) Staff member to denote as current staff. function Room:setStaffMember(staff) self.staff_member = staff end +--! Does the given staff member fit in the room? -- Returns false if the room is already full of staff or if the given member of staff cannot help out. -- Otherwise returns true. +--!return (bool) True if the staff member can work in the room, else False. function Room:staffFitsInRoom(staff) local criteria = self:getMaximumStaffCriteria() if self:testStaffCriteria(criteria) or not self:testStaffCriteria(criteria, staff) then @@ -423,15 +453,6 @@ return false end --- Tests whether this room is awaiting more staff to be able to do business -function Room:isWaitingToGetStaff(staff) - if not self.is_active or (self.door.queue:patientSize() == 0 - and not (self.door.reserved_for and class.is(self.door.reserved_for, Patient) or false)) then - return false - end - return self:staffFitsInRoom(staff, true) -end - --! When a valid member of staff enters the room this function is called. -- Can be extended in derived classes. --!param humanoid The staff in question @@ -440,7 +461,7 @@ function Room:commandEnteringStaff(humanoid, already_initialized) if not already_initialized then self.staff_member = humanoid - humanoid:setNextAction{name = "meander"} + humanoid:setNextAction(MeanderAction()) end self:tryToFindNearbyPatients() humanoid:setDynamicInfoText("") @@ -456,19 +477,18 @@ self.door.queue.visitor_count = self.door.queue.visitor_count + 1 humanoid:updateDynamicInfo("") - for humanoid in pairs(self.humanoids) do -- Staff is no longer waiting - if class.is(humanoid, Staff) then - if humanoid.humanoid_class ~= "Handyman" then - humanoid:setMood("staff_wait", "deactivate") - humanoid:setDynamicInfoText("") + for room_humanoid in pairs(self.humanoids) do -- Staff is no longer waiting + if class.is(room_humanoid, Staff) then + if room_humanoid.humanoid_class ~= "Handyman" then + room_humanoid:setMood("staff_wait", "deactivate") + room_humanoid:setDynamicInfoText("") end end end end function Room:tryAdvanceQueue() - if self.door.queue:size() > 0 and not self.door.user - and not self.door.reserved_for then + if self.door.queue:size() > 0 and not self.door.user and not self.door.reserved_for then local front = self.door.queue:front() -- These two conditions differ by the waiting symbol @@ -477,11 +497,11 @@ self.door:updateDynamicInfo() -- Do nothing if it is the staff room or training room. if self:hasQueueDialog() then - for humanoid in pairs(self.humanoids) do -- Staff is now waiting - if class.is(humanoid, Staff) then - if humanoid.humanoid_class ~= "Handyman" then - humanoid:setMood("staff_wait", "activate") - humanoid:setDynamicInfoText(_S.dynamic_info.staff.actions.waiting_for_patient) + for room_humanoid in pairs(self.humanoids) do -- Staff is now waiting + if class.is(room_humanoid, Staff) then + if room_humanoid.humanoid_class ~= "Handyman" then + room_humanoid:setMood("staff_wait", "activate") + room_humanoid:setDynamicInfoText(_S.dynamic_info.staff.actions.waiting_for_patient) end end end @@ -507,14 +527,14 @@ if class.is(humanoid, Patient) then -- Some staff member in the room might be waiting to get to the staffroom. - for humanoid in pairs(self.humanoids) do + for room_humanoid in pairs(self.humanoids) do -- A patient leaving allows doctors/nurses inside to go to staffroom, if needed -- In a rare case a handyman that just decided he wants to go to the staffroom -- could be in the room at the same time as a patient leaves. - if class.is(humanoid, Staff) and humanoid.humanoid_class ~= "Handyman" then - if humanoid.staffroom_needed then - humanoid.staffroom_needed = nil - humanoid:goToStaffRoom() + if class.is(room_humanoid, Staff) and room_humanoid.humanoid_class ~= "Handyman" then + if room_humanoid.staffroom_needed then + room_humanoid.staffroom_needed = nil + room_humanoid:goToStaffRoom() staff_leaving = true end end @@ -544,16 +564,18 @@ end -- Make patients leave the room if there are no longer enough staff if not self:testStaffCriteria(self:getRequiredStaffCriteria()) then + local patient_needs_to_reenter = false + for room_humanoid in pairs(self.humanoids) do + if class.is(room_humanoid, Patient) and self:shouldHavePatientReenter(room_humanoid) then + self:makeHumanoidLeave(room_humanoid) + room_humanoid:queueAction(self:createEnterAction(room_humanoid)) + patient_needs_to_reenter = true + end + end -- Call for staff if needed - if self.is_active and self.door.queue:patientSize() > 0 then + if self.is_active and (patient_needs_to_reenter or self.door.queue:patientSize() > 0) then self.world.dispatcher:callForStaff(self) end - for humanoid in pairs(self.humanoids) do - if class.is(humanoid, Patient) and self:shouldHavePatientReenter(humanoid) then - self:makeHumanoidLeave(humanoid) - humanoid:queueAction(self:createEnterAction(humanoid)) - end - end end -- Remove any unwanted moods the staff member might have humanoid:setMood("staff_wait", "deactivate") @@ -562,7 +584,7 @@ -- The player might be waiting to edit this room if not self.is_active then local i = 0 - for humanoid in pairs(self.humanoids) do + for _ in pairs(self.humanoids) do i = i + 1 end if i == 0 then @@ -579,6 +601,9 @@ local tile_factor = 10 -- how many tiles further are we willing to walk for 1 person fewer in the queue local readiness_bonus = 50 -- how many tiles further are we willing to walk if the room has all the required staff + +--! Score function to decide how desirable a room is for a patient. +--!return (int) The score, lower is better. function Room:getUsageScore() local queue = self.door.queue local score = queue:patientSize() + self:getPatientCount() - self.maximum_patients @@ -639,67 +664,114 @@ self:tryAdvanceQueue() end +--! Try to move a patient from the old room to the new room. +--!param old_room (Room) Room that currently has the patient in the queue. +--!param new_room (Room) Room that wants the patient in the queue. +--!param patient (Humanoid) Patient to move. +--!return (boolean) Whether we are done with the old room (no more patients will come from it). +local function tryMovePatient(old_room, new_room, patient) + local world = new_room.world + + local px, py = patient.tile_x, patient.tile_y + -- Don't reroute the patient if he just decided to go to the toilet + if patient.going_to_toilet ~= "no" then + return false + end + + local new_x, new_y = new_room:getEntranceXY(true) + local old_x, old_y = old_room:getEntranceXY(true) + local new_distance = world:getPathDistance(px, py, new_x, new_y) + if not new_distance then return true end -- Patient cannot reach us, quit trying + + local new_score = new_room:getUsageScore() + new_distance + local old_score + local old_distance = world:getPathDistance(px, py, old_x, old_y) + if old_distance then + old_score = old_room:getUsageScore() + old_distance + else + old_score = new_score + 1 -- Make condition below fail. + end + if new_score >= old_score then return true end + + -- Update the queues + local old_queue = old_room.door.queue + old_queue:removeValue(patient) + patient.next_room_to_visit = new_room + new_room.door.queue:expect(patient) + new_room.door:updateDynamicInfo() + + -- Rewrite the action queue + for i, action in ipairs(patient.action_queue) do + if i ~= 1 then + action.todo_interrupt = true + end + -- The patient will most likely have a queue action for the other + -- room that must be cancelled. To prevent the after_use callback + -- of the drinks machine to enqueue the patient in the other queue + -- again, is_in_queue is set to false so the callback won't run + if action.name == 'queue' then + action.is_in_queue = false + elseif action.name == "walk" and action.x == old_x and action.y == old_y then + patient:queueAction(new_room:createEnterAction(patient), i) + break + end + end + + local interrupted = patient:getCurrentAction() + local on_interrupt = interrupted.on_interrupt + if on_interrupt then + interrupted.on_interrupt = nil + on_interrupt(interrupted, patient, false) + end + return false +end + +--! Try to find new patients for this room by 'stealing' them from other rooms nearby. function Room:tryToFindNearbyPatients() if not self.door.queue then return end - local world = self.world - local our_score = self:getUsageScore() - local our_x, our_y = self:getEntranceXY(true) - for _, room in pairs(self.world.rooms) do - if room.hospital == self.hospital and room.room_info == self.room_info - and room.door.queue and room.door.queue:reportedSize() >= 2 then - local other_score = room:getUsageScore() - local other_x, other_y = room:getEntranceXY(true) - local queue = room.door.queue - while queue:reportedSize() > 1 do - local patient = queue:back() - local px, py = patient.tile_x, patient.tile_y - if world:getPathDistance(px, py, our_x, our_y) + our_score < - world:getPathDistance(px, py, other_x, other_y) + other_score then - -- Update the queues - queue:removeValue(patient) - patient.next_room_to_visit = self - self.door.queue:expect(patient) - self.door:updateDynamicInfo() - - -- Update our cached values - our_score = self:getUsageScore() - other_score = room:getUsageScore() - - -- Rewrite the action queue - for i, action in ipairs(patient.action_queue) do - if i ~= 1 then - action.todo_interrupt = true - end - if action.name == "walk" and action.x == other_x and action.y == other_y then - local action = self:createEnterAction(patient) - patient:queueAction(action, i) - break - end - end - local interrupted = patient.action_queue[1] - local on_interrupt = interrupted.on_interrupt - if on_interrupt then - interrupted.on_interrupt = nil - on_interrupt(interrupted, patient, false) - end - else - break - end + + for _, old_room in pairs(self.world.rooms) do + if old_room.hospital == self.hospital and old_room ~= self and + old_room.room_info == self.room_info and old_room.door.queue and + old_room.door.queue:reportedSize() >= 2 then + local old_queue = old_room.door.queue + local pat_number = old_queue:reportedSize() + while pat_number > 1 do + local patient = old_queue:reportedHumanoid(pat_number) + if tryMovePatient(old_room, self, patient) then break end + -- tryMovePatient may have just removed patient 'pat_number', but it does + -- not change the queue in front of it. 'pat_number - 1' thus still exists. + pat_number = pat_number - 1 end end end end +--! Explode the room. function Room:crashRoom() self.door:closeDoor() if self.door2 then self.door2.hover_cursor = nil end + -- A patient might be about to use the door (staff are dealt with elsewhere): + if self.door.reserved_for then + local person = self.door.reserved_for + if not person:isLeaving() then + if class.is(person, Patient) then + --Delay so that room is destroyed before the SeekRoom search. + person:queueAction(IdleAction():setCount(1)) + person:queueAction(SeekRoomAction(self.room_info.id)) + end + end + person:finishAction() + self.door.reserved_for = nil + end + local remove_humanoid = function(humanoid) - humanoid:queueAction({name = "idle"}, 1) + humanoid:queueAction(IdleAction(), 1) humanoid.user_of = nil -- Make sure any emergency list is not messed up. -- Note that these humanoids might just have been kicked. (No hospital set) @@ -733,8 +805,8 @@ end object.unreachable = true end - if object.object_type.id ~= "door" and not object.strength - and object.object_type.class ~= "SwingDoor" then + if object.object_type.id ~= "door" and not object.strength and + object.object_type.class ~= "SwingDoor" then object.user = nil object.user_list = nil object.reserved_for = nil @@ -785,19 +857,58 @@ -- Tells a humanoid in the room to leave it. This can be overridden for special -- handling, e.g. if the humanoid needs to change before leaving the room. function Room:makeHumanoidLeave(patient) - local leave = self:createLeaveAction() - leave.must_happen = true + local leave = self:createLeaveAction():setMustHappen(true) patient:setNextAction(leave) end +function Room:makeHumanoidDressIfNecessaryAndThenLeave(humanoid) + if not humanoid:isLeaving() then + local leave = self:createLeaveAction():setMustHappen(true) + + if not string.find(humanoid.humanoid_class, "Stripped") then + humanoid:setNextAction(leave) + return + end + + local screen, sx, sy = self.world:findObjectNear(humanoid, "screen") + local use_screen = UseScreenAction(screen):setMustHappen(true):setIsLeaving(true) + + --Make old saved game action queues compatible with the changes made by the #293 fix commit: + for actions_index, action in ipairs(humanoid.action_queue) do + if action.name == "use screen" or (action.name == "walk" and action.x == sx and action.y == sy) then + if not action.is_leaving then + humanoid.humanoid_actions[actions_index].is_leaving = true + end + if action.name == "walk" and action.must_happen then + action.must_happen = false + end + end + end + + if humanoid:getCurrentAction().name == "use_screen" then + --The humanoid must be using the screen to undress because this isn't a leaving action: + humanoid:getCurrentAction().after_use = nil + humanoid:setNextAction(use_screen) + else + humanoid:setNextAction(WalkAction(sx, sy):setMustHappen(true):disableTruncate():setIsLeaving(true)) + humanoid:queueAction(use_screen) + end + + humanoid:queueAction(leave) + end +end + +--! Deactivate the room from the world. function Room:deactivate() self.is_active = false -- So that no more patients go to it. self.world:notifyRoomRemoved(self) - for humanoid, callback in pairs(self.humanoids_enroute) do - callback.callback(); + for _, callback in pairs(self.humanoids_enroute) do + callback.callback() end -- Now empty the humanoids_enroute list since they are not enroute anymore. self.humanoids_enroute = {} + + self.hospital:removeRatholesAroundRoom(self) end function Room:tryToEdit() @@ -805,17 +916,17 @@ local i = 0 -- Tell all humanoids that they should leave -- If someone is entering the room right now they are also counted. - if self.door.user and self.door.user.action_queue[1].is_entering then + if self.door.user and self.door.user:getCurrentAction().is_entering then i = 1 end for humanoid, _ in pairs(self.humanoids) do if not humanoid:isLeaving() then if class.is(humanoid, Patient) then self:makeHumanoidLeave(humanoid) - humanoid:queueAction({name = "seek_room", room_type = self.room_info.id}) + humanoid:queueAction(SeekRoomAction(self.room_info.id)) else humanoid:setNextAction(self:createLeaveAction()) - humanoid:queueAction({name = "meander"}) + humanoid:queueAction(MeanderAction()) end end i = i + 1 @@ -839,3 +950,43 @@ end end +--[[ Is the room one of the diagnosis rooms for the patient? +-- This used for epidemics when the disease and therefore the diagnosis +-- rooms of a patient may change. +-- @param patient (Patient) patient to verify if treatment room ]] +-- @return result (boolean) true if is suitable diagnosis room, false otherwise +function Room:isDiagnosisRoomForPatient(patient) + if self.room_info.id ~= "gp" then + for _, room_name in ipairs(patient.disease.diagnosis_rooms) do + if self.room_info.id == room_name then + return true + end + end + return false + else + return true + end +end + +--! Get the average service quality of the staff members in the room. +--!return (float) [0-1] Average staff service quality. +function Room:getStaffServiceQuality() + local quality = 0.5 + + if self.staff_member_set then + -- For rooms with multiple staff member (like operating theatre) + quality = 0 + local count = 0 + for member, _ in pairs(self.staff_member_set) do + quality = quality + member:getServiceQuality() + count = count + 1 + end + + quality = quality / count + elseif self.staff_member then + -- For rooms with one staff member + quality = self.staff_member:getServiceQuality() + end + + return quality +end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/blood_machine_room.lua corsix-th-0.62/CorsixTH/Lua/rooms/blood_machine_room.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/blood_machine_room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/blood_machine_room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -43,6 +43,9 @@ class "BloodMachineRoom" (Room) +---@type BloodMachineRoom +local BloodMachineRoom = _G["BloodMachineRoom"] + function BloodMachineRoom:BloodMachineRoom(...) self:Room(...) end @@ -50,31 +53,27 @@ function BloodMachineRoom:commandEnteringPatient(patient) local staff = self.staff_member local machine, stf_x, stf_y = self.world:findObjectNear(patient, "blood_machine") - local orientation = machine.object_type.orientations[machine.direction] local pat_x, pat_y = machine:getSecondaryUsageTile() - staff:setNextAction{name = "walk", x = stf_x, y = stf_y} - patient:setNextAction{name = "walk", x = pat_x, y = pat_y} - patient:queueAction{name = "idle", direction = machine.direction == "north" and "west" or "north"} + staff:setNextAction(WalkAction(stf_x, stf_y)) + patient:setNextAction(WalkAction(pat_x, pat_y)) + patient:queueAction(IdleAction():setDirection(machine.direction == "north" and "west" or "north")) + local length = math.random(2, 4) - local action - staff:queueAction{ - name = "multi_use_object", - object = machine, - use_with = patient, - prolonged_usage = true, - invisible_phase_span = {-3, 3}, - loop_callback = --[[persistable:blood_machine_loop_callback]] function(action) - if length <= 0 then - action.prolonged_usage = false - end - length = length - 1 - end, - after_use = --[[persistable:blood_machine_after_use]] function() - staff:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } + local loop_callback = --[[persistable:blood_machine_loop_callback]] function(action) + if length <= 0 then + action.prolonged_usage = false + end + length = length - 1 + end + + local after_use = --[[persistable:blood_machine_after_use]] function() + staff:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + + staff:queueAction(MultiUseObjectAction(machine, patient):setProlongedUsage(true) + :setInvisiblePhaseSpan({-3, 3}):setLoopCallback(loop_callback):setAfterUse(after_use)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/cardiogram.lua corsix-th-0.62/CorsixTH/Lua/rooms/cardiogram.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/cardiogram.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/cardiogram.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -43,6 +43,9 @@ class "CardiogramRoom" (Room) +---@type CardiogramRoom +local CardiogramRoom = _G["CardiogramRoom"] + function CardiogramRoom:CardiogramRoom(...) self:Room(...) end @@ -50,85 +53,65 @@ function CardiogramRoom:commandEnteringPatient(patient) local screen, sx, sy = self.world:findObjectNear(patient, "screen") patient:walkTo(sx, sy) - patient:queueAction{ - name = "use_screen", - object = screen, - after_use = --[[persistable:cardiogram_screen_after_use1]] function() - local staff = self.staff_member - if not staff or patient.going_home then - -- If, by some fluke, the staff member left the room while the - -- patient used the screen, then the patient should get changed - -- again (they will already have been instructed to leave by the - -- staff leaving). - patient:queueAction({ - name = "use_screen", - object = screen, - must_happen = true, - }, 1) + + local screen_after_use = --[[persistable:cardiogram_screen_after_use1]] function() + local staff = self.staff_member + local cardio, cx, cy = self.world:findObjectNear(patient, "cardio") + staff:walkTo(cardio:getSecondaryUsageTile()) + local staff_idle = IdleAction() + staff:queueAction(staff_idle) + patient:walkTo(cx, cy) + + local timer = 6 + local phase = -2 + local cardio_loop_callback = --[[persistable:cardiogram_cardio_loop_callback]] function(action) + if not action.on_interrupt then + action.prolonged_usage = false + patient.num_animation_ticks = 1 return end - local cardio, cx, cy = self.world:findObjectNear(patient, "cardio") - staff:walkTo(cardio:getSecondaryUsageTile()) - local staff_idle = {name = "idle"} - staff:queueAction(staff_idle) - patient:walkTo(cx, cy) - local timer = 6 - local phase = -2 - patient:queueAction{ - name = "multi_use_object", - object = cardio, - use_with = staff, - must_happen = true, -- set so that the second use_screen always happens - prolonged_usage = true, - loop_callback = --[[persistable:cardiogram_cardio_loop_callback]] function(action) - if not action.on_interrupt then - action.prolonged_usage = false - patient.num_animation_ticks = 1 - return - end - timer = timer - 1 - if timer == 0 then - phase = phase + 1 - if phase == 3 then - action.prolonged_usage = false - else - patient.num_animation_ticks = 3 - math.abs(phase) - end - timer = 6 - else - action.secondary_anim = 1030 - end - end, - after_use = --[[persistable:cardiogram_cardio_after_use]] function() - if #staff.action_queue == 1 then - staff:setNextAction{name = "meander"} - else - staff:finishAction(staff_idle) - end - end, - } - patient:queueAction{ - name = "walk", - x = sx, - y = sy, - must_happen = true, - no_truncate = true, - } - patient:queueAction{ - name = "use_screen", - object = screen, - must_happen = true, - after_use = --[[persistable:cardiogram_screen_after_use2]] function() - if #patient.action_queue == 1 then - self:dealtWithPatient(patient) - end - end, - } - end, - } + timer = timer - 1 + if timer == 0 then + phase = phase + 1 + if phase == 3 then + action.prolonged_usage = false + else + patient.num_animation_ticks = 3 - math.abs(phase) + end + timer = 6 + else + action.secondary_anim = 1030 + end + end + + local cardio_after_use = --[[persistable:cardiogram_cardio_after_use]] function() + if #staff.action_queue == 1 then + staff:setNextAction(MeanderAction()) + else + staff:finishAction(staff_idle) + end + end + + patient:queueAction(MultiUseObjectAction(cardio, staff):setMustHappen(false) + :setProlongedUsage(true):setLoopCallback(cardio_loop_callback):setAfterUse(cardio_after_use)) + patient:queueAction(WalkAction(sx, sy):setIsLeaving(true):setMustHappen(false):disableTruncate()) + + local leaving_after_use = --[[persistable:cardiogram_screen_after_use2]] function() + if #patient.action_queue == 1 then + self:dealtWithPatient(patient) + end + end + patient:queueAction(UseScreenAction(screen):setIsLeaving(true):setMustHappen(true):setAfterUse(leaving_after_use)) + end + + patient:queueAction(UseScreenAction(screen):setAfterUse(screen_after_use)) return Room.commandEnteringPatient(self, patient) end +function CardiogramRoom:makeHumanoidLeave(humanoid) + self:makeHumanoidDressIfNecessaryAndThenLeave(humanoid) +end + function CardiogramRoom:onHumanoidLeave(humanoid) if self.staff_member == humanoid then self.staff_member = nil @@ -136,4 +119,8 @@ Room.onHumanoidLeave(self, humanoid) end +function CardiogramRoom:shouldHavePatientReenter(patient) + return not patient:isLeaving() +end + return room diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/decontamination.lua corsix-th-0.62/CorsixTH/Lua/rooms/decontamination.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/decontamination.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/decontamination.lua 2018-07-21 11:13:17.000000000 +0000 @@ -43,13 +43,16 @@ class "DecontaminationRoom" (Room) +---@type DecontaminationRoom +local DecontaminationRoom = _G["DecontaminationRoom"] + function DecontaminationRoom:DecontaminationRoom(...) self:Room(...) end function DecontaminationRoom:commandEnteringStaff(staff) self.staff_member = staff - staff:setNextAction{name = "meander"} + staff:setNextAction(MeanderAction()) return Room.commandEnteringStaff(self, staff) end @@ -59,31 +62,26 @@ local console, stf_x, stf_y = self.world:findObjectNear(staff, "console") local --[[persistable:decontamination_shared_loop_callback]] function loop_callback() - if staff.action_queue[1].shower_ready and patient.action_queue[1].shower_ready then + if staff:getCurrentAction().shower_ready and patient:getCurrentAction().shower_ready then staff:finishAction() patient:finishAction() end end staff:walkTo(stf_x, stf_y) - staff:queueAction{ - name = "idle", - direction = console.direction == "north" and "west" or "north", - loop_callback = loop_callback, - shower_ready = true, - } - staff:queueAction{ - name = "use_object", - object = console, - } + + local idle_action = IdleAction():setDirection(console.direction == "north" and "west" or "north") + :setLoopCallback(loop_callback) + idle_action.shower_ready = true + staff:queueAction(idle_action) + staff:queueAction(UseObjectAction(console)) patient:walkTo(pat_x, pat_y) - patient:queueAction{ - name = "idle", - direction = shower.direction == "north" and "north" or "west", - loop_callback = loop_callback, - shower_ready = true, - } + + idle_action = IdleAction():setDirection(shower.direction == "north" and "north" or "west") + :setLoopCallback(loop_callback) + idle_action.shower_ready = true + patient:queueAction(idle_action) local prolonged = true local length = math.random() * 3 - staff.profile.skill @@ -92,26 +90,26 @@ else length = length - 1 end - patient:queueAction{ - name = "use_object", - object = shower, - prolonged_usage = prolonged, - loop_callback = --[[persistable:shower_loop_callback]] function(action) - length = length - 1 - if length <= 0 then - action.prolonged_usage = false - end - end, - after_use = --[[persistable:shower_after_use]] function() - if not self.staff_member then - return - end - self.staff_member:setNextAction{name = "meander"} - if not patient.going_home then - self:dealtWithPatient(patient) - end - end, - } + + local shower_loop_callback = --[[persistable:shower_loop_callback]] function(action) + length = length - 1 + if length <= 0 then + action.prolonged_usage = false + end + end + + local shower_after_use = --[[persistable:shower_after_use]] function() + if not self.staff_member then + return + end + self.staff_member:setNextAction(MeanderAction()) + if not patient.going_home then + self:dealtWithPatient(patient) + end + end + + patient:queueAction(UseObjectAction(shower):setProlongedUsage(prolonged) + :setLoopCallback(shower_loop_callback):setAfterUse(shower_after_use)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/dna_fixer.lua corsix-th-0.62/CorsixTH/Lua/rooms/dna_fixer.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/dna_fixer.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/dna_fixer.lua 2018-07-21 11:13:17.000000000 +0000 @@ -44,6 +44,9 @@ class "DNAFixerRoom" (Room) +---@type DNAFixerRoom +local DNAFixerRoom = _G["DNAFixerRoom"] + function DNAFixerRoom:DNAFixerRoom(...) self:Room(...) end @@ -55,39 +58,29 @@ local --[[persistable:dna_fixer_shared_loop_callback]] function loop_callback() -- If the other humanoid has already started to idle we move on - if staff.action_queue[1].name == "idle" and patient.action_queue[1].name == "idle" then + if staff:getCurrentAction().name == "idle" and patient:getCurrentAction().name == "idle" then -- We need to change to another type before starting, to be able -- to have different animations depending on gender. patient:setType(patient.change_into) - patient:setNextAction{ - name = "use_object", - object = dna_fixer, - prolonged_usage = false, - after_use = --[[persistable:dna_fixer_after_use]] function() - self:dealtWithPatient(patient) - staff:setNextAction{name = "meander"} - end, - } - - staff:setNextAction{ - name = "use_object", - object = console, - } + + local fixer_after_use = --[[persistable:dna_fixer_after_use]] function() + self:dealtWithPatient(patient) + staff:setNextAction(MeanderAction()) + end + + patient:setNextAction(UseObjectAction(dna_fixer):setProlongedUsage(false) + :setAfterUse(fixer_after_use)) + staff:setNextAction(UseObjectAction(console)) end end -- As soon as one starts to idle the callback is called to see if the other one is already idling. patient:walkTo(pat_x, pat_y) - patient:queueAction{ - name = "idle", - direction = dna_fixer.direction == "north" and "north" or "west", - loop_callback = loop_callback, - } + patient:queueAction(IdleAction():setDirection(dna_fixer.direction == "north" and "north" or "west") + :setLoopCallback(loop_callback)) + staff:walkTo(stf_x, stf_y) - staff:queueAction{ - name = "idle", - direction = console.direction == "north" and "north" or "west", - loop_callback = loop_callback, - } + staff:queueAction(IdleAction():setDirection(console.direction == "north" and "north" or "west") + :setLoopCallback(loop_callback)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/electrolysis.lua corsix-th-0.62/CorsixTH/Lua/rooms/electrolysis.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/electrolysis.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/electrolysis.lua 2018-07-21 11:13:17.000000000 +0000 @@ -43,6 +43,9 @@ class "ElectrolysisRoom" (Room) +---@type ElectrolysisRoom +local ElectrolysisRoom = _G["ElectrolysisRoom"] + function ElectrolysisRoom:ElectrolysisRoom(...) self:Room(...) end @@ -54,7 +57,7 @@ local --[[persistable:electrolysis_shared_loop_callback]] function loop_callback() -- If the other humanoid has already started to idle we move on - if staff.action_queue[1].name == "idle" and patient.action_queue[1].name == "idle" then + if staff:getCurrentAction().name == "idle" and patient:getCurrentAction().name == "idle" then -- Skilled doctors require less electrocutions local num_electrocutions = math.random(1, 5) * (2 - staff.profile.skill) -- We need to change to another type before starting, to be able @@ -67,47 +70,40 @@ patient:setLayer(1, math.random(0, 3) * 2) patient:setLayer(2, 0) end - patient:setNextAction{ - name = "use_object", - object = electrolyser, - loop_callback = --[[persistable:electrolysis_loop_callback]] function(action) - num_electrocutions = num_electrocutions - 1 - if num_electrocutions <= 0 then - -- Tired doctors can continue electrocuting for a bit too long... - -- Fatigue 0.00 - normal number of electrocutions - -- Fatigue 0.45 - normal number of electrocutions - -- Fatigue 0.80 - expect 1 extra electrocution - -- Fatigue 1.00 - expect 9 extra electrocutions - if math.random() <= 0.1 + 2 * (1 - staff.attributes["fatigue"]) then - action.prolonged_usage = false - end + + local loop_callback_electrolysis = --[[persistable:electrolysis_loop_callback]] function(action) + num_electrocutions = num_electrocutions - 1 + if num_electrocutions <= 0 then + -- Tired doctors can continue electrocuting for a bit too long... + -- Fatigue 0.00 - normal number of electrocutions + -- Fatigue 0.45 - normal number of electrocutions + -- Fatigue 0.80 - expect 1 extra electrocution + -- Fatigue 1.00 - expect 9 extra electrocutions + if math.random() <= 0.1 + 2 * (1 - staff.attributes["fatigue"]) then + action.prolonged_usage = false end - end, - after_use = --[[persistable:electrolysis_after_use]] function() - self:dealtWithPatient(patient) - staff:setNextAction{name = "meander"} - end, - } - - staff:setNextAction{ - name = "use_object", - object = console, - } + end + end + + local after_electrolysis = --[[persistable:electrolysis_after_use]] function() + self:dealtWithPatient(patient) + staff:setNextAction(MeanderAction()) + end + + patient:setNextAction(UseObjectAction(electrolyser):setLoopCallback(loop_callback_electrolysis) + :setAfterUse(after_electrolysis)) + + staff:setNextAction(UseObjectAction(console)) end end -- As soon as one starts to idle the callback is called to see if the other one is already idling. patient:walkTo(pat_x, pat_y) - patient:queueAction{ - name = "idle", - direction = electrolyser.direction == "north" and "east" or "south", - loop_callback = loop_callback, - } + patient:queueAction(IdleAction():setDirection(electrolyser.direction == "north" and "east" or "south") + :setLoopCallback(loop_callback)) + staff:walkTo(stf_x, stf_y) - staff:queueAction{ - name = "idle", - direction = console.direction == "north" and "east" or "south", - loop_callback = loop_callback, - } + staff:queueAction(IdleAction():setDirection(console.direction == "north" and "east" or "south") + :setLoopCallback(loop_callback)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/fracture_clinic.lua corsix-th-0.62/CorsixTH/Lua/rooms/fracture_clinic.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/fracture_clinic.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/fracture_clinic.lua 2018-07-21 11:13:17.000000000 +0000 @@ -43,6 +43,9 @@ class "FractureRoom" (Room) +---@type FractureRoom +local FractureRoom = _G["FractureRoom"] + function FractureRoom:FractureRoom(...) self:Room(...) end @@ -50,25 +53,22 @@ function FractureRoom:commandEnteringPatient(patient) local staff = self.staff_member local cast, pat_x, pat_y = self.world:findObjectNear(patient, "cast_remover") - local orientation = cast.object_type.orientations[cast.direction] local stf_x, stf_y = cast:getSecondaryUsageTile() staff:walkTo(stf_x, stf_y) - staff:queueAction{name = "idle", direction = cast.direction == "north" and "west" or "north"} + staff:queueAction(IdleAction():setDirection(cast.direction == "north" and "west" or "north")) + patient:walkTo(pat_x, pat_y) - patient:queueAction{ - name = "multi_use_object", - object = cast, - use_with = staff, - after_use = --[[persistable:fracture_clinic_after_use]] function() - patient:setLayer(2, 0) -- Remove casts - patient:setLayer(3, 0) - patient:setLayer(4, 0) - staff:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } + local after_fracture = --[[persistable:fracture_clinic_after_use]] function() + patient:setLayer(2, 0) -- Remove casts + patient:setLayer(3, 0) + patient:setLayer(4, 0) + staff:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + + patient:queueAction(MultiUseObjectAction(cast, staff):setAfterUse(after_fracture)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/general_diag.lua corsix-th-0.62/CorsixTH/Lua/rooms/general_diag.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/general_diag.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/general_diag.lua 2018-07-21 11:13:17.000000000 +0000 @@ -42,6 +42,9 @@ class "GeneralDiagRoom" (Room) +---@type GeneralDiagRoom +local GeneralDiagRoom = _G["GeneralDiagRoom"] + function GeneralDiagRoom:GeneralDiagRoom(...) self:Room(...) end @@ -49,61 +52,38 @@ function GeneralDiagRoom:commandEnteringPatient(patient) local screen, sx, sy = self.world:findObjectNear(patient, "screen") patient:walkTo(sx, sy) - patient:queueAction{ - name = "use_screen", - object = screen, - after_use = --[[persistable:general_diag_screen_after_use1]] function() - local staff = self.staff_member - if not staff or patient.going_home then - -- If, by some fluke, the staff member left the room while the - -- patient used the screen, then the patient should get changed - -- again (they will already have been instructed to leave by the - -- staff leaving). - patient:queueAction({ - name = "use_screen", - object = screen, - must_happen = true, - }, 1) - return + + local after_use_screen1 = --[[persistable:general_diag_screen_after_use1]] function() + local staff = self.staff_member + local trolley, cx, cy = self.world:findObjectNear(patient, "crash_trolley") + staff:walkTo(trolley:getSecondaryUsageTile()) + local staff_idle = IdleAction() + staff:queueAction(staff_idle) + patient:walkTo(cx, cy, true) + + local after_use_trolley = --[[persistable:general_diag_trolley_after_use]] function() + if #staff.action_queue == 1 then + staff:setNextAction(MeanderAction()) + else + staff:finishAction(staff_idle) end - local trolley, cx, cy = self.world:findObjectNear(patient, "crash_trolley") - staff:walkTo(trolley:getSecondaryUsageTile()) - local staff_idle = {name = "idle"} - staff:queueAction(staff_idle) - patient:walkTo(cx, cy, true) - patient:queueAction{ - name = "multi_use_object", - object = trolley, - use_with = staff, - must_happen = true, -- set so that the second use_screen always happens - prolonged_usage = false, - after_use = --[[persistable:general_diag_trolley_after_use]] function() - if #staff.action_queue == 1 then - staff:setNextAction{name = "meander"} - else - staff:finishAction(staff_idle) - end - end, - } - patient:queueAction{ - name = "walk", - x = sx, - y = sy, - must_happen = true, - no_truncate = true, - } - patient:queueAction{ - name = "use_screen", - object = screen, - must_happen = true, - after_use = --[[persistable:general_diag_screen_after_use2]] function() - if #patient.action_queue == 1 then - self:dealtWithPatient(patient) - end - end, - } - end, - } + end + + patient:queueAction(MultiUseObjectAction(trolley, staff):setMustHappen(false) + :setProlongedUsage(false):setAfterUse(after_use_trolley)) + patient:queueAction(WalkAction(sx, sy):setIsLeaving(true):setMustHappen(false):disableTruncate()) + + local after_use_screen2 = --[[persistable:general_diag_screen_after_use2]] function() + if #patient.action_queue == 1 then + self:dealtWithPatient(patient) + end + end + + patient:queueAction(UseScreenAction(screen):setIsLeaving(true):setMustHappen(true) + :setAfterUse(after_use_screen2)) + end + + patient:queueAction(UseScreenAction(screen):setAfterUse(after_use_screen1)) return Room.commandEnteringPatient(self, patient) end @@ -114,4 +94,12 @@ Room.onHumanoidLeave(self, humanoid) end +function GeneralDiagRoom:makeHumanoidLeave(humanoid) + self:makeHumanoidDressIfNecessaryAndThenLeave(humanoid) +end + +function GeneralDiagRoom:shouldHavePatientReenter(patient) + return not patient:isLeaving() +end + return room diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/gp.lua corsix-th-0.62/CorsixTH/Lua/rooms/gp.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/gp.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/gp.lua 2018-07-21 11:13:17.000000000 +0000 @@ -42,6 +42,9 @@ class "GPRoom" (Room) +---@type GPRoom +local GPRoom = _G["GPRoom"] + function GPRoom:GPRoom(...) self:Room(...) end @@ -49,40 +52,42 @@ function GPRoom:doStaffUseCycle(humanoid) local obj, ox, oy = self.world:findObjectNear(humanoid, "cabinet") humanoid:walkTo(ox, oy) - humanoid:queueAction{name = "use_object", object = obj} + humanoid:queueAction(UseObjectAction(obj)) + obj, ox, oy = self.world:findObjectNear(humanoid, "desk") - humanoid:queueAction{name = "walk", x = ox, y = oy} + humanoid:queueAction(WalkAction(ox, oy)) + -- A skilled doctor requires less time at the desk to diagnose the patient local inv_skill = 1 - humanoid.profile.skill local desk_use_time = math.random(math.floor(3 + 5 * inv_skill), math.ceil (8 + 10 * inv_skill)) - humanoid:queueAction{name = "use_object", - object = obj, - loop_callback = --[[persistable:gp_loop_callback]] function() - desk_use_time = desk_use_time - 1 - if desk_use_time == 0 then - -- Consultants who aren't tired might not need to stretch their legs - -- to remain alert, so might just remain at the desk and deal with the - -- next patient quicker. - if humanoid.profile.is_consultant - and math.random() >= humanoid.attributes.fatigue then - desk_use_time = math.random(7, 14) - else - self:doStaffUseCycle(humanoid) - end - local patient = self:getPatient() - if patient then - if math.random() <= (0.7 + 0.3 * humanoid.profile.skill) or self.max_times <= 0 then - if patient.user_of and not class.is(patient.user_of, Door) then - self:dealtWithPatient(patient) - end - else - self.max_times = self.max_times - 1 + local gp_loop_callback = --[[persistable:gp_loop_callback]] function() + desk_use_time = desk_use_time - 1 + if desk_use_time == 0 then + -- Consultants who aren't tired might not need to stretch their legs + -- to remain alert, so might just remain at the desk and deal with the + -- next patient quicker. + if humanoid.profile.is_consultant and + math.random() >= humanoid.attributes.fatigue then + desk_use_time = math.random(7, 14) + else + self:doStaffUseCycle(humanoid) + end + + local patient = self:getPatient() + if patient then + if math.random() <= (0.7 + 0.3 * humanoid.profile.skill) or self.max_times <= 0 then + if patient.user_of and not class.is(patient.user_of, Door) then + self:dealtWithPatient(patient) end + else + self.max_times = self.max_times - 1 end end - end, - } + end + end + + humanoid:queueAction(UseObjectAction(obj):setLoopCallback(gp_loop_callback)) end function GPRoom:commandEnteringStaff(humanoid) @@ -94,7 +99,7 @@ function GPRoom:commandEnteringPatient(humanoid) local obj, ox, oy = self.world:findObjectNear(humanoid, "chair") humanoid:walkTo(ox, oy) - humanoid:queueAction{name = "use_object", object = obj} + humanoid:queueAction(UseObjectAction(obj)) self.max_times = 3 return Room.commandEnteringPatient(self, humanoid) end @@ -120,36 +125,33 @@ patient:setNextAction(self:createLeaveAction()) patient:addToTreatmentHistory(self.room_info) - if patient.disease and not patient.diagnosed then + -- If the patient got sent to the wrong room and needs telling where + -- to go next - this happens when a disease changes for an epidemic + if patient.needs_redirecting then + self:sendPatientToNextDiagnosisRoom(patient) + patient.needs_redirecting = false + elseif patient.disease and not patient.diagnosed then self.hospital:receiveMoneyForTreatment(patient) - patient:completeDiagnosticStep(self) if patient.diagnosis_progress >= self.hospital.policies["stop_procedure"] then - patient:setDiagnosed(true) - patient:queueAction{name = "seek_room", room_type = patient.disease.treatment_rooms[1], treatment_room = true} + patient:setDiagnosed() + if patient:agreesToPay(patient.disease.id) then + patient:queueAction(SeekRoomAction(patient.disease.treatment_rooms[1]):enableTreatmentRoom()) + else + patient:goHome("over_priced", patient.disease.id) + end self.staff_member:setMood("idea3", "activate") -- Show the light bulb over the doctor -- Check if this disease has just been discovered if not self.hospital.disease_casebook[patient.disease.id].discovered then self.hospital.research:discoverDisease(patient.disease) end - elseif #patient.available_diagnosis_rooms == 0 then - -- The very rare case where the patient has visited all his/her possible diagnosis rooms - -- There's not much to do then... Send home - patient:goHome() - patient:updateDynamicInfo(_S.dynamic_info.patient.actions.no_diagnoses_available) else - self.staff_member:setMood("reflexion", "activate") -- Show the uncertainty mood over the doctor - local next_room = math.random(1, #patient.available_diagnosis_rooms) - patient:queueAction{ - name = "seek_room", - room_type = patient.available_diagnosis_rooms[next_room], - diagnosis_room = next_room, - } + self:sendPatientToNextDiagnosisRoom(patient) end else - patient:queueAction{name = "meander", count = 2} - patient:queueAction{name = "idle"} + patient:queueAction(MeanderAction():setCount(2)) + patient:queueAction(IdleAction()) end if self.dealt_patient_callback then @@ -162,11 +164,31 @@ self:findWorkForStaff() end +function GPRoom:sendPatientToNextDiagnosisRoom(patient) + if #patient.available_diagnosis_rooms == 0 then + -- The very rare case where the patient has visited all his/her possible diagnosis rooms + -- There's not much to do then... Send home + patient:goHome("kicked") + patient:updateDynamicInfo(_S.dynamic_info.patient.actions.no_diagnoses_available) + else + self.staff_member:setMood("reflexion", "activate") -- Show the uncertainty mood over the doctor + local next_room_id = math.random(1, #patient.available_diagnosis_rooms) + local next_room = patient.available_diagnosis_rooms[next_room_id] + if patient:agreesToPay("diag_" .. next_room) then + patient:queueAction(SeekRoomAction(next_room):setDiagnosisRoom(next_room_id)) + else + patient:goHome("over_priced", "diag_" .. next_room) + end + end +end + function GPRoom:onHumanoidLeave(humanoid) -- Reset moods when either the patient or the doctor leaves the room. - if self.staff_member then - self.staff_member:setMood("idea3", "deactivate") - self.staff_member:setMood("reflexion", "deactivate") + if humanoid.humanoid_class ~= "Handyman" then + for staff, _ in pairs(self.humanoids) do + staff:setMood("idea3", "deactivate") + staff:setMood("reflexion", "deactivate") + end end if self.staff_member == humanoid then self.staff_member = nil @@ -178,8 +200,8 @@ end function GPRoom:roomFinished() - if not self.hospital:hasStaffOfCategory("Doctor") - and not self.world.ui.start_tutorial then + if not self.hospital:hasStaffOfCategory("Doctor") and + not self.world.ui.start_tutorial then self.world.ui.adviser:say(_A.room_requirements.gps_office_need_doctor) end return Room.roomFinished(self) diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/hair_restoration.lua corsix-th-0.62/CorsixTH/Lua/rooms/hair_restoration.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/hair_restoration.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/hair_restoration.lua 2018-07-21 11:13:17.000000000 +0000 @@ -43,6 +43,9 @@ class "HairRestorationRoom" (Room) +---@type HairRestorationRoom +local HairRestorationRoom = _G["HairRestorationRoom"] + function HairRestorationRoom:HairRestorationRoom(...) self:Room(...) end @@ -53,38 +56,31 @@ local console, stf_x, stf_y = self.world:findObjectNear(staff, "console") local --[[persistable:hair_restoration_shared_loop_callback]] function loop_callback() - if staff.action_queue[1].name == "idle" and patient.action_queue[1].name == "idle" then - patient:setNextAction{ - name = "use_object", - object = hair_restorer, - loop_callback = --[[persistable:hair_restoration_loop_callback]] function(action) - action.prolonged_usage = false - end, - after_use = --[[persistable:hair_restoration_after_use]] function() - patient:setLayer(0, patient.layers[0] + 2) -- Change to normal hair - staff:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } - staff:setNextAction{ - name = "use_object", - object = console, - } + if staff:getCurrentAction().name == "idle" and patient:getCurrentAction().name == "idle" then + local loop_callback_restore = --[[persistable:hair_restoration_loop_callback]] function(action) + action.prolonged_usage = false + end + + local after_use_restore = --[[persistable:hair_restoration_after_use]] function() + patient:setLayer(0, patient.layers[0] + 2) -- Change to normal hair + staff:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + + patient:setNextAction(UseObjectAction(hair_restorer) + :setLoopCallback(loop_callback_restore):setAfterUse(after_use_restore)) + + staff:setNextAction(UseObjectAction(console)) end end patient:walkTo(pat_x, pat_y) - patient:queueAction{ - name = "idle", - direction = hair_restorer.direction == "north" and "east" or "south", - loop_callback = loop_callback, - } + patient:queueAction(IdleAction():setDirection(hair_restorer.direction == "north" and "east" or "south") + :setLoopCallback(loop_callback)) + staff:walkTo(stf_x, stf_y) - staff:queueAction{ - name = "idle", - direction = console.direction == "north" and "east" or "south", - loop_callback = loop_callback, - } + staff:queueAction(IdleAction():setDirection(console.direction == "north" and "east" or "south") + :setLoopCallback(loop_callback)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/inflation.lua corsix-th-0.62/CorsixTH/Lua/rooms/inflation.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/inflation.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/inflation.lua 2018-07-21 11:13:17.000000000 +0000 @@ -43,6 +43,9 @@ class "InflationRoom" (Room) +---@type InflationRoom +local InflationRoom = _G["InflationRoom"] + function InflationRoom:InflationRoom(...) self:Room(...) end @@ -50,22 +53,20 @@ function InflationRoom:commandEnteringPatient(patient) local staff = self.staff_member local inflator, pat_x, pat_y = self.world:findObjectNear(patient, "inflator") - local orientation = inflator.object_type.orientations[inflator.direction] local stf_x, stf_y = inflator:getSecondaryUsageTile() - staff:setNextAction{name = "walk", x = stf_x, y = stf_y} - staff:queueAction{name = "idle", direction = inflator.direction == "north" and "east" or "south"} - patient:setNextAction{name = "walk", x = pat_x, y = pat_y} - patient:queueAction{ - name = "multi_use_object", - object = inflator, - use_with = staff, - after_use = --[[persistable:inflation_after_use]] function() - patient:setLayer(0, patient.layers[0] - 10) -- Change to normal head - staff:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } + staff:setNextAction(WalkAction(stf_x, stf_y)) + staff:queueAction(IdleAction():setDirection(inflator.direction == "north" and "east" or "south")) + + patient:setNextAction(WalkAction(pat_x, pat_y)) + + local inflation_after_use = --[[persistable:inflation_after_use]] function() + patient:setLayer(0, patient.layers[0] - 10) -- Change to normal head + staff:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + + patient:queueAction(MultiUseObjectAction(inflator, staff):setAfterUse(inflation_after_use)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/jelly_vat.lua corsix-th-0.62/CorsixTH/Lua/rooms/jelly_vat.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/jelly_vat.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/jelly_vat.lua 2018-07-21 11:13:17.000000000 +0000 @@ -43,6 +43,9 @@ class "JellyVatRoom" (Room) +---@type JellyVatRoom +local JellyVatRoom = _G["JellyVatRoom"] + function JellyVatRoom:JellyVatRoom(...) self:Room(...) end @@ -50,22 +53,20 @@ function JellyVatRoom:commandEnteringPatient(patient) local staff = self.staff_member local moulder, stf_x, stf_y = self.world:findObjectNear(patient, "jelly_moulder") - local orientation = moulder.object_type.orientations[moulder.direction] local pat_x, pat_y = moulder:getSecondaryUsageTile() - staff:setNextAction{name = "walk", x = stf_x, y = stf_y} - staff:queueAction{ - name = "multi_use_object", - object = moulder, - use_with = patient, - invisible_phase_span = {-3, 4}, - after_use = --[[persistable:jelly_vat_after_use]] function() - staff:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } - patient:setNextAction{name = "walk", x = pat_x, y = pat_y} - patient:queueAction{name = "idle", direction = moulder.direction == "north" and "west" or "north"} + staff:setNextAction(WalkAction(stf_x, stf_y)) + + local jellyvat_after_use = --[[persistable:jelly_vat_after_use]] function() + staff:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + + staff:queueAction(MultiUseObjectAction(moulder, patient):setInvisiblePhaseSpan({-3, 4}) + :setAfterUse(jellyvat_after_use)) + + patient:setNextAction(WalkAction(pat_x, pat_y)) + patient:queueAction(IdleAction():setDirection(moulder.direction == "north" and "west" or "north")) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/operating_theatre.lua corsix-th-0.62/CorsixTH/Lua/rooms/operating_theatre.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/operating_theatre.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/operating_theatre.lua 2018-07-21 11:13:17.000000000 +0000 @@ -49,6 +49,9 @@ class "OperatingTheatreRoom" (Room) +---@type OperatingTheatreRoom +local OperatingTheatreRoom = _G["OperatingTheatreRoom"] + function OperatingTheatreRoom:OperatingTheatreRoom(...) self:Room(...) self.staff_member_set = {} @@ -77,54 +80,88 @@ end local function wait_for_object(humanoid, obj, must_happen) - return { - name = "idle", - must_happen = must_happen, - loop_callback = --[[persistable:operatring_theatre_wait]] function(action) - if action.todo_interrupt or not obj.user then - humanoid:finishAction(action) - else - humanoid:queueAction({ - name = "idle", - count = 5, - must_happen = must_happen, - }, 0) - end - end, - } + assert(type(must_happen) == "boolean", "must happen must be true or false") + + local loop_callback_wait = --[[persistable:operatring_theatre_wait]] function(action) + if action.todo_interrupt or not obj.user then + humanoid:finishAction(action) + else + humanoid:queueAction(IdleAction():setCount(5):setMustHappen(true), 0) + end + end + + return IdleAction():setMustHappen(must_happen):setLoopCallback(loop_callback_wait) end -function OperatingTheatreRoom:commandEnteringStaff(staff) - self.staff_member_set[staff] = true +--! Returns true if an operation is ongoing +function OperatingTheatreRoom:isOperating() + for k, _ in pairs(self.staff_member_set) do + if k:getCurrentAction().name == "multi_use_object" then + return true + end + end + + return false +end +--! Builds the second operation action (i.e. with the surgeon whose we +--! see the back). Called either when the operation starts or when the +--! operation is resumed after interruption caused by the picking up of +--! the second surgeon. +--! Note: Must be part of OperatingTheatreRoom and not a local function +--! because of the use in the persisted callback function operation_standby. +--!param multi_use (action): the first operation action (built with via buildTableAction1()). +--!param operation_table_b (OperatingTable): slave object representing the operation table. +function OperatingTheatreRoom._buildTableAction2(multi_use, operation_table_b) + local num_loops = math.random(2, 5) + + local loop_callback_use_object = --[[persistable:operatring_theatre_use_callback]] function(action) + num_loops = num_loops - 1 + if num_loops <= 0 then + action.prolonged_usage = false + end + end + + local after_use_use_object = --[[persistable:operatring_theatre_after_use]] function() + multi_use.prolonged_usage = false + end + + return UseObjectAction(operation_table_b):setLoopCallback(loop_callback_use_object) + :setAfterUse(after_use_use_object):setMustHappen(true):disableTruncate() +end + +function OperatingTheatreRoom:commandEnteringStaff(staff) -- Put surgeon outfit on - local obj, ox, oy = self.world:findObjectNear(staff, "surgeon_screen") - staff:walkTo(ox, oy) - staff:queueAction(wait_for_object(staff, obj)) - staff:queueAction{ - name = "use_screen", - object = obj - } + local screen, screen_x, screen_y = self.world:findObjectNear(staff, "surgeon_screen") + staff:walkTo(screen_x, screen_y) + staff:queueAction(wait_for_object(staff, screen, false)) + staff:queueAction(UseScreenAction(screen)) + + -- Resume operation if already ongoing + if self:isOperating() then + local surgeon1 = next(self.staff_member_set) + local ongoing_action = surgeon1:getCurrentAction() + assert(ongoing_action.name == "multi_use_object") + + local table, table_x, table_y = self.world:findObjectNear(staff, "operating_table_b") + self:queueWashHands(staff) + staff:queueAction(WalkAction(table_x, table_y)) + staff:queueAction(self._buildTableAction2(ongoing_action, table)) + end + + self.staff_member_set[staff] = true -- Wait around for patients - local meander = {name = "meander", must_happen = true, - loop_callback = --[[persistable:operatring_theatre_after_surgeon_clothes_on]] function() - self.staff_member_set[staff] = "ready" - self:tryAdvanceQueue() - end - } - staff:queueAction(meander) + local loop_callback_more_patients = --[[persistable:operatring_theatre_after_surgeon_clothes_on]] function() + self.staff_member_set[staff] = "ready" + self:tryAdvanceQueue() + end + staff:queueAction(MeanderAction():setMustHappen(true):setLoopCallback(loop_callback_more_patients)) -- Ensure that surgeons turn back into doctors when they leave - staff:queueAction{ - name = "walk", - x = ox, - y = oy, - must_happen = true, - truncate_only_on_high_priority = true, - is_leaving = true, - } - staff:queueAction{name = "use_screen", object = obj, must_happen = true, is_leaving = true} + staff:queueAction(WalkAction(screen_x, screen_y):setMustHappen(true):setIsLeaving(true) + :truncateOnHighPriority()) + staff:queueAction(UseScreenAction(screen):setMustHappen(true):setIsLeaving(true)) return Room.commandEnteringStaff(self, staff, true) end @@ -151,11 +188,63 @@ return staff end -function OperatingTheatreRoom:commandEnteringPatient(patient) - -- Turn on x-ray viewer - if it has been found. +--! Builds the first operation action (i.e. with the surgeon whose we see the front). +--!param surgeon1 (Staff): the surgeon who does this operation action. He must +--! be the same as the surgeon who gets the action on his queue. +--!param patient (Patient): the patient to be operated. +--!param operation_table (OperatingTable): master object representing +--! the operation table. +function OperatingTheatreRoom:buildTableAction1(surgeon1, patient, operation_table) + local loop_callback_multi_use = --[[persistable:operatring_theatre_multi_use_callback]] function(_) + -- dirty hack to make the truncated animation work + surgeon1.animation_idx = nil + end + + local after_use_table = --[[persistable:operatring_theatre_table_after_use]] function() + self:dealtWithPatient(patient) + -- Tell the patient that it's time to leave, but only if the first action + -- is really an idle action. + if patient:getCurrentAction().name == "idle" then + patient:finishAction() + end + end + + return MultiUseObjectAction(operation_table, patient):setProlongedUsage(true) + :setLoopCallback(loop_callback_multi_use):setAfterUse(after_use_table) + :setMustHappen(true):disableTruncate() +end + +--! Sends the surgeon to the nearest operation sink ("op_sink1") +--! and makes him wash his hands +--!param at_front (boolean): If true, add the actions at the front the action queue. +--! Add the actions at the end of the queue otherwise. +--! Default value is true. +function OperatingTheatreRoom:queueWashHands(surgeon, at_front) + local sink, sink_x, sink_y = self.world:findObjectNear(surgeon, "op_sink1") + local walk = WalkAction(sink_x, sink_y):setMustHappen(true):disableTruncate() + local wait = wait_for_object(surgeon, sink, true) + local wash = UseObjectAction(sink):setMustHappen(true) + + for pos, action in pairs({walk, wait, wash}) do + if (at_front) then + surgeon:queueAction(action, pos) + else + surgeon:queueAction(action) + end + end +end + +--! Turn on/off x-ray viewer - if it's been found +--!param turn_on (boolean): true to switch on and false to switch off +function OperatingTheatreRoom:setXRayOn(turn_on) if self.x_ray_viewer then - self.x_ray_viewer:setLayer(11, 2) + self.x_ray_viewer:setLayer(11, (turn_on and 2 or 0)) end +end + +function OperatingTheatreRoom:commandEnteringPatient(patient) + -- Turn on x-ray viewer + self:setXRayOn(true) -- Identify the staff local surgeon1 = next(self.staff_member_set) @@ -165,20 +254,16 @@ -- Patient changes into surgical gown local screen, sx, sy = self.world:findObjectNear(patient, "surgeon_screen") patient:walkTo(sx, sy) - patient:queueAction{name = "use_screen", object = screen} + patient:queueAction(UseScreenAction(screen)) -- Meanwhile, surgeons wash their hands - local obj, ox, oy = self.world:findObjectNear(surgeon1, "op_sink1") - surgeon1:queueAction({name = "walk", x = ox, y = oy, must_happen = true, no_truncate = true}, 1) - surgeon2:queueAction({name = "walk", x = ox, y = oy, must_happen = true, no_truncate = true}, 1) - surgeon1:queueAction(wait_for_object(surgeon1, obj, true), 2) - surgeon1:queueAction({name = "use_object", object = obj, must_happen = true}, 3) - surgeon2:queueAction(wait_for_object(surgeon2, obj, true), 2) - surgeon2:queueAction({name = "use_object", object = obj, must_happen = true}, 3) + -- TODO: They sometimes overlap each other when doing that. Can we avoid that? + self:queueWashHands(surgeon1, true) + self:queueWashHands(surgeon2, true) local num_ready = {0} ----- BEGIN Save game compatibility ----- - -- These function are merely for save game compability. + -- These function are merely for save game compatibility. -- And they does not participate in the current game logic. -- Do not move or edit local --[[persistable:operatring_theatre_wait_for_ready]] function wait_for_ready(action) @@ -198,57 +283,23 @@ end ----- END Save game compatibility ----- - local room = self local --[[persistable:operatring_theatre_operation_standby]] function operation_standby(action, humanoid) action.on_interrupt = nil if not action.done_ready then num_ready[1] = num_ready[1] + 1 action.done_ready = true end - if room.staff_member_set[humanoid] and room.staff_member_set[humanoid] == "abort" then + if self.staff_member_set[humanoid] and self.staff_member_set[humanoid] == "abort" then humanoid:finishAction() elseif num_ready[1] == 3 then -- Only if everyone (2 Surgeons and Patient) ready, we schedule the operation action - local obj, ox, oy = room.world:findObjectNear(surgeon1, "operating_table") - local multi_use = { - name = "multi_use_object", - object = obj, - use_with = patient, - prolonged_usage = true, - loop_callback = --[[persistable:operatring_theatre_multi_use_callback]] function(action) - -- dirty hack to make the truncated animation work - surgeon1.animation_idx = nil - end, - after_use = --[[persistable:operatring_theatre_table_after_use]] function() - room:dealtWithPatient(patient) - -- Tell the patient that it's time to leave, but only if the first action - -- is really an idle action. - if patient.action_queue[1].name == "idle" then - patient:finishAction() - end - end, - must_happen = true, - no_truncate = true, - } - surgeon1:queueAction(multi_use, 1) - - obj, ox, oy = self.world:findObjectNear(surgeon1, "operating_table_b") - local num_loops = math.random(2, 5) - surgeon2:queueAction({ - name = "use_object", - object = obj, - loop_callback = --[[persistable:operatring_theatre_use_callback]] function(action) - num_loops = num_loops - 1 - if num_loops <= 0 then - action.prolonged_usage = false - end - end, - after_use = --[[persistable:operatring_theatre_after_use]] function() - multi_use.prolonged_usage = false - end, - must_happen = true, - no_truncate = true, - }, 1) + local obj, _, _ = self.world:findObjectNear(surgeon1, "operating_table") + + local table_action1 = self:buildTableAction1(surgeon1, patient, obj) + surgeon1:queueAction(table_action1, 1) + + obj, _, _ = self.world:findObjectNear(surgeon2, "operating_table_b") + surgeon2:queueAction(self._buildTableAction2(table_action1, obj), 1) -- Kick off surgeon1:finishAction() @@ -259,40 +310,36 @@ ---- Everyone standby...and sync start the operation -- -- first surgeon walk over to the operating table - obj, ox, oy = self.world:findObjectNear(surgeon1, "operating_table") - surgeon1:queueAction({name = "walk", x = ox, y = oy, must_happen = true, no_truncate = true}, 4) - surgeon1:queueAction({name = "idle", loop_callback = operation_standby, must_happen = true}, 5) + local obj, ox, oy = self.world:findObjectNear(surgeon1, "operating_table") + surgeon1:queueAction(WalkAction(ox, oy):setMustHappen(true):disableTruncate(), 4) + surgeon1:queueAction(IdleAction():setLoopCallback(operation_standby):setMustHappen(true), 5) -- Patient walk to the side of the operating table ox, oy = obj:getSecondaryUsageTile() - patient:queueAction{name = "walk", x = ox, y = oy, must_happen = true, no_truncate = true} - patient:queueAction{name = "idle", loop_callback = operation_standby, must_happen = true} + patient:queueAction(WalkAction(ox, oy):setMustHappen(true):disableTruncate()) + patient:queueAction(IdleAction():setLoopCallback(operation_standby):setMustHappen(true)) -- Patient changes out of the gown afterwards - patient:queueAction{ - name = "walk", - x = sx, - y = sy, - must_happen = true, - no_truncate = true, - } - patient:queueAction{name = "use_screen", object = screen, must_happen = true} + patient:queueAction(WalkAction(sx, sy):setMustHappen(true):disableTruncate()) + patient:queueAction(UseScreenAction(screen):setMustHappen(true)) -- Meanwhile, second surgeon walks over to other side of operating table - obj, ox, oy = self.world:findObjectNear(surgeon1, "operating_table_b") - surgeon2:queueAction({name = "walk", x = ox, y = oy, must_happen = true, no_truncate = true}, 4) - surgeon2:queueAction({name = "idle", loop_callback = operation_standby, must_happen = true}, 5) + local _ + _, ox, oy = self.world:findObjectNear(surgeon1, "operating_table_b") + surgeon2:queueAction(WalkAction(ox, oy):setMustHappen(true):disableTruncate(), 4) + surgeon2:queueAction(IdleAction():setLoopCallback(operation_standby):setMustHappen(true), 5) return Room.commandEnteringPatient(self, patient) end function OperatingTheatreRoom:onHumanoidLeave(humanoid) self.staff_member_set[humanoid] = nil - -- Turn off x-ray viewer + if class.is(humanoid, Patient) then - if self.x_ray_viewer then - self.x_ray_viewer:setLayer(11, 0) - end + -- Turn off x-ray viewer + -- (FIXME: would be better when patient dress back?) + self:setXRayOn(false) + local surgeon1 = next(self.staff_member_set) local surgeon2 = next(self.staff_member_set, surgeon1) if surgeon1 then diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/pharmacy.lua corsix-th-0.62/CorsixTH/Lua/rooms/pharmacy.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/pharmacy.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/pharmacy.lua 2018-07-21 11:13:17.000000000 +0000 @@ -42,6 +42,9 @@ class "PharmacyRoom" (Room) +---@type PharmacyRoom +local PharmacyRoom = _G["PharmacyRoom"] + function PharmacyRoom:PharmacyRoom(...) self:Room(...) end @@ -71,27 +74,26 @@ layer3 = math.random(0, 2) * 2 end - patient:setNextAction{name = "walk", x = pat_x, y = pat_y} - patient:queueAction{name = "idle", direction = cabinet.direction == "north" and "east" or "south"} - staff:setNextAction{name = "walk", x = stf_x, y = stf_y} - staff:queueAction{ - name = "multi_use_object", - object = cabinet, - use_with = patient, - layer3 = layer3, - after_use = --[[persistable:pharmacy_after_use]] function() - --if we haven't tried to edit the room while she's animating, meander - if #staff.action_queue == 1 then - staff:setNextAction{name = "meander"} - end - if patient_class == "Invisible Patient" or patient_class == "Transparent Male Patient" then - patient:setType "Standard Male Patient" - elseif patient_class == "Transparent Female Patient" then - patient:setType "Standard Female Patient" - end - self:dealtWithPatient(patient) - end, - } + patient:setNextAction(WalkAction(pat_x, pat_y)) + patient:queueAction(IdleAction():setDirection(cabinet.direction == "north" and "east" or "south")) + + staff:setNextAction(WalkAction(stf_x, stf_y)) + + local after_use_pharmacy = --[[persistable:pharmacy_after_use]] function() + --if we haven't tried to edit the room while she's animating, meander + if #staff.action_queue == 1 then + staff:setNextAction(MeanderAction()) + end + if patient_class == "Invisible Patient" or patient_class == "Transparent Male Patient" then + patient:setType "Standard Male Patient" + elseif patient_class == "Transparent Female Patient" then + patient:setType "Standard Female Patient" + end + self:dealtWithPatient(patient) + end + + staff:queueAction(MultiUseObjectAction(cabinet, patient):setAfterUse(after_use_pharmacy) + :setLayer3(layer3)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/psych.lua corsix-th-0.62/CorsixTH/Lua/rooms/psych.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/psych.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/psych.lua 2018-07-21 11:13:17.000000000 +0000 @@ -43,6 +43,9 @@ class "PsychRoom" (Room) +---@type PsychRoom +local PsychRoom = _G["PsychRoom"] + function PsychRoom:PsychRoom(...) self:Room(...) end @@ -59,20 +62,18 @@ self.staff_member = staff local obj, ox, oy = self.world:findFreeObjectNearToUse(staff, "bookcase", "near") if not obj then - staff:setNextAction{name = "meander"} + staff:setNextAction(MeanderAction()) else staff:walkTo(ox, oy) - staff:queueAction{name = "use_object", object = obj} + staff:queueAction(UseObjectAction(obj)) local num_meanders = math.random(2, 8) - staff:queueAction{ - name = "meander", - loop_callback = --[[persistable:psych_meander_loop_callback]] function(action) - num_meanders = num_meanders - 1 - if num_meanders == 0 then - self:commandEnteringStaff(staff) - end + local loop_callback_meanders = --[[persistable:psych_meander_loop_callback]] function(action) + num_meanders = num_meanders - 1 + if num_meanders == 0 then + self:commandEnteringStaff(staff) end - } + end + staff:queueAction(MeanderAction():setLoopCallback(loop_callback_meanders)) end return Room.commandEnteringStaff(self, staff, true) end @@ -82,7 +83,7 @@ local obj, ox, oy = self.world:findObjectNear(patient, "couch") patient:walkTo(ox, oy) - patient:queueAction{name = "use_object", object = obj} + patient:queueAction(UseObjectAction(obj)) local duration = math.random(16, 72) local bookcase, bx, by @@ -94,42 +95,37 @@ duration = duration - 1 end if duration <= 0 then - if patient.diagnosed and patient.humanoid_class == "Elvis Patient" then + if patient.diagnosed and patient.disease.id == "king_complex" then -- Diagnosed patients (Elvis) need to change clothes + local after_use_screen = --[[persistable:psych_screen_after_use]] function() + if self:getStaffMember() then + self:getStaffMember():setNextAction(MeanderAction()) + end + self:dealtWithPatient(patient) + end + obj, ox, oy = self.world:findObjectNear(patient, "screen") patient:walkTo(ox, oy) - patient:queueAction{ - name = "use_screen", - object = obj, - after_use = --[[persistable:psych_screen_after_use]] function() - self:dealtWithPatient(patient) - end, - } + patient:queueAction(UseScreenAction(obj):setAfterUse(after_use_screen)) else + if self:getStaffMember() then + self:getStaffMember():setNextAction(MeanderAction()) + end self:dealtWithPatient(patient) end - self:getStaffMember():setNextAction{name = "meander"} return end if bookcase and (duration % 10) == 0 and math.random(1, 2) == 1 then staff:walkTo(bx, by) - staff:queueAction{name = "use_object", object = bookcase} - staff:queueAction{name = "walk", x = ox, y = oy} - staff:queueAction{ - name = "use_object", - object = obj, - loop_callback = loop_callback, - } + staff:queueAction(UseObjectAction(bookcase)) + staff:queueAction(WalkAction(ox, oy)) + staff:queueAction(UseObjectAction(obj):setLoopCallback(loop_callback)) duration = math.max(8, duration - 72) end end obj, ox, oy = self.world:findObjectNear(staff, "comfortable_chair") staff:walkTo(ox, oy) - staff:queueAction{ - name = "use_object", - object = obj, - loop_callback = loop_callback, - } + staff:queueAction(UseObjectAction(obj):setLoopCallback(loop_callback)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/research.lua corsix-th-0.62/CorsixTH/Lua/rooms/research.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/research.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/research.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -49,6 +49,9 @@ class "ResearchRoom" (Room) +---@type ResearchRoom +local ResearchRoom = _G["ResearchRoom"] + function ResearchRoom:ResearchRoom(...) self:Room(...) self.staff_member_set = {} @@ -71,53 +74,50 @@ staff:walkTo(ox, oy) if obj.object_type.id == "desk" then local desk_use_time = math.random(7, 14) - staff:queueAction { - name = "use_object", - object = obj, - loop_callback = --[[persistable:research_desk_loop_callback]] function(action) - desk_use_time = desk_use_time - 1 - if action.todo_interrupt or desk_use_time == 0 then - action.prolonged_usage = false - end - end, - after_use = --[[persistable:research_desk_after_use]] function() - -- TODO: Should interactions give points? - self.hospital.research:addResearchPoints(100) - end, - } + local loop_callback_desk = --[[persistable:research_desk_loop_callback]] function(action) + desk_use_time = desk_use_time - 1 + if action.todo_interrupt or desk_use_time == 0 then + action.prolonged_usage = false + end + end + + local after_use_desk = --[[persistable:research_desk_after_use]] function() + -- TODO: Should interactions give points? + self.hospital.research:addResearchPoints(100) + end + + staff:queueAction(UseObjectAction(obj):setLoopCallback(loop_callback_desk) + :setAfterUse(after_use_desk)) else - staff:queueAction { - name = "use_object", - object = obj, - after_use = --[[persistable:research_obj_after_use]] function() - if obj.object_type.id == "computer" then - self.hospital.research:addResearchPoints(500) - elseif obj.object_type.id == "analyser" then - self.hospital.research:addResearchPoints(800) - -- TODO: Balance value, find it in level config? - end - end, - } + local after_use_obj = --[[persistable:research_obj_after_use]] function() + if obj.object_type.id == "computer" then + self.hospital.research:addResearchPoints(500) + elseif obj.object_type.id == "analyser" then + self.hospital.research:addResearchPoints(800) + -- TODO: Balance value, find it in level config? + end + end + + staff:queueAction(UseObjectAction(obj):setAfterUse(after_use_obj)) end end local num_meanders = math.random(2, 4) - staff:queueAction { - name = "meander", - loop_callback = --[[persistable:research_meander_loop_callback]] function(action) - num_meanders = num_meanders - 1 - if num_meanders == 0 then - self:doStaffUseCycle(staff) - end + local loop_callback_meander = --[[persistable:research_meander_loop_callback]] function(action) + num_meanders = num_meanders - 1 + if num_meanders == 0 then + self:doStaffUseCycle(staff) end - } + end + + staff:queueAction(MeanderAction():setLoopCallback(loop_callback_meander)) end function ResearchRoom:roomFinished() local fx, fy = self:getEntranceXY(true) local objects = self.world:findAllObjectsNear(fx, fy) local number = 0 - for object, value in pairs(objects) do + for object, _ in pairs(objects) do -- The number of desks in the room determines how many researchers -- can work there at once. if object.object_type.id == "desk" then @@ -135,8 +135,7 @@ end -- Also check if it would be good to hire a researcher. if not self.hospital:hasStaffOfCategory("Researcher") then - self.world.ui.adviser:say(_A.room_requirements - .research_room_need_researcher) + self.world.ui.adviser:say(_A.room_requirements.research_room_need_researcher) end return Room.roomFinished(self) end @@ -154,42 +153,36 @@ function ResearchRoom:commandEnteringPatient(patient) local staff = next(self.staff_member_set) local autopsy, stf_x, stf_y = self.world:findObjectNear(patient, "autopsy") - local orientation = autopsy.object_type.orientations[autopsy.direction] local pat_x, pat_y = autopsy:getSecondaryUsageTile() patient:walkTo(pat_x, pat_y) - patient:queueAction{name = "idle", direction = "east"} + patient:queueAction(IdleAction():setDirection("east")) staff:walkTo(stf_x, stf_y) - staff:queueAction{ - name = "multi_use_object", - object = autopsy, - use_with = patient, - after_use = --[[persistable:autopsy_after_use]] function() - self:commandEnteringStaff(staff) - -- Patient dies :( - self:onHumanoidLeave(patient) - -- Some research is done. :) Might trigger a loss of reputation though. - local hosp = self.hospital - local room = patient.disease.treatment_rooms[#patient.disease.treatment_rooms] - hosp.research:addResearchPoints("dummy", room) - if hosp.discover_autopsy_risk > math.random(1, 100) and not hosp.autopsy_discovered then - -- Can only be discovered once. - hosp.autopsy_discovered = true - hosp:changeReputation("autopsy_discovered") - hosp.world.ui.adviser:say(_A.research.autopsy_discovered_rep_loss) - else - -- The risk increases after each use. - -- TODO: Should it ever become 100%? - self.hospital.discover_autopsy_risk = self.hospital.discover_autopsy_risk + 10 - end - if patient.hospital then - -- NB: Do not use patient:setHospital(nil) as that also causes despawning, which - -- has some bad effects if the autopsy machine is directly next to the room's door - hosp:removePatient(patient) - patient.hospital = nil - end - patient.world:destroyEntity(patient) - end, - } + + local after_use_autopsy = --[[persistable:autopsy_after_use]] function() + self:commandEnteringStaff(staff) + -- Patient dies :( + self:onHumanoidLeave(patient) + -- Some research is done. :) Might trigger a loss of reputation though. + local hosp = self.hospital + local patient_room = patient.disease.treatment_rooms[#patient.disease.treatment_rooms] + hosp.research:addResearchPoints("dummy", patient_room) + if not hosp.autopsy_discovered and hosp.discover_autopsy_risk > math.random(1, 100) then + -- Can only be discovered once. + hosp.autopsy_discovered = true + hosp:changeReputation("autopsy_discovered") + hosp.world.ui.adviser:say(_A.research.autopsy_discovered_rep_loss) + else + -- The risk increases after each use. + -- TODO: Should it ever become 100%? + self.hospital.discover_autopsy_risk = self.hospital.discover_autopsy_risk + 10 + end + if patient.hospital then + hosp:removePatient(patient) + end + patient.world:destroyEntity(patient) + end + + staff:queueAction(MultiUseObjectAction(autopsy, patient):setAfterUse(after_use_autopsy)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/scanner_room.lua corsix-th-0.62/CorsixTH/Lua/rooms/scanner_room.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/scanner_room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/scanner_room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -45,6 +45,9 @@ class "ScannerRoom" (Room) +---@type ScannerRoom +local ScannerRoom = _G["ScannerRoom"] + function ScannerRoom:ScannerRoom(...) self:Room(...) end @@ -58,64 +61,54 @@ (patient.humanoid_class == "Standard Female Patient") local --[[persistable:scanner_shared_loop_callback]] function loop_callback() - if staff.action_queue[1].scanner_ready and patient.action_queue[1].scanner_ready then + if staff:getCurrentAction().scanner_ready and patient:getCurrentAction().scanner_ready then staff:finishAction() patient:finishAction() end end staff:walkTo(stf_x, stf_y) - staff:queueAction{ - name = "idle", - direction = console.direction == "north" and "west" or "north", - loop_callback = loop_callback, - scanner_ready = true, - } - staff:queueAction{ - name = "use_object", - object = console, - } + local idle_action = IdleAction():setDirection(console.direction == "north" and "west" or "north") + :setLoopCallback(loop_callback) + idle_action.scanner_ready = true + staff:queueAction(idle_action) + + staff:queueAction(UseObjectAction(console)) if do_change then patient:walkTo(sx, sy) - patient:queueAction{ - name = "use_screen", - object = screen, - } - patient:queueAction{ - name = "walk", - x = pat_x, - y = pat_y, - } + patient:queueAction(UseScreenAction(screen)) + patient:queueAction(WalkAction(pat_x, pat_y)) else patient:walkTo(pat_x, pat_y) end - patient:queueAction{ - name = "idle", - direction = scanner.direction == "north" and "east" or "south", - loop_callback = loop_callback, - scanner_ready = true, - } + + idle_action = IdleAction():setDirection(scanner.direction == "north" and "east" or "south") + :setLoopCallback(loop_callback) + idle_action.scanner_ready = true + patient:queueAction(idle_action) + local length = math.random(10, 20) * (2 - staff.profile.skill) - patient:queueAction{ - name = "use_object", - object = scanner, - loop_callback = --[[persistable:scanner_loop_callback]] function(action) - if length <= 0 then - action.prolonged_usage = false - end - length = length - 1 - end, - after_use = --[[persistable:scanner_after_use]] function() - if not self.staff_member or patient.going_home then - -- If we aborted somehow, don't do anything here. - -- The patient already has orders to change back if necessary and leave. - return - end - self.staff_member:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } + local loop_callback_scan = --[[persistable:scanner_loop_callback]] function(action) + if length <= 0 then + action.prolonged_usage = false + end + length = length - 1 + end + + local after_use_scan = --[[persistable:scanner_after_use]] function() + if not self.staff_member or patient.going_home then + -- If we aborted somehow, don't do anything here. + -- The patient already has orders to change back if necessary and leave. + -- makeHumanoidLeave() will make this function nil when it aborts the scanner's use. + return + end + self.staff_member:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + + patient:queueAction(UseObjectAction(scanner):setLoopCallback(loop_callback_scan) + :setAfterUse(after_use_scan)) return Room.commandEnteringPatient(self, patient) end @@ -126,69 +119,35 @@ Room.onHumanoidLeave(self, humanoid) end -function ScannerRoom:makeHumanoidLeave(patient) - local screen, sx, sy = self.world:findObjectNear(patient, "screen") - - if (patient.humanoid_class == "Stripped Male Patient" or - patient.humanoid_class == "Stripped Male Patient 2" or - patient.humanoid_class == "Stripped Female Patient" or - patient.humanoid_class == "Stripped Male Patient 3" or - patient.humanoid_class == "Stripped Female Patient 2" or - patient.humanoid_class == "Stripped Female Patient 3") and - not patient.action_queue[1].is_leaving then - - patient:setNextAction{ - name = "walk", - x = sx, - y = sy, - must_happen = true, - no_truncate = true, - is_leaving = true, - } - patient:queueAction{ - name = "use_screen", - object = screen, - must_happen = true, - is_leaving = true, - } - local leave = self:createLeaveAction() - leave.must_happen = true - patient:queueAction(leave) - else - local leave = self:createLeaveAction() - leave.must_happen = true - patient:setNextAction(leave) +function ScannerRoom:makeHumanoidLeave(humanoid) + if humanoid:getCurrentAction().name == "use_object" and + humanoid:getCurrentAction().object == self.world:findObjectNear(humanoid, "scanner") then + humanoid:getCurrentAction().after_use = nil end + + self:makeHumanoidDressIfNecessaryAndThenLeave(humanoid) end function ScannerRoom:dealtWithPatient(patient) - local screen, sx, sy = self.world:findObjectNear(patient, "screen") - if patient.humanoid_class == "Stripped Male Patient" or - patient.humanoid_class == "Stripped Female Patient" or - patient.humanoid_class == "Stripped Male Patient 2" or - patient.humanoid_class == "Stripped Female Patient 2" or - patient.humanoid_class == "Stripped Male Patient 3" or - patient.humanoid_class == "Stripped Female Patient 3" then - - patient:setNextAction{ - name = "walk", - x = sx, - y = sy, - must_happen = true, - no_truncate = true, - is_leaving = true, - } - patient:queueAction{ - name = "use_screen", - object = screen, - must_happen = true, - is_leaving = true, - after_use = --[[persistable:scanner_exit]] function() Room.dealtWithPatient(self, patient) end, - } + if string.find(patient.humanoid_class, "Stripped") then + local screen, sx, sy = self.world:findObjectNear(patient, "screen") + patient:setNextAction(WalkAction(sx, sy):setMustHappen(true):setIsLeaving(true) + :disableTruncate()) + + local after_use_patient = --[[persistable:scanner_exit]] function() + Room.dealtWithPatient(self, patient) + end + + patient:queueAction(UseScreenAction(screen):setMustHappen(true):setIsLeaving(true) + :setAfterUse(after_use_patient)) patient:queueAction(self:createLeaveAction()) else Room.dealtWithPatient(self, patient) end end +function ScannerRoom:shouldHavePatientReenter(patient) + return not patient:isLeaving() +end + return room diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/slack_tongue.lua corsix-th-0.62/CorsixTH/Lua/rooms/slack_tongue.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/slack_tongue.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/slack_tongue.lua 2018-07-21 11:13:17.000000000 +0000 @@ -43,6 +43,9 @@ class "SlackTongueRoom" (Room) +---@type SlackTongueRoom +local SlackTongueRoom = _G["SlackTongueRoom"] + function SlackTongueRoom:SlackTongueRoom(...) self:Room(...) end @@ -50,27 +53,24 @@ function SlackTongueRoom:commandEnteringPatient(patient) local staff = self.staff_member local slicer, pat_x, pat_y = self.world:findObjectNear(patient, "slicer") - local orientation = slicer.object_type.orientations[slicer.direction] local stf_x, stf_y = slicer:getSecondaryUsageTile() - staff:setNextAction{name = "walk", x = stf_x, y = stf_y} - staff:queueAction{name = "idle", direction = slicer.direction == "north" and "east" or "south"} - patient:setNextAction{name = "walk", x = pat_x, y = pat_y} - patient:queueAction{ - name = "multi_use_object", - object = slicer, - use_with = staff, - after_use = --[[persistable:slack_tongue_after_use]] function() - if patient.humanoid_class == "Slack Male Patient" then - patient:setType "Standard Male Patient" -- Change to normal head - else - patient:setLayer(0, patient.layers[0] - 8) -- Change to normal head - end - staff:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } + staff:setNextAction(WalkAction(stf_x, stf_y)) + staff:queueAction(IdleAction():setDirection(slicer.direction == "north" and "east" or "south")) + + patient:setNextAction(WalkAction(pat_x, pat_y)) + + local after_use_slack_tongue = --[[persistable:slack_tongue_after_use]] function() + if patient.humanoid_class == "Slack Male Patient" then + patient:setType "Standard Male Patient" -- Change to normal head + else + patient:setLayer(0, patient.layers[0] - 8) -- Change to normal head + end + staff:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + patient:queueAction(MultiUseObjectAction(slicer, staff):setAfterUse(after_use_slack_tongue)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/staff_room.lua corsix-th-0.62/CorsixTH/Lua/rooms/staff_room.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/staff_room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/staff_room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -38,6 +38,9 @@ class "StaffRoom" (Room) +---@type StaffRoom +local StaffRoom = _G["StaffRoom"] + function StaffRoom:StaffRoom(...) self:Room(...) end @@ -50,7 +53,7 @@ -- Receptionists cannot enter, so we do not have to worry about them -- If it is a handyman and he is here to do a job, let him pass if not humanoid.on_call then - humanoid:setNextAction({name = "use_staffroom"}) + humanoid:setNextAction(UseStaffRoomAction()) self.door.queue.visitor_count = self.door.queue.visitor_count + 1 end else diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/toilets.lua corsix-th-0.62/CorsixTH/Lua/rooms/toilets.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/toilets.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/toilets.lua 2018-07-21 11:13:17.000000000 +0000 @@ -37,7 +37,8 @@ class "ToiletRoom" (Room) -room.free_loos = 0 +---@type ToiletRoom +local ToiletRoom = _G["ToiletRoom"] function ToiletRoom:ToiletRoom(...) self:Room(...) @@ -48,7 +49,7 @@ local fx, fy = self:getEntranceXY(true) local objects = self.world:findAllObjectsNear(fx, fy) local number = 0 - for object, value in pairs(objects) do + for object, _ in pairs(objects) do if object.object_type.id == "loo" then number = number + 1 end @@ -57,28 +58,13 @@ Room.roomFinished(self) end --- if any of the occupants are not using a loo then the loo must be free! -function ToiletRoom:freeLoos() - local number = 0 - for humanoid in pairs(self.humanoids) do - if class.is(humanoid, Patient) then - if (humanoid.action_queue[1].name == "use_object" - and humanoid.action_queue[1].object.object_type.id ~= "loo") then - number = number + 1 - room.free_loos = number - end - end - end - return room.free_loos -end - function ToiletRoom:dealtWithPatient(patient) --- Continue to the previous room + -- Continue going to the room before going to the toilets. patient:setNextAction(self:createLeaveAction()) if patient.next_room_to_visit then - patient:queueAction{name = "seek_room", room_type = patient.next_room_to_visit.room_info.id} + patient:queueAction(SeekRoomAction(patient.next_room_to_visit.room_info.id)) else - patient:queueAction{name = "seek_reception"} + patient:queueAction(SeekReceptionAction()) end end @@ -93,69 +79,62 @@ if humanoid.humanoid_class == "Transparent Female Patient" then use_time = math.random(15, 40) end - humanoid:queueAction{ - name = "use_object", - object = loo, - loop_callback = --[[persistable:toilets_loop_callback]] function() - use_time = use_time - 1 - if use_time <= 0 then - humanoid:setMood("poo", "deactivate") - humanoid:changeAttribute("toilet_need", -(0.85 + math.random()*0.15)) - humanoid.going_to_toilet = nil + + local loop_callback_toilets = --[[persistable:toilets_loop_callback]] function() + use_time = use_time - 1 + if use_time <= 0 then + humanoid:setMood("poo", "deactivate") + humanoid:changeAttribute("toilet_need", -(0.85 + math.random() * 0.15)) + humanoid.going_to_toilet = "no" + -- There are only animations for standard patients to use the sinks. - if humanoid.humanoid_class == "Standard Female Patient" or + if humanoid.humanoid_class == "Standard Female Patient" or humanoid.humanoid_class == "Standard Male Patient" then - local --[[persistable:toilets_find_sink]] function after_use() - local sink, sx, sy = self.world:findFreeObjectNearToUse(humanoid, "sink") - if sink then - humanoid:walkTo(sx, sy) - humanoid:queueAction{ - name = "use_object", - object = sink, - prolonged_usage = false, - after_use = --[[persistable:toilets_after_use_sink]] function() - self:dealtWithPatient(humanoid) - end, - } - sink.reserved_for = humanoid - -- Make sure that the mood waiting is no longer active. - humanoid:setMood("patient_wait", "deactivate") - else - -- if there is a queue to wash hands there is a chance we might not bother - -- but the patient won't be happy about this. - if math.random(1, 4) > 2 then + local --[[persistable:toilets_find_sink]] function after_use() + local sink, sx, sy = self.world:findFreeObjectNearToUse(humanoid, "sink") + if sink then + humanoid:walkTo(sx, sy) + + local after_use_sink = --[[persistable:toilets_after_use_sink]] function() + self:dealtWithPatient(humanoid) + end + + humanoid:queueAction(UseObjectAction(sink):setProlongedUsage(false) + :setAfterUse(after_use_sink)) + sink.reserved_for = humanoid + -- Make sure that the mood waiting is no longer active. + humanoid:setMood("patient_wait", "deactivate") + else + -- if there is a queue to wash hands there is a chance we might not bother + -- but the patient won't be happy about this. + if math.random(1, 4) > 2 then -- Wait for a while before trying again. - humanoid:setNextAction{ - name = "idle", - count = 5, - after_use = after_use, - direction = loo.direction == "north" and "south" or "east", - } - else - self:dealtWithPatient(humanoid) - humanoid:changeAttribute("happiness", -0.08) - humanoid:setMood("patient_wait", "deactivate") - end - -- For now, activate the wait icon to show the player that the patient hasn't - -- got stuck. TODO: Make a custom mood? Let many people use the sinks? - humanoid:setMood("patient_wait", "activate") + humanoid:setNextAction(IdleAction():setCount(5):setAfterUse(after_use) + :setDirection(loo.direction == "north" and "south" or "east")) + + else + self:dealtWithPatient(humanoid) + humanoid:changeAttribute("happiness", -0.08) + humanoid:setMood("patient_wait", "deactivate") end + -- For now, activate the wait icon to show the player that the patient hasn't + -- got stuck. TODO: Make a custom mood? Let many people use the sinks? + humanoid:setMood("patient_wait", "activate") end - after_use() - else - self:dealtWithPatient(humanoid) end + after_use() + else + self:dealtWithPatient(humanoid) end end - } + end + + humanoid:queueAction(UseObjectAction(loo):setLoopCallback(loop_callback_toilets)) else --[[ If no loo is found, perhaps the patient followed another one in and they were heading for the same one. Now there is no free loo, so wait for a bit and then leave the room to wait outside. No need for a warning as this is what happens in busy toilets]] - humanoid:setNextAction{ - name = "meander", - count = 1 - } + humanoid:setNextAction(MeanderAction():setCount(1)) humanoid:queueAction(self:createLeaveAction()) humanoid:queueAction(self:createEnterAction(humanoid)) end @@ -167,25 +146,29 @@ -- that some of them may not be using the loo, allowing others to enter the room earlier than normal; -- but not if there is only one loo in the room, then it becomes a private toilet with only one person at a time. function ToiletRoom:getPatientCount() - local count = 0 - local true_space = 0 + local number_users = 0 + local not_using_loo = 0 for humanoid in pairs(self.humanoids) do if class.is(humanoid, Patient) then - count = count + 1 - self:freeLoos() - if self.maximum_patients > 1 then - true_space = count - room.free_loos - else - true_space = count + number_users = number_users + 1 + + if humanoid:getCurrentAction().name == "use_object" and + humanoid:getCurrentAction().object.object_type.id ~= "loo" then + not_using_loo = not_using_loo + 1 end end end - return true_space + + if self.maximum_patients == 1 then + return number_users + else + return number_users - not_using_loo + end end function ToiletRoom:afterLoad(old, new) - if old < 74 then - room.free_loos = 0 + if old < 110 then + room.free_loos = nil end Room.afterLoad(self, old, new) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/training.lua corsix-th-0.62/CorsixTH/Lua/rooms/training.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/training.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/training.lua 2018-07-21 11:13:17.000000000 +0000 @@ -38,6 +38,9 @@ class "TrainingRoom" (Room) +---@type TrainingRoom +local TrainingRoom = _G["TrainingRoom"] + function TrainingRoom:TrainingRoom(...) self:Room(...) end @@ -49,7 +52,7 @@ local chairs = 0 local skeletons = 0 local bookcases = 0 - for object, value in pairs(objects) do + for object, _ in pairs(objects) do if object.object_type.id == "lecture_chair" then chairs = chairs + 1 elseif object.object_type.id == "skeleton" then @@ -99,8 +102,8 @@ end function TrainingRoom:testStaffCriteria(criteria, extra_humanoid) - if extra_humanoid and extra_humanoid.profile - and extra_humanoid.profile.is_consultant and self.staff_member then + if extra_humanoid and extra_humanoid.profile and + extra_humanoid.profile.is_consultant and self.staff_member then -- Training room can only have on consultant return false end @@ -117,36 +120,35 @@ function TrainingRoom:doStaffUseCycle(humanoid) local projector, ox, oy = self.world:findObjectNear(humanoid, "projector") - humanoid:queueAction{name = "walk", x = ox, y = oy} + humanoid:queueAction(WalkAction(ox, oy)) local projector_use_time = math.random(6,20) - humanoid:queueAction{name = "use_object", - object = projector, - loop_callback = --[[persistable:training_loop_callback]] function() - projector_use_time = projector_use_time - 1 - if projector_use_time == 0 then - local skeleton, sox, soy = self.world:findFreeObjectNearToUse(humanoid, "skeleton", "near") - local bookcase, box, boy = self.world:findFreeObjectNearToUse(humanoid, "bookcase", "near") - if math.random(0, 1) == 0 and bookcase then skeleton = nil end -- choose one - if skeleton then - humanoid:walkTo(sox, soy) - for i = 1, math.random(3, 10) do - humanoid:queueAction{name = "use_object", object = skeleton} - end - elseif bookcase then - humanoid:walkTo(box, boy) - for i = 1, math.random(3, 10) do - humanoid:queueAction{name = "use_object", object = bookcase} - end + local loop_callback_training = --[[persistable:training_loop_callback]] function() + projector_use_time = projector_use_time - 1 + if projector_use_time == 0 then + local skeleton, sox, soy = self.world:findFreeObjectNearToUse(humanoid, "skeleton", "near") + local bookcase, box, boy = self.world:findFreeObjectNearToUse(humanoid, "bookcase", "near") + if math.random(0, 1) == 0 and bookcase then skeleton = nil end -- choose one + if skeleton then + humanoid:walkTo(sox, soy) + for _ = 1, math.random(3, 10) do + humanoid:queueAction(UseObjectAction(skeleton)) + end + elseif bookcase then + humanoid:walkTo(box, boy) + for _ = 1, math.random(3, 10) do + humanoid:queueAction(UseObjectAction(bookcase)) end - -- go back to the projector - self:doStaffUseCycle(humanoid) - elseif projector_use_time < 0 then - -- reset variable to avoid potential overflow (over a VERY long - -- period of time) - projector_use_time = 0 end - end, - } + -- go back to the projector + self:doStaffUseCycle(humanoid) + elseif projector_use_time < 0 then + -- reset variable to avoid potential overflow (over a VERY long + -- period of time) + projector_use_time = 0 + end + end + + humanoid:queueAction(UseObjectAction(projector):setLoopCallback(loop_callback_training)) end function TrainingRoom:onHumanoidEnter(humanoid) @@ -183,13 +185,13 @@ local staff = self.waiting_staff_member staff.waiting_on_other_staff = nil staff:setNextAction(self:createLeaveAction()) - staff:queueAction{name = "meander"} + staff:queueAction(MeanderAction()) end humanoid.waiting_on_other_staff = true - humanoid:setNextAction{name = "meander"} + humanoid:setNextAction(MeanderAction()) self.waiting_staff_member = humanoid self.staff_member:setNextAction(self:createLeaveAction()) - self.staff_member:queueAction{name = "meander"} + self.staff_member:queueAction(MeanderAction()) else if obj then obj.reserved_for = humanoid @@ -198,7 +200,7 @@ self:setStaffMember(humanoid) else humanoid:setNextAction(self:createLeaveAction()) - humanoid:queueAction{name = "meander"} + humanoid:queueAction(MeanderAction()) end end else @@ -206,11 +208,11 @@ if obj then obj.reserved_for = humanoid humanoid:walkTo(ox, oy) - humanoid:queueAction{name = "use_object", object = obj} - humanoid:queueAction{name = "meander"} + humanoid:queueAction(UseObjectAction(obj)) + humanoid:queueAction(MeanderAction()) else humanoid:setNextAction(self:createLeaveAction()) - humanoid:queueAction{name = "meander"} + humanoid:queueAction(MeanderAction()) humanoid.last_room = nil end end @@ -218,7 +220,7 @@ self.world.ui.adviser:say(_A.staff_place_advice.only_doctors_in_room :format(_S.rooms_long.training_room)) humanoid:setNextAction(self:createLeaveAction()) - humanoid:queueAction{name = "meander"} + humanoid:queueAction(MeanderAction()) return end @@ -230,19 +232,19 @@ -- unreserve whatever it was they we using local fx, fy = self:getEntranceXY(true) local objects = self.world:findAllObjectsNear(fx,fy) - for object, value in pairs(objects) do + for object, _ in pairs(objects) do if object.reserved_for == humanoid then object:removeReservedUser() end end if humanoid.profile.is_consultant and humanoid == self.staff_member then - local humanoid = self.waiting_staff_member + local staff = self.waiting_staff_member self:setStaffMember(nil) - if humanoid then - humanoid.waiting_on_other_staff = nil + if staff then + staff.waiting_on_other_staff = nil self.waiting_staff_member = nil - self:commandEnteringStaff(humanoid) + self:commandEnteringStaff(staff) end end end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/ultrascan.lua corsix-th-0.62/CorsixTH/Lua/rooms/ultrascan.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/ultrascan.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/ultrascan.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -43,6 +43,9 @@ class "UltrascanRoom" (Room) +---@type UltrascanRoom +local UltrascanRoom = _G["UltrascanRoom"] + function UltrascanRoom:UltrascanRoom(...) self:Room(...) end @@ -50,22 +53,19 @@ function UltrascanRoom:commandEnteringPatient(patient) local staff = self.staff_member local ultrascan, pat_x, pat_y = self.world:findObjectNear(patient, "ultrascanner") - local orientation = ultrascan.object_type.orientations[ultrascan.direction] local stf_x, stf_y = ultrascan:getSecondaryUsageTile() - staff:setNextAction{name = "walk", x = stf_x, y = stf_y} - staff:queueAction{name = "idle", direction = ultrascan.direction == "north" and "west" or "north"} - patient:setNextAction{name = "walk", x = pat_x, y = pat_y} - patient:queueAction{ - name = "multi_use_object", - object = ultrascan, - use_with = staff, - after_use = --[[persistable:ultrascan_after_use]] function() - staff:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } + staff:setNextAction(WalkAction(stf_x, stf_y)) + staff:queueAction(IdleAction():setDirection(ultrascan.direction == "north" and "west" or "north")) + + patient:setNextAction(WalkAction(pat_x, pat_y)) + + local after_use_scan = --[[persistable:ultrascan_after_use]] function() + staff:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + patient:queueAction(MultiUseObjectAction(ultrascan, staff):setAfterUse(after_use_scan)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/ward.lua corsix-th-0.62/CorsixTH/Lua/rooms/ward.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/ward.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/ward.lua 2018-07-21 11:13:17.000000000 +0000 @@ -50,6 +50,9 @@ class "WardRoom" (Room) +---@type WardRoom +local WardRoom = _G["WardRoom"] + function WardRoom:WardRoom(...) self:Room(...) self.staff_member_set = {} @@ -60,7 +63,7 @@ local objects = self.world:findAllObjectsNear(fx, fy) local beds = 0 local desks = 0 - for object, value in pairs(objects) do + for object, _ in pairs(objects) do if object.object_type.id == "bed" then beds = beds + 1 end @@ -91,41 +94,33 @@ function WardRoom:doStaffUseCycle(humanoid) local meander_time = math.random(4, 10) - local desk_use_time = math.random(8, 16) + humanoid:setNextAction(MeanderAction():setCount(meander_time)) - humanoid:setNextAction{ - name = "meander", - count = meander_time, - } local obj, ox, oy = self.world:findFreeObjectNearToUse(humanoid, "desk") - if obj then + if obj then obj.reserved_for = humanoid humanoid:walkTo(ox, oy) if obj.object_type.id == "desk" then local desk_use_time = math.random(7, 14) - humanoid:queueAction { - name = "use_object", - object = obj, - loop_callback = --[[persistable:ward_desk_loop_callback]] function() - desk_use_time = desk_use_time - 1 - if desk_use_time == 0 then - self:doStaffUseCycle(humanoid) + local desk_loop = --[[persistable:ward_desk_loop_callback]] function() + desk_use_time = desk_use_time - 1 + if desk_use_time == 0 then + self:doStaffUseCycle(humanoid) + end end - end, - } - end + humanoid:queueAction(UseObjectAction(obj):setLoopCallback(desk_loop)) + end end + local num_meanders = math.random(2, 4) - humanoid:queueAction { - name = "meander", - loop_callback = --[[persistable:ward_meander_loop_callback]] function(action) - num_meanders = num_meanders - 1 - if num_meanders == 0 then - self:doStaffUseCycle(humanoid) - end + local meanders_loop = --[[persistable:ward_meander_loop_callback]] function(action) + num_meanders = num_meanders - 1 + if num_meanders == 0 then + self:doStaffUseCycle(humanoid) end - } + end + humanoid:queueAction(MeanderAction():setLoopCallback(meanders_loop)) end @@ -154,13 +149,8 @@ self:dealtWithPatient(patient) end patient:walkTo(pat_x, pat_y) - patient:queueAction{ - name = "use_object", - object = bed, - prolonged_usage = true, - loop_callback = loop_callback, - after_use = after_use, - } + patient:queueAction(UseObjectAction(bed):setProlongedUsage(true):setLoopCallback(loop_callback) + :setAfterUse(after_use)) end return Room.commandEnteringPatient(self, patient) @@ -217,11 +207,10 @@ local map = self.world.map.th local flags = {} - local function checkLocation(x, y) - if self.world:getRoom(x, y) - or not map:getCellFlags(x, y, flags).passable then - local message = "Warning: An update has resolved a problem concerning " - .. "swing doors, but not all tiles adjacent to them could be fixed." + local function checkLocation(xpos, ypos) + if self.world:getRoom(xpos, ypos) or not map:getCellFlags(xpos, ypos, flags).passable then + local message = "Warning: An update has resolved a problem concerning " .. + "swing doors, but not all tiles adjacent to them could be fixed." self.world.ui:addWindow(UIInformation(self.world.ui, {message})) return false end @@ -260,7 +249,7 @@ local nurse = self.staff_member if nurse then nurse:setNextAction(self:createLeaveAction()) - nurse:queueAction({name = "meander"}) + nurse:queueAction(MeanderAction()) end end Room.afterLoad(self, old, new) diff -Nru corsix-th-0.30/CorsixTH/Lua/rooms/x_ray_room.lua corsix-th-0.62/CorsixTH/Lua/rooms/x_ray_room.lua --- corsix-th-0.30/CorsixTH/Lua/rooms/x_ray_room.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/rooms/x_ray_room.lua 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ ---[[ Copyright (c) 2009 Manuel Knig +--[[ Copyright (c) 2009 Manuel König Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -43,6 +43,9 @@ class "XRayRoom" (Room) +---@type XRayRoom +local XRayRoom = _G["XRayRoom"] + function XRayRoom:XRayRoom(...) self:Room(...) end @@ -53,42 +56,34 @@ local console, stf_x, stf_y = self.world:findObjectNear(staff, "radiation_shield") local --[[persistable:x_ray_shared_loop_callback]] function loop_callback() - if staff.action_queue[1].name == "idle" and patient.action_queue[1].name == "idle" then + if staff:getCurrentAction().name == "idle" and patient:getCurrentAction().name == "idle" then - local length = math.random(2, 4) * (2 - staff.profile.skill) - patient:setNextAction{ - name = "use_object", - object = x_ray, - loop_callback = --[[persistable:x_ray_loop_callback]] function(action) - if length <= 0 then - action.prolonged_usage = false - end - length = length - 1 - end, - after_use = --[[persistable:x_ray_after_use]] function() - staff:setNextAction{name = "meander"} - self:dealtWithPatient(patient) - end, - } - staff:setNextAction{ - name = "use_object", - object = console, - } + local length = math.random(2, 4) * (2 - staff.profile.skill) + local loop_callback_xray = --[[persistable:x_ray_loop_callback]] function(action) + if length <= 0 then + action.prolonged_usage = false + end + length = length - 1 + end + + local after_use_xray = --[[persistable:x_ray_after_use]] function() + staff:setNextAction(MeanderAction()) + self:dealtWithPatient(patient) + end + + patient:setNextAction(UseObjectAction(x_ray):setLoopCallback(loop_callback_xray) + :setAfterUse(after_use_xray)) + staff:setNextAction(UseObjectAction(console)) end end patient:walkTo(pat_x, pat_y) - patient:queueAction{ - name = "idle", - direction = x_ray.direction == "north" and "east" or "south", - loop_callback = loop_callback, - } + patient:queueAction(IdleAction():setDirection(x_ray.direction == "north" and "east" or "south") + :setLoopCallback(loop_callback)) + staff:walkTo(stf_x, stf_y) - staff:queueAction{ - name = "idle", - direction = console.direction == "north" and "east" or "south", - loop_callback = loop_callback, - } + staff:queueAction(IdleAction():setDirection(console.direction == "north" and "east" or "south") + :setLoopCallback(loop_callback)) return Room.commandEnteringPatient(self, patient) end diff -Nru corsix-th-0.30/CorsixTH/Lua/run_debugger.lua corsix-th-0.62/CorsixTH/Lua/run_debugger.lua --- corsix-th-0.30/CorsixTH/Lua/run_debugger.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/run_debugger.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,31 @@ +--- +-- This script is responsible for starting a DBGp client for CorsixTH's +-- Lua scripts and then connecting this to a running DBGp server. +-- +-- It does this in the function it returns. +--- +local function run() + print("NOTE: While CorsixTH is connected to an IDE's debugger server,") + print("text will be printed in its output console instead of here.") + + if not pcall(require, "socket") then + print("Can't connect debugger: LuaSocket is not available.") + return "Can't connect debugger: LuaSocket is not available." + end + + local _, config = corsixth.require("config_finder") + local connect = dofile("debugger") + + local successful, error_message = pcall(connect, config.DBGp_client_idehost, + config.DBGp_client_ideport, + config.DBGp_client_idekey, + config.DBGp_client_transport, + config.DBGp_client_platform, + config.DBGp_client_workingdir) + if not successful then + print("\nCan't connect DBGp client:\n" .. error_message .. "\n") + return "Failed to connect debugger, error printed in console." + end +end +return run + diff -Nru corsix-th-0.30/CorsixTH/Lua/sprite_viewer.lua corsix-th-0.62/CorsixTH/Lua/sprite_viewer.lua --- corsix-th-0.30/CorsixTH/Lua/sprite_viewer.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/sprite_viewer.lua 2018-07-21 11:13:17.000000000 +0000 @@ -22,9 +22,7 @@ -- when you don't have a copy of AnimView, or the means to compile it, then a -- crude sprite viewer is better than no sprite viewer. -local app = TheApp -local lfs = require"lfs" -local gfx = app.gfx +local gfx = TheApp.gfx gfx.cache.tabled = {} local font = gfx:loadFont("QData", "Font00V") local need_draw = true @@ -37,8 +35,8 @@ local y_off local old_event_handlers -for _, dir in ipairs{"Data", "QData", "DataM", "QDataM"} do - for item in pairs(app.fs:listFiles(dir) or {}) do +for _, dir in ipairs({"Data", "QData", "DataM", "QDataM"}) do + for item in pairs(TheApp.fs:listFiles(dir) or {}) do if item:match"%.TAB$" then sprite_table_paths[#sprite_table_paths + 1] = {dir, item:sub(1, -5)} end @@ -53,7 +51,7 @@ is_complex = complex local path = sprite_table_paths[n] local pal - if app.fs:readContents(path[1], path[2] .. ".PAL") then + if TheApp.fs:readContents(path[1], path[2] .. ".PAL") then pal = gfx:loadPalette(path[1], path[2] .. ".PAL") end sprite_table = gfx:loadSpriteTable(path[1], path[2], complex, pal) @@ -62,36 +60,38 @@ end LoadTable(1, false) -local function DoKey(self, code) - if code == string.byte"c" then +local function DoKey(self, rawchar, modifiers, is_repeat) + local key = rawchar:lower() + if key == "c" then gfx.cache.tabled = {} LoadTable(sprite_table_index, not is_complex) - elseif code == string.byte"a" then + elseif key == "a" then if sprite_table_index > 1 then LoadTable(sprite_table_index - 1, is_complex) end - elseif code == string.byte"d" then + elseif key == "d" then if sprite_table_index < #sprite_table_paths then LoadTable(sprite_table_index + 1, is_complex) end - elseif code == string.byte"w" then + elseif key == "w" then wdown = true need_draw = true - elseif code == string.byte"s" then + elseif key == "s" then sdown = true need_draw = true - elseif code == string.byte"q" then - app.eventHandlers = old_event_handlers + elseif key == "q" then + TheApp.eventHandlers = old_event_handlers need_draw = false end return need_draw end -local function DoKeyUp(self, code) - if code == string.byte"w" then +local function DoKeyUp(self, rawchar) + local key = rawchar:lower() + if key == "w" then wdown = false end - if code == string.byte"s" then + if key == "s" then sdown = false end end @@ -107,11 +107,11 @@ font:draw(canvas, msg, 0, y) y = y + fonth + sep local x = 0 - local sw, sh = app.config.width, app.config.height + local sw, sh = TheApp.config.width, TheApp.config.height local tallest = 0 for i = 0, #sprite_table - 1 do local w, h = sprite_table:size(i) - local lbl = "#" .. i .. " (" .. w .. "x" .. h ..")" + local lbl = "#" .. i .. " (" .. w .. "x" .. h .. ")" local lw = font:sizeOf(lbl) if lw > w then w = lw end h = h + fonth + sep @@ -152,8 +152,8 @@ return need_draw end -old_event_handlers = app.eventHandlers -app.eventHandlers = { +old_event_handlers = TheApp.eventHandlers +TheApp.eventHandlers = { frame = DoFrame, keydown = DoKey, keyup = DoKeyUp, diff -Nru corsix-th-0.30/CorsixTH/Lua/staff_profile.lua corsix-th-0.62/CorsixTH/Lua/staff_profile.lua --- corsix-th-0.30/CorsixTH/Lua/staff_profile.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/staff_profile.lua 2018-07-21 11:13:17.000000000 +0000 @@ -20,6 +20,9 @@ class "StaffProfile" +---@type StaffProfile +local StaffProfile = _G["StaffProfile"] + function StaffProfile:StaffProfile(world, humanoid_class, local_string) self.world = world self.humanoid_class = humanoid_class @@ -196,8 +199,10 @@ -- Update junior and consultant status function StaffProfile:parseSkillLevel() local level_config = self.world.map.level_config + local junior_skill = level_config.gbv.DoctorThreshold / 1000 - self.is_junior = self.skill <= junior_skill and 1 or nil + self.is_junior = self.skill <= junior_skill and 1 or nil + local consultant_skill = level_config.gbv.ConsultantThreshold / 1000 self.is_consultant = self.skill >= consultant_skill and 1 or nil end diff -Nru corsix-th-0.30/CorsixTH/Lua/strict.lua corsix-th-0.62/CorsixTH/Lua/strict.lua --- corsix-th-0.30/CorsixTH/Lua/strict.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/strict.lua 2018-07-21 11:13:17.000000000 +0000 @@ -62,7 +62,7 @@ function destrict(fn) return function(...) local ni, i = strict_mt.__newindex, strict_mt.__index - strict_mt.__newindex, strict_mt.__index = nil + strict_mt.__newindex, strict_mt.__index = nil, nil return restrict(ni, i, fn(...)) end end diff -Nru corsix-th-0.30/CorsixTH/Lua/string_extensions.lua corsix-th-0.62/CorsixTH/Lua/string_extensions.lua --- corsix-th-0.30/CorsixTH/Lua/string_extensions.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/string_extensions.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,9 +18,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local TH = require "TH" -local lpeg = require "lpeg" -local type = type +local TH = require("TH") +local lpeg = require("lpeg") local _unwrap = TH.stringProxy._unwrap function TH.stringProxy.gsub(str, patt, repl) @@ -66,13 +65,11 @@ args.idx = idx local arg, proxy_found = _unwrap(args[idx]) local t = type(arg) - if key == "%d" and t == "number" - -- NB: Numbers are allowed for %s as well to allow concatenation with number. - -- TODO the third check should really be class.is(arg, TH.stringProxy), but - -- it doesn't currently work due to TH.stringProxy overriding __index - or key == "%s" and (t == "string" - or t == "number" - or t == "userdata") then + if (key == "%d" and t == "number") or + -- NB: Numbers are allowed for %s as well to allow concatenation with number. + -- TODO the third check should really be class.is(arg, TH.stringProxy), but + -- it doesn't currently work due to TH.stringProxy overriding __index + (key == "%s" and (t == "string" or t == "number" or t == "userdata")) then if proxy_found then args.proxy_found = true end @@ -147,6 +144,6 @@ return result end -for _, method_name in ipairs{"gsub", "format", "find", "sub"} do - permanent("TH.stringProxy.".. method_name, TH.stringProxy[method_name]) +for _, method_name in ipairs({"gsub", "format", "find", "sub"}) do + permanent("TH.stringProxy." .. method_name, TH.stringProxy[method_name]) end diff -Nru corsix-th-0.30/CorsixTH/Lua/strings.lua corsix-th-0.62/CorsixTH/Lua/strings.lua --- corsix-th-0.30/CorsixTH/Lua/strings.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/strings.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,16 +18,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local lfs = require "lfs" -local TH = require "TH" -local type, loadfile, pcall, tostring, setfenv, setmetatable, math_random - = type, loadfile, pcall, tostring, setfenv, setmetatable, math.random -local rawset, rawget - = rawset, rawget +local lfs = require("lfs") +local TH = require("TH") --! Layer which handles the loading of localised text. class "Strings" +---@type Strings +local Strings = _G["Strings"] + function Strings:Strings(app) self.app = app end @@ -72,7 +71,7 @@ -- the default value of nil. local infinite_table_mt infinite_table_mt = { - __index = function(t, k) + __index = function(_, _) return setmetatable({}, infinite_table_mt) end } @@ -97,7 +96,7 @@ for _, name in pairs(names) do self.language_to_chunk[name:lower()] = chunk end - self.chunk_to_names[chunk] = names + self.chunk_to_names[chunk] = names error(good_error_marker) end, Font = function(...) @@ -112,7 +111,7 @@ }, infinite_table_mt) -- Actually run the language file local status, err = pcall(chunk, env) - if not status and err ~= good_error_marker and app.good_install_folder then + if not status and err ~= good_error_marker and TheApp.good_install_folder then print("Error evaluating " .. filename .. ":\n" .. tostring(err)) end end @@ -133,23 +132,23 @@ -- "__random" to each table (which always resolves to a random string from -- the table), and to prevent editing or adding to a string table. local strings_metatable = function(no_restriction) return { - __index = function(t, k) + __index = function(t, key) t = shadows[t] - local v = t[k] - if v ~= nil then - return v + local val = t[key] + if val ~= nil then + return val end - if k ~= "__random" then + if key ~= "__random" then if no_restriction then return nil end - error("Non-existant string: " .. tostring(k), 2) + error("Non-existant string: " .. tostring(key), 2) end local candidates = {} - for k, v in pairs(t) do + for _, v in pairs(t) do candidates[#candidates + 1] = v end - return candidates[math_random(1, #candidates)] + return candidates[math.random(1, #candidates)] end, - __newindex = function(t, k, v) + __newindex = function(_, _, _) error("String tables are read-only", 2) end, __pairs = function(t) @@ -203,13 +202,13 @@ end, -- Inherit() should evaluate the named language in the current environment -- NB: Inheritance of any but original_strings disabled when no_inheritance set - Inherit = function(language, ...) - if no_inheritance and language ~= "original_strings" then return end + Inherit = function(lang, ...) + if no_inheritance and lang ~= "original_strings" then return end local old_encoding = encoding encoding = default_encoding local old_language_called = language_called language_called = false - self:_loadPrivate(language, env, ...) + self:_loadPrivate(lang, env, ...) encoding = old_encoding language_called = old_language_called end, @@ -226,7 +225,7 @@ -- LoadStrings() should return the original game string table LoadStrings = function(filename) return assert(TH.LoadStrings(self.app:readDataFile(filename)), - "Cannot load original string file '"..filename.."'") + "Cannot load original string file '" .. filename .. "'") end, -- SetSpeechFile() should remember the named file to return to our caller SetSpeechFile = function(...) @@ -296,7 +295,7 @@ local chunk = self.language_to_chunk[language:lower()] if not chunk then -- If selected language could not be found, try to revert to English print_table(self.language_to_chunk) - print("Language '".. language .."' could not be found. Reverting to English.") + print("Language '" .. language .. "' could not be found. Reverting to English.") chunk = self.language_to_chunk["english"] if not chunk then -- If english could not be found, raise an error error("Language 'English' could not be found. Please verify your installation.") @@ -334,21 +333,21 @@ --cheats } local formatFunc - formatFunc = function(self, arg) + formatFunc = function(format_self, arg) -- After 'format', it is not useful to have indexing magic anymore. - return { text = self.text:format(arg), priority = self.priority } + return { text = format_self.text:format(arg), priority = format_self.priority } end local indexFunc - indexFunc = function(self, field) - -- Since prioTable is a partial table, self.table may disappear, prevent infinite recursion. + indexFunc = function(index_self, field) + -- Since prioTable is a partial table, index_self.table may disappear, prevent infinite recursion. if field == "table" then return nil end local val = {} - val.text = self.text[field] + val.text = index_self.text[field] val.format = formatFunc - val.table = self.table - val.priority = self.priority + val.table = index_self.table + val.priority = index_self.priority if val.table ~= nil then val.table = val.table[field] if val.table ~= nil and val.table._priority ~= nil then @@ -474,21 +473,21 @@ return string.char(codepoint) elseif codepoint <= 0x7FF then local sextet = codepoint % 64 - codepoint = (codepoint - sextet) / 64 + codepoint = math.floor((codepoint - sextet) / 64) return string.char(0xC0 + codepoint, 0x80 + sextet) elseif codepoint <= 0xFFFF then local sextet2 = codepoint % 64 - codepoint = (codepoint - sextet2) / 64 + codepoint = math.floor((codepoint - sextet2) / 64) local sextet1 = codepoint % 64 - codepoint = (codepoint - sextet2) / 64 + codepoint = math.floor((codepoint - sextet2) / 64) return string.char(0xE0 + codepoint, 0x80 + sextet1, 0x80 + sextet2) else local sextet3 = codepoint % 64 - codepoint = (codepoint - sextet3) / 64 + codepoint = math.floor((codepoint - sextet3) / 64) local sextet2 = codepoint % 64 - codepoint = (codepoint - sextet2) / 64 + codepoint = math.floor((codepoint - sextet2) / 64) local sextet1 = codepoint % 64 - codepoint = (codepoint - sextet2) / 64 + codepoint = math.floor((codepoint - sextet2) / 64) return string.char(0xF0 + codepoint, 0x80 + sextet1, 0x80 + sextet2, 0x80 + sextet3) end @@ -597,7 +596,7 @@ end codepoint = codepoint + (c:byte(1) % 2^(7 - #c)) * multiplier -- If the utf-8 character is a combining diacritical mark, merge it with the - -- preceeding normal character + -- preceding normal character if prechar and (0x300 <= codepoint and codepoint < 0x370) then if combine_diacritical_marks[prechar] then if combine_diacritical_marks[prechar][codepoint] then @@ -616,7 +615,7 @@ utf8conv = function(s) -- Pull out each individual utf-8 character and pass it through utf8char - -- [\1-\127] picks up a preceeding ASCII character to combine diacritics + -- [\1-\127] picks up a preceding ASCII character to combine diacritics -- [\192-\253] picks up the first byte of a utf-8 character (technically -- only 194 through 244 should be used) -- [\128-\191] picks up the remaining bytes of a utf-8 character @@ -641,10 +640,12 @@ case(0x94, 0x99) -- o-umlaut case(0xA4, 0xA5) -- n-tilde local case_pattern = "\195[\128-\191]" -- Unicode range [0xC0, 0xFF] as UTF-8 + local orig_upper = string.upper function string.upper(s) return orig_upper(s:gsub(case_pattern, lower_to_upper)) end + local orig_lower = string.lower function string.lower(s) return orig_lower(s:gsub(case_pattern, upper_to_lower)) diff -Nru corsix-th-0.30/CorsixTH/Lua/ui.lua corsix-th-0.62/CorsixTH/Lua/ui.lua --- corsix-th-0.30/CorsixTH/Lua/ui.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/ui.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,23 +18,25 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -dofile "window" +corsixth.require("window") --! Top-level container for all other user-interface components. class "UI" (Window) -local TH = require "TH" -local WM = require "sdl".wm -local SDL = require "sdl" -local lfs = require "lfs" -local pathsep = package.config:sub(1, 1) +---@type UI +local UI = _G["UI"] + +local TH = require("TH") +local SDL = require("sdl") +local WM = SDL.wm +local lfs = require("lfs") local function invert(t) local r = {} for k, v in pairs(t) do if type(v) == "table" then - for _, v in ipairs(v) do - r[v] = k + for _, val in ipairs(v) do + r[val] = k end else r[v] = k @@ -48,8 +50,8 @@ local button_remaps = {} local key_to_button_remaps = {} local key_norms = setmetatable({ - space = " ", - escape = "esc", + [" "] = "space", + esc = "escape", }, {__index = function(t, k) k = tostring(k):lower() return rawget(t, k) or k @@ -77,45 +79,33 @@ end end, } - setmetatable(env, {__index = function(t, k) + setmetatable(env, {__index = function(_, k) return k end}) result(env) end end - self.key_codes = { - backspace = 8, - delete = 127, - esc = 27, - up = 273, - down = 274, - right = 275, - left = 276, - x = 120, - z = 122, - f1 = 282, - f2 = 283, - f3 = 284, - f4 = 285, - f5 = 286, - f6 = 287, - f7 = 288, - f8 = 289, - f9 = 290, - f10 = 291, - f11 = 292, - f12 = 293, - enter = 13, - home = 278, - end_key = 279, - shift = {303, 304}, - ctrl = {305, 306}, - alt = {307, 308, 313}, + local keypad = { + ["Keypad 0"] = "insert", + ["Keypad 1"] = "end", + ["Keypad 2"] = "down", + ["Keypad 3"] = "pagedown", + ["Keypad 4"] = "left", + ["Keypad 6"] = "right", + ["Keypad 7"] = "home", + ["Keypad 8"] = "up", + ["Keypad 9"] = "pageup", + ["Keypad ."] = "delete", } + + -- Apply keypad remapping + for k, v in pairs(keypad) do + key_remaps[key_norms[k]] = key_norms[v] + end + self.key_remaps = key_remaps self.key_to_button_remaps = key_to_button_remaps - self.key_codes = invert(self.key_codes) self.button_codes = { left = 1, @@ -150,8 +140,6 @@ self.screen_offset_x = 0 self.screen_offset_y = 0 self.cursor = nil - self.cursor_x = 0 - self.cursor_y = 0 self.cursor_entity = nil self.debug_cursor_entity = nil -- through trial and error, this palette seems to give the desired result (white background, black text) @@ -178,10 +166,7 @@ } -- Windows can tell UI to pass specific codes forward to them. See addKeyHandler and removeKeyHandler self.key_handlers = {} - self.key_code_to_rawchar = {} - self.keyboard_repeat_enable_count = 0 - SDL.modifyKeyboardRepeat(0, 0) self.down_count = 0 if not minimal then self.default_cursor = app.gfx:loadMainCursor("default") @@ -248,32 +233,48 @@ self:setupGlobalKeyHandlers() end +function UI:runDebugScript() + print("Executing Debug Script...") + local path_sep = package.config:sub(1, 1) + local lua_dir = debug.getinfo(1, "S").source:sub(2, -8) + _ = TheApp.ui and TheApp.ui.debug_cursor_entity + local script = assert(loadfile(lua_dir .. path_sep .. "debug_script.lua")) + script() +end + function UI:setupGlobalKeyHandlers() -- Add some global keyhandlers - self:addKeyHandler("esc", self, self.closeWindow) - self:addKeyHandler("esc", self, self.stopMovie) - self:addKeyHandler(" ", self, self.stopMovie) + self:addKeyHandler("escape", self, self.closeWindow) + self:addKeyHandler("escape", self, self.stopMovie) + self:addKeyHandler("space", self, self.stopMovie) self:addKeyHandler({"ctrl", "s"}, self, self.makeScreenshot) - self:addKeyHandler({"alt", "enter"}, self, self.toggleFullscreen) + self:addKeyHandler({"alt", "return"}, self, self.toggleFullscreen) + self:addKeyHandler({"alt", "keypad enter"}, self, self.toggleFullscreen) self:addKeyHandler({"alt", "f4"}, self, self.exitApplication) self:addKeyHandler({"shift", "f10"}, self, self.resetApp) + self:addKeyHandler({"ctrl", "f10"}, self, self.toggleCaptureMouse) - if self.app.config.debug then - self:addKeyHandler("f12", self, self.showLuaConsole) + self:addOrRemoveDebugModeKeyHandlers() +end + +function UI:connectDebugger() + local error_message = TheApp:connectDebugger() + if error_message then + self:addWindow(UIInformation(self, {error_message})) end end -- Used for everything except music and announcements -function UI:playSound(name) +function UI:playSound(name, played_callback, played_callback_delay) if self.app.config.play_sounds then - self.app.audio:playSound(name) + self.app.audio:playSound(name, nil, false, played_callback, played_callback_delay) end end -- Used for announcements only -function UI:playAnnouncement(name) +function UI:playAnnouncement(name, played_callback, played_callback_delay) if self.app.config.play_announcements then - self.app.audio:playSound(name, nil, true) + self.app.audio:playSound(name, nil, true, played_callback, played_callback_delay) end end @@ -326,17 +327,16 @@ function UI:draw(canvas) local app = self.app - local config = app.config if self.background then local bg_w, bg_h = self.background_width, self.background_height local screen_w, screen_h = app.config.width, app.config.height local factor = math.max(screen_w / bg_w, screen_h / bg_h) if canvas:scale(factor, "bitmap") or canvas:scale(factor) then - self.background:draw(canvas, (screen_w / factor - bg_w) / 2, (screen_h / factor - bg_h) / 2) + self.background:draw(canvas, math.floor((screen_w - bg_w * factor) / 2), math.floor((screen_h - bg_h * factor) / 2)) canvas:scale(1) else canvas:fillBlack() - self.background:draw(canvas, (screen_w - bg_w) / 2, (screen_h - bg_h) / 2) + self.background:draw(canvas, math.floor((screen_w - bg_w) / 2), math.floor((screen_h - bg_h) / 2)) end end Window.draw(self, canvas, 0, 0) @@ -393,23 +393,6 @@ end end --- Enables a keyboard repeat. --- Default is 500 delay, interval 30 -function UI:enableKeyboardRepeat(delay, interval) - self.keyboard_repeat_enable_count = self.keyboard_repeat_enable_count + 1 - SDL.modifyKeyboardRepeat(delay or nil, interval or nil) -end - --- Disables the keyboard repeat. -function UI:disableKeyboardRepeat() - if self.keyboard_repeat_enable_count <= 1 then - self.keyboard_repeat_enable_count = 0 - SDL.modifyKeyboardRepeat(0, 0) - else - self.keyboard_repeat_enable_count = self.keyboard_repeat_enable_count - 1 - end -end - local menu_bg_sizes = { -- Available menu background sizes {1920, 1080}, } @@ -427,6 +410,9 @@ self:setMenuBackground() end -- Inform windows of resolution change + if not self.windows then + return + end for _, window in ipairs(self.windows) do window:onChangeResolution() end @@ -443,42 +429,23 @@ break end end - -- If the textbox was active at time of unregistering, disable keyboard repeat - if box.active then - self:disableKeyboardRepeat() - end -end - -function UI:resetVideo() - local width, height = self.app.config.width, self.app.config.height - - self.app.video:endFrame() - self.app.video = TH.surface(width, height, unpack(self.app.modes)) - self.app.gfx:updateTarget(self.app.video) - self.app.video:startFrame() - -- Redraw cursor - local cursor = self.cursor - self.cursor = nil - self:setCursor(cursor) end function UI:changeResolution(width, height) - local old_width, old_height = self.app.config.width, self.app.config.height - self.app.video:endFrame() - local video, error_message = TH.surface(width, height, unpack(self.app.modes)) - if video then - self.app.config.width = width - self.app.config.height = height - else - print("Warning: Could not change resolution to " .. width .. "x" .. height .. ". Reverting to previous resolution.") + self.app:prepareVideoUpdate() + local error_message = self.app.video:update(width, height, unpack(self.app.modes)) + self.app:finishVideoUpdate() + + if error_message then + print("Warning: Could not change resolution to " .. width .. "x" .. height .. ".") print("The error was: ") print(error_message) - video = TH.surface(old_width, old_height, unpack(self.app.modes)) return false end - self.app.video = video - self.app.gfx:updateTarget(self.app.video) - self.app.video:startFrame() + + self.app.config.width = width + self.app.config.height = height + -- Redraw cursor local cursor = self.cursor self.cursor = nil @@ -491,6 +458,11 @@ return true end +function UI:toggleCaptureMouse() + self.app.capturemouse = not self.app.capturemouse + self.app.video:setCaptureMouse(self.app.capturemouse) +end + function UI:toggleFullscreen() local modes = self.app.modes @@ -515,92 +487,43 @@ -- Toggle Fullscreen mode toggleMode(index) - self.app.video:endFrame() - self.app.moviePlayer:deallocatePictureBuffer(); local success = true - local video = TH.surface(self.app.config.width, self.app.config.height, unpack(modes)) - if not video then + self.app:prepareVideoUpdate() + local error_message = self.app.video:update(self.app.config.width, self.app.config.height, unpack(modes)) + self.app:finishVideoUpdate() + + if error_message then success = false local mode_string = modes[index] or "windowed" print("Warning: Could not toggle to " .. mode_string .. " mode with resolution of " .. self.app.config.width .. "x" .. self.app.config.height .. ".") -- Revert fullscreen mode modifications toggleMode(index) - video = TH.surface(self.app.config.width, self.app.config.height, unpack(self.app.modes)) end - self.app.video = video -- Apply changes - self.app.gfx:updateTarget(self.app.video) - self.app.moviePlayer:allocatePictureBuffer(); - self.app.video:startFrame() -- Redraw cursor local cursor = self.cursor self.cursor = nil self:setCursor(cursor) - -- Save new setting in config - self.app.config.fullscreen = self.app.fullscreen - self.app:saveConfig() + if success then + -- Save new setting in config + self.app.config.fullscreen = self.app.fullscreen + self.app:saveConfig() + end return success end -function UI:_translateKeyCode(code, rawchar) - local key = self.key_codes[code] or rawchar:lower() - return self.key_remaps[key] or key -end - ---! Table with chars and corresponding chars when shift is pressed (qwerty keyboard layout) -local workaround_shift = { - ["1"] = "!", - ["2"] = "@", - ["3"] = "#", - ["4"] = "$", - ["5"] = "%", - ["6"] = "^", - ["7"] = "&", - ["8"] = "*", - ["9"] = "(", - ["0"] = ")", - ["-"] = "_", - ["="] = "+", - ["["] = "{", - ["]"] = "}", - [";"] = ":", - ["'"] = "\"", - ["\\"] = "|", - [","] = "<", - ["."] = ">", - ["/"] = "?", -} - --! Called when the user presses a key on the keyboard ---!param code (integer) The hardware key-code for the pressed key. Note that --- these codes only coincide with ASCII for certain keyboard layouts. ---!param rawchar (string) The unicode character corresponding to the pressed --- key, encoded as UTF8 in a Lua string (for non-character keys, this value is --- "\0"). This value is affected by shift/caps-lock keys, but is not affected --- by any key-remappings. -function UI:onKeyDown(code, rawchar) - -- Workaround bad SDL implementations and/or old binaries - if rawchar == nil or rawchar == "\0" then - if code < 128 then - rawchar = string.char(code) - if self.buttons_down.shift then - if 97 <= code and code <= 122 then -- letters - rawchar = rawchar:upper() - else - rawchar = workaround_shift[rawchar] or rawchar - end - end - end - end - -- Remember the raw character associated with the code, as when the key is - -- released, we only get given the code. - self.key_code_to_rawchar[code] = rawchar - +--!param rawchar (string) The name of the key the user pressed. +--!param is_repeat (boolean) True if this is a key repeat event +function UI:onKeyDown(rawchar, modifiers, is_repeat) + local handled = false -- Apply key-remapping and normalisation - local key = self.key_codes[code] or rawchar:lower() + rawchar = string.sub(rawchar,1,6) == "Keypad" and + modifiers["numlockactive"] and string.sub(rawchar,8) or rawchar + local key = rawchar:lower() do local mapped_button = self.key_to_button_remaps[key] if mapped_button then @@ -610,51 +533,46 @@ key = self.key_remaps[key] or key end - -- If there is one, the current textbox gets the key + -- Remove numlock modifier + modifiers["numlockactive"] = nil + + -- If there is one, the current textbox gets the key. + -- It will not process any text at this point though. for _, box in ipairs(self.textboxes) do - if box.enabled and box.active then - local handled = box:input(key, rawchar, code) - if handled then - return true - end + if box.enabled and box.active and not handled then + handled = box:keyInput(key, rawchar) end end -- Otherwise, if there is a key handler bound to the given key, then it gets -- the key. - - -- For some reason the rawchar used above is not good if Ctrl is being pressed - local key_down = key - if self.buttons_down.ctrl and code < 128 then - key_down = string.char(code) - end - - local keyHandlers = self.key_handlers[key_down] - if keyHandlers then - -- Iterate over key handlers and call each one whose modifier(s) are pressed - -- NB: Only if the exact correct modifiers are pressed will the shortcut get processed. - local handled = false - for _, handler in ipairs(keyHandlers) do - if compare_tables(handler.modifiers, self.buttons_down) then - handler.callback(handler.window, unpack(handler)) - handled = true + if not handled then + local keyHandlers = self.key_handlers[key] + if keyHandlers then + -- Iterate over key handlers and call each one whose modifier(s) are pressed + -- NB: Only if the exact correct modifiers are pressed will the shortcut get processed. + for _, handler in ipairs(keyHandlers) do + if compare_tables(handler.modifiers, modifiers) then + handler.callback(handler.window, unpack(handler)) + handled = true + end end end - if handled then - return true - end end self.buttons_down[key] = true + self.modifiers_down = modifiers + self.key_press_handled = handled + return handled end --! Called when the user releases a key on the keyboard ---!param code (integer) The hardware key-code for the pressed key. Note that --- these codes only coincide with ASCII for certain keyboard layouts. -function UI:onKeyUp(code) - local rawchar = self.key_code_to_rawchar[code] or "" - self.key_code_to_rawchar[code] = nil - local key = self.key_codes[code] or rawchar:lower() +--!param rawchar (string) The name of the key the user pressed. +function UI:onKeyUp(rawchar) + rawchar = SDL.getKeyModifiers().numlockactive and + string.sub(rawchar,1,6) == "Keypad" and string.sub(rawchar,8) or + rawchar + local key = rawchar:lower() do local mapped_button = self.key_to_button_remaps[key] if mapped_button then @@ -666,6 +584,37 @@ self.buttons_down[key] = nil end +function UI:onEditingText(text, start, length) + -- Does nothing at the moment. We are handling text input ourselves. +end + +--! Called in-between onKeyDown and onKeyUp. The argument 'text' is a +--! string containing the input localized according to the keyboard layout +--! the user uses. +function UI:onTextInput(text) + -- It's time for any active textbox to get input. + for _, box in ipairs(self.textboxes) do + if box.enabled and box.active then + box:textInput(text) + end + end + + -- Finally it might happen that a hotkey was not recognized because of + -- differing local keyboard layout. Give it another shot. + if not self.key_press_handled then + local keyHandlers = self.key_handlers[text] + if keyHandlers then + -- Iterate over key handlers and call each one whose modifier(s) are pressed + -- NB: Only if the exact correct modifiers are pressed will the shortcut get processed. + for _, handler in ipairs(keyHandlers) do + if compare_tables(handler.modifiers, self.modifiers_down) then + handler.callback(handler.window, unpack(handler)) + end + end + end + end +end + function UI:onMouseDown(code, x, y) local repaint = false local button = self.button_codes[code] or code @@ -675,8 +624,8 @@ end return true end - if self.cursor_entity == nil and self.down_count == 0 - and self.cursor == self.default_cursor then + if self.cursor_entity == nil and self.down_count == 0 and + self.cursor == self.default_cursor then self:setCursor(self.down_cursor) repaint = true end @@ -705,8 +654,7 @@ if Window.onMouseUp(self, button, x, y) then repaint = true else - if self.cursor_entity and self.cursor_entity.onClick - and self.app.world.user_actions_allowed then + if self:ableToClickEntity(self.cursor_entity) then self.cursor_entity:onClick(self, button) repaint = true end @@ -716,6 +664,25 @@ return repaint end +function UI:onMouseWheel(x, y) + Window.onMouseWheel(self, x, y) +end + +--[[ Determines if a cursor entity can be clicked +@param entity (Entity,nil) cursor entity clicked on if any +@return true if can be clicked on, false otherwise (boolean) ]] +function UI:ableToClickEntity(entity) + if self.cursor_entity and self.cursor_entity.onClick then + local hospital = entity.hospital + local epidemic = hospital and hospital.epidemic + + return self.app.world.user_actions_allowed and not epidemic or + (epidemic and not epidemic.vaccination_mode_active) + else + return false + end +end + function UI:getScreenOffset() return self.screen_offset_x, self.screen_offset_y end @@ -748,6 +715,15 @@ function UI:onWindowActive(gain) end +--! Window has been resized by the user +--!param width (integer) New window width +--!param height (integer) New window height +function UI:onWindowResize(width, height) + if not self.app.config.fullscreen then + self:changeResolution(width, height) + end +end + function UI:onMouseMove(x, y, dx, dy) local repaint = UpdateCursorPosition(self.app.video, x, y) @@ -794,7 +770,7 @@ end self.modal_windows[window.modal_class] = window end - if window.modal_class == "main" or window.modal_class == "fullscreen" then + if window.modal_class == "main" or window.modal_class == "fullscreen" then self.editing_allowed = false -- do not allow editing rooms if main windows (build, furnish, hire) are open end Window.addWindow(self, window) @@ -827,29 +803,34 @@ return x, y end +function UI:addOrRemoveDebugModeKeyHandlers() + self:removeKeyHandler({"ctrl", "c"}, self) + self:removeKeyHandler("f12", self) + self:removeKeyHandler({"shift", "d"}, self) + if self.app.config.debug then + self:addKeyHandler({"ctrl", "c"}, self, self.connectDebugger) + self:addKeyHandler("f12", self, self.showLuaConsole) + self:addKeyHandler({"shift", "d"}, self, self.runDebugScript) + end +end + function UI:afterLoad(old, new) if old < 5 then self.editing_allowed = true end - if old < 13 then - self.key_code_to_rawchar = {} - end if old < 63 then -- modifiers have been added to key handlers - for key, handlers in pairs(self.key_handlers) do + for _, handlers in pairs(self.key_handlers) do for _, handler in ipairs(handlers) do handler.modifiers = {} end end -- some global key shortcuts were converted to use keyHandlers + self:removeKeyHandler("f12", self) + self:removeKeyHandler({"shift", "d"}, self) self:setupGlobalKeyHandlers() end - -- disable keyboardrepeat after loading a game just in case - -- (might be transferred from before loading, or broken savegame) - repeat - self:disableKeyboardRepeat() - until self.keyboard_repeat_enable_count == 0 if old < 70 then self:removeKeyHandler("f10", self) self:addKeyHandler({"shift", "f10"}, self, self.resetApp) @@ -860,6 +841,19 @@ self:removeKeyHandler({"alt", "f4"}, self, self.quit) self:addKeyHandler({"alt", "f4"}, self, self.exitApplication) end + + if old < 100 then + self:removeKeyHandler({"alt", "enter"}, self) + self:addKeyHandler({"alt", "return"}, self, self.toggleFullscreen) + end + if old < 104 then + self:addKeyHandler({"alt", "keypad enter"}, self, self.toggleFullscreen) + end + + if old < 118 then + self:addKeyHandler({"ctrl", "f10"}, self, self.toggleCaptureMouse) + end + Window.afterLoad(self, old, new) end @@ -888,6 +882,10 @@ --! Closes one window (the topmost / active window, if possible) --!return true iff a window was closed function UI:closeWindow() + if not self.windows then + return false + end + -- Close the topmost window first local first = self.windows[1] if first.on_top and first.esc_closes then diff -Nru corsix-th-0.30/CorsixTH/Lua/utility.lua corsix-th-0.62/CorsixTH/Lua/utility.lua --- corsix-th-0.30/CorsixTH/Lua/utility.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/utility.lua 2018-07-21 11:13:17.000000000 +0000 @@ -32,7 +32,7 @@ local function f() local value = root_table local nkey = 1 - for i, part in ipairs(wildcard_parts) do + for _, part in ipairs(wildcard_parts) do if part == "*" then local key = keys[nkey] if nkey >= #keys then @@ -72,11 +72,11 @@ -- Helper function to print the contents of a table. Child tables are printed recursively. -- Call without specifying level, only obj and (if wished) max_level. function print_table(obj, max_level, level) - assert(type(obj) == "table", "Tried to print ".. tostring(obj) .." with print_table.") + assert(type(obj) == "table", "Tried to print " .. tostring(obj) .. " with print_table.") pt_reflist[#pt_reflist + 1] = obj level = level or 0 local spacer = "" - for i = 1, level do + for _ = 1, level do spacer = spacer .. " " end for k, v in pairs(obj) do @@ -128,29 +128,29 @@ local result = f:read(4) if result == "\239\187\191#" then -- UTF-8 BOM plus Unix Shebang - result = f:read"*a":gsub("^[^\r\n]*", "", 1) + result = f:read("*a"):gsub("^[^\r\n]*", "", 1) elseif result:sub(1, 3) == "\239\187\191" then -- UTF-8 BOM - result = result:sub(4,4) .. f:read"*a" + result = result:sub(4,4) .. f:read("*a") elseif result:sub(1, 1) == "#" then -- Unix Shebang - result = (result .. f:read"*a"):gsub("^[^\r\n]*", "", 1) + result = (result .. f:read("*a")):gsub("^[^\r\n]*", "", 1) else -- Normal - result = result .. f:read"*a" + result = result .. f:read("*a") end f:close() - return loadstring_envcall(result, "@".. filename) + return loadstring_envcall(result, "@" .. filename) end -if rawget(_G, "loadin") then +if _G._VERSION == "Lua 5.2" or _G._VERSION == "Lua 5.3" then function loadstring_envcall(contents, chunkname) - -- Lua 5.2 lacks setfenv(), but does provide loadin() - -- loadin() still only allows a chunk to have an environment set once, so + -- Lua 5.2+ lacks setfenv() + -- load() still only allows a chunk to have an environment set once, so -- we give it an empty environment and use __[new]index metamethods on it -- to allow the same effect as changing the actual environment. local env_mt = {} - local result, err = loadin(setmetatable({}, env_mt), contents, chunkname) + local result, err = load(contents, chunkname, "bt", setmetatable({}, env_mt)) if result then return function(env, ...) env_mt.__index = env @@ -261,7 +261,7 @@ if t2[k] ~= v then return false end end local count2 = 0 - for k, v in pairs(t2) do + for _, _ in pairs(t2) do count2 = count2 + 1 end if count1 ~= count2 then return false end @@ -271,8 +271,44 @@ -- Convert a list to a set function list_to_set(list) local set = {} - for i, v in ipairs(list) do + for _, v in ipairs(list) do set[v] = true end return set end + +--! Find the smallest bucket with its upper value less or equal to a given number, +--! and return the value of the bucket, or its index. +--!param number (number) Value to accept by the bucket. +--!param buckets (list) Available buckets, pairs of {upper=x, value=y} tables, +-- in increasing x value, where nil is taken as infinite. The y value is +-- returned for the first bucket in the list where number <= x. If y is nil, +-- the index of the bucket in the list is returned. +--!return (number) Value or index of the matching bucket. +function rangeMapLookup(number, buckets) + for index, bucket in ipairs(buckets) do + if not bucket.upper or bucket.upper >= number then + return bucket.value or index + end + end + assert(false) -- Should never get here. +end + +-- this is a pseudo bitwise OR operation +-- assumes value2 is always a power of 2 (limits carry errors in the addition) +-- mimics the logic of hasBit with the addition if bit not set +--!param value1 (int) value to check set bit of +--!param value2 (int) power of 2 value - bit enumeration +--!return (int) value1 and value2 'bitwise' or. +function bitOr(value1, value2) + return value1 % (value2 + value2) >= value2 and value1 or value1 + value2 +end + +--! Check bit is set +--!param value (int) value to check set bit of +--!param bit (int) 0-base index of bit to check +--!return (boolean) true if bit is set. +function hasBit(value, bit) + local p = 2 ^ bit + return value % (p + p) >= p +end diff -Nru corsix-th-0.30/CorsixTH/Lua/walls/external.lua corsix-th-0.62/CorsixTH/Lua/walls/external.lua --- corsix-th-0.30/CorsixTH/Lua/walls/external.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/walls/external.lua 2018-07-21 11:13:17.000000000 +0000 @@ -24,17 +24,21 @@ north = 122, north_window_1 = 124, north_window_2 = 126, + north_expansion = 144, west = 123, west_window_1 = 127, west_window_2 = 125, + west_expansion = 145, } wall.outside_tiles = { north = 114, north_window_1 = 116, north_window_2 = 118, + north_expansion = 142, west = 115, west_window_1 = 119, west_window_2 = 117, + west_expansion = 143, } wall.window_tiles = { } diff -Nru corsix-th-0.30/CorsixTH/Lua/window.lua corsix-th-0.62/CorsixTH/Lua/window.lua --- corsix-th-0.30/CorsixTH/Lua/window.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/window.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,11 +18,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -dofile "persistance" +corsixth.require("persistance") --! Base class for user-interface dialogs. class "Window" +---@type Window +local Window = _G["Window"] + -- NB: pressed mouse buttons are denoted with a "mouse_" prefix in buttons_down, -- i.e. mouse_left, mouse_middle, mouse_right Window.buttons_down = permanent"Window.buttons_down" {} @@ -30,6 +33,10 @@ function Window:Window() self.x = 0 self.y = 0 + + self.cursor_x = 0 + self.cursor_y = 0 + self.panels = { } self.buttons = { @@ -124,6 +131,12 @@ self.key_handlers[key] = true end +--!param keys (string or table) The key or a list containing the key & its modifiers, +-- previously passed to Window:addKeyHandler(keys). +function Window:removeKeyHandler(keys) + self.ui:removeKeyHandler(keys, self) +end + --! The basic component which makes up most `Window`s. --! The visual parts of most ingame dialogs are sprites from a sprite sheet. -- A `Panel` is an instance of a particular sprite, consisting of a sprite @@ -133,6 +146,9 @@ -- thus reducing the amount of work that each individual dialog has to do. class "Panel" +---@type Panel +local Panel = _G["Panel"] + -- !dummy function Panel:Panel() self.window = nil @@ -223,7 +239,7 @@ --!param label (string) The text to be drawn on top of the label. --!param font (font) [optional] The font to use. Default is Font01V in QData. --!param align (string) [optional] Alignment for non-multiline labels (multiline is always left) ---! can be either of "left", "center"/"centre"/"middle", "right" +--! can be either of "left", "center", "right" function Panel:setLabel(label, font, align) self.label = label or "" self.label_font = font or self.label_font or TheApp.gfx:loadFont("QData", "Font01V") @@ -301,16 +317,28 @@ return next_y, last_x end +--! Set the position of a panel. +--!param x (int) New horizontal position of the panel. +--!param y (int) New vertical position of the panel. function Panel:setPosition(x, y) self.x = x self.y = y end +--! Set the size of a panel. +--!param width (int) New width of the panel. +--!param height (int) New height of the panel. function Panel:setSize(width, height) self.w = width self.h = height end +--! Set the visibility of the panel. +--!param visibility (bool) New visibility of the panel. +function Panel:setVisible(visibility) + self.visible = visibility +end + --[[ Add a `Panel` to the window. ! Panels form the basic building blocks of most windows. A panel is a small bitmap coupled with a position, and by combining several panels, a window can @@ -512,6 +540,9 @@ --! A region of a `Panel` which causes some action when clicked. class "Button" +---@type Button +local Button = _G["Button"] + --!dummy function Button:Button() self.ui = nil @@ -540,14 +571,17 @@ return self end +--! Enable or disable a button. +--!param enable (boolean) Whether to enable (true) or disable (false) the button. function Button:enable(enable) - if enable then + if enable and not self.enabled then self.enabled = true self.panel_for_sprite.sprite_index = self.sprite_index_normal if self.panel_for_sprite.colour_backup then self.panel_for_sprite.colour = self.panel_for_sprite.colour_backup end - else + end + if not enable and self.enabled then self.enabled = false self.panel_for_sprite.sprite_index = self.sprite_index_disabled if self.panel_for_sprite.disabled_colour then @@ -572,6 +606,7 @@ return self end +--! Flip the toggle state of the button (on -> off, or off -> on). function Button:toggle() self.sprite_index_normal, self.sprite_index_active = self.sprite_index_active, self.sprite_index_normal @@ -583,6 +618,8 @@ return self.toggled end +--! Set the toggle state of the button to the provided state. +--!param state (boolean) Desired state of the toggle button. function Button:setToggleState(state) if self.toggled ~= state then self:toggle() @@ -651,6 +688,9 @@ end end +--! Set the position of a button. +--!param x (int) New horizontal position of the button. +--!param y (int) New vertical position of the button. function Button:setPosition(x, y) self.panel_for_sprite:setPosition(x, y) self.r = self.r - self.x + x @@ -663,6 +703,9 @@ end end +--! Set the size of a button. +--!param width (int) New width of the button. +--!param height (int) New height of the button. function Button:setSize(width, height) self.panel_for_sprite:setSize(width, height) self.r = self.x + width @@ -673,6 +716,12 @@ end end +--! Set the visibility of the button. +--!param visibility (bool) New visibility of the button. +function Button:setVisible(visibility) + self.panel_for_sprite:setVisible(visibility) +end + --! Convenience function to allow setLabel to be called on a button, not only its panel. --! see Panel:setLabel function Button:setLabel(label, font, align) @@ -730,6 +779,9 @@ --! A window element used to scroll in lists class "Scrollbar" +---@type Scrollbar +local Scrollbar = _G["Scrollbar"] + --!dummy function Scrollbar:Scrollbar() self.base = nil @@ -760,11 +812,11 @@ if self.direction == "y" then slider.h = math.ceil((page_size / (max_value - min_value + 1)) * slider.max_h) slider.max_y = slider.min_y + slider.max_h - slider.h - slider.y = (value - min_value) / (max_value - min_value - page_size + 2) * (slider.max_y - slider.min_y) + slider.min_y + slider.y = math.floor((value - min_value) / (max_value - min_value - page_size + 2) * (slider.max_y - slider.min_y) + slider.min_y) else slider.w = math.ceil((page_size / (max_value - min_value + 1)) * slider.max_w) slider.max_x = slider.min_x + slider.max_w - slider.w - slider.x = (value - min_value) / (max_value - min_value - page_size + 2) * (slider.max_x - slider.min_x) + slider.min_x + slider.x = math.floor((value - min_value) / (max_value - min_value - page_size + 2) * (slider.max_x - slider.min_x) + slider.min_x) end return self @@ -836,6 +888,9 @@ --! A window element used to enter text class "Textbox" +---@type Textbox +local Textbox = _G["Textbox"] + --!dummy function Textbox:Textbox() self.panel = nil @@ -871,7 +926,11 @@ if self.cursor_state then local col = TheApp.video:mapRGB(255, 255, 255) local cursor_y, cursor_x = self.panel:drawLabel(nil, x, y, self.cursor_pos) - local w, h = self.panel.label_font:sizeOf("0") + local w, _ = self.panel.label_font:sizeOf("0") + if self.panel.align == nil or self.panel.align == "center" then + local _, text_x = self.panel:drawLabel(nil, x, y, {self.cursor_pos[1], #self.text}) + cursor_x = text_x - (text_x - cursor_x) * 2 + end cursor_y = cursor_y - 3 -- Add x separation, but only if there was actually some text in this line. if self.text[self.cursor_pos[1]] ~= "" then @@ -916,12 +975,8 @@ self.cursor_pos[2] = type(self.text) == "table" and string.len(self.text[#self.text]) or string.len(self.text) -- Update text self.panel:setLabel(self.text) - -- Enable Keyboard repeat - ui:enableKeyboardRepeat() else self.cursor_state = false - -- Disable Keyboard repeat - ui:disableKeyboardRepeat() end self.active = active @@ -944,7 +999,9 @@ end end -function Textbox:input(char, rawchar, code) +--! Handles special characters such as Enter. Normal text input is processed in the textInput function. +--! Note though that this function still returns true if it appears to be a characters being entered. +function Textbox:keyInput(char, rawchar) if not self.active then return false end @@ -956,31 +1013,22 @@ if not self.char_limit or string.len(line) < self.char_limit then -- Upper- and lowercase letters if self.allowed_input.alpha then - if #rawchar == 1 and (("a" <= rawchar and rawchar <= "z") - or ("A" <= rawchar and rawchar <= "Z")) then + if #char == 1 and string.match(char, '%a') then handled = true end end -- Numbers if not handled and self.allowed_input.numbers then - if 256 <= code and code <= 265 then - -- Numeric keypad - rawchar = string.char(string.byte"0" + code - 256) - end - if #rawchar == 1 and "0" <= rawchar and rawchar <= "9" then + if #char == 1 and string.match(char, '%d') then handled = true end end - -- Space and hyphen + -- Space, hyphen and plus sign if not handled and self.allowed_input.misc then - if rawchar == " " or rawchar == "-" then + if char == "space" or char == "-" or char == "+" then handled = true end end - if handled then - new_line = line:sub(1, self.cursor_pos[2]) .. rawchar .. line:sub(self.cursor_pos[2] + 1, -1) - self.cursor_pos[2] = self.cursor_pos[2] + 1 - end end -- Backspace (delete last char, or last word if ctrl is pressed) if not handled and char == "backspace" then @@ -993,8 +1041,9 @@ end else local pos = self.cursor_pos[2] - 1 - if ui.buttons_down.ctrl then - pos = string.find(string.sub(line, 1, self.cursor_pos[2]), "[^"..pat.."]["..pat.."]+[^"..pat.."]*$") or 0 + if ui.app.key_modifiers.ctrl then + pos = string.find(string.sub(line, 1, self.cursor_pos[2]), + "[^" .. pat .. "][" .. pat .. "]+[^" .. pat .. "]*$") or 0 end new_line = line:sub(1, pos) .. line:sub(self.cursor_pos[2] + 1, -1) self.cursor_pos[2] = pos @@ -1010,15 +1059,16 @@ end else local pos = self.cursor_pos[2] + 2 - if ui.buttons_down.ctrl then - pos = (string.find(line, "[^"..pat.."]["..pat.."]", self.cursor_pos[2] + 1) or string.len(line)) + 1 + if ui.app.key_modifiers.ctrl then + pos = (string.find(line, "[^" .. pat .. "][" .. pat .. "]", + self.cursor_pos[2] + 1) or string.len(line)) + 1 end new_line = line:sub(1, self.cursor_pos[2]) .. line:sub(pos, -1) end handled = true end -- Enter (newline or confirm) - if not handled and char == "enter" then + if not handled and (char == "return" or char == "enter") then if type(self.text) == "table" then local remainder = line:sub(self.cursor_pos[2] + 1, -1) self.text[self.cursor_pos[1]] = line:sub(1, self.cursor_pos[2]) @@ -1032,13 +1082,13 @@ end end -- Escape (abort) - if not handled and char == "esc" then + if not handled and char == "escape" then self:abort() return true end - -- Arrow keys (code >= 273 and code <= 276) - if not handled and code >= 273 and code <= 276 then - if code == 273 then -- up + -- Arrow keys + if not handled then + if char == "up" then -- up if type(self.text) ~= "table" or self.cursor_pos[1] == 1 then -- to beginning of line self.cursor_pos[2] = 0 @@ -1047,7 +1097,8 @@ self.cursor_pos[1] = self.cursor_pos[1] - 1 self.cursor_pos[2] = math.min(self.cursor_pos[2], string.len(self.text[self.cursor_pos[1]])) end - elseif code == 274 then -- down + handled = true + elseif char == "down" then -- down if type(self.text) ~= "table" or self.cursor_pos[1] == #self.text then -- to end of line self.cursor_pos[2] = string.len(line) @@ -1056,7 +1107,8 @@ self.cursor_pos[1] = self.cursor_pos[1] + 1 self.cursor_pos[2] = math.min(self.cursor_pos[2], string.len(self.text[self.cursor_pos[1]])) end - elseif code == 275 then -- right + handled = true + elseif char == "right" then -- right if self.cursor_pos[2] == string.len(line) then -- next line if type(self.text) == "table" and self.cursor_pos[1] < #self.text then @@ -1064,15 +1116,17 @@ self.cursor_pos[2] = 0 end else - if ui.buttons_down.ctrl then + if ui.app.key_modifiers.ctrl then -- to the right until next word or end of line - self.cursor_pos[2] = string.find(line, "[^"..pat.."]["..pat.."]", self.cursor_pos[2] + 1) or string.len(line) + self.cursor_pos[2] = string.find(line, "[^" .. pat .. "][" .. pat .. "]", + self.cursor_pos[2] + 1) or string.len(line) else -- one to the right self.cursor_pos[2] = self.cursor_pos[2] + 1 end end - elseif code == 276 then -- left + handled = true + elseif char == "left" then -- left if self.cursor_pos[2] == 0 then -- previous line if type(self.text) == "table" and self.cursor_pos[1] > 1 then @@ -1080,20 +1134,21 @@ self.cursor_pos[2] = string.len(self.text[self.cursor_pos[1]]) end else - if ui.buttons_down.ctrl then + if ui.app.key_modifiers.ctrl then -- to the left until beginning of word or beginning of line - self.cursor_pos[2] = string.find(string.sub(line, 1, self.cursor_pos[2]), "[^"..pat.."]["..pat.."]+[^"..pat.."]*$") or 0 + self.cursor_pos[2] = string.find(string.sub(line, 1, self.cursor_pos[2]), + "[^" .. pat .. "][" .. pat .. "]+[^" .. pat .. "]*$") or 0 else -- one to the left self.cursor_pos[2] = self.cursor_pos[2] - 1 end end + handled = true end - handled = true end -- Tab (reserved) - if not handled and code == 9 then - return true + if not handled and char == "tab" then + handled = true end -- Home (beginning of line) if not handled and char == "home" then @@ -1101,17 +1156,14 @@ handled = true end -- End (end of line) - if not handled and char == "end_key" then + if not handled and char == "end" then self.cursor_pos[2] = string.len(line) handled = true end if not self.char_limit or string.len(self.text) < self.char_limit then -- Experimental "all" category - if not handled and self.allowed_input.all - and not (char == "shift" or char == "ctrl" or char == "alt") - and not (282 <= code and code <= 293) then -- F-Keys - new_line = line:sub(1, self.cursor_pos[2]) .. rawchar .. line:sub(self.cursor_pos[2] + 1, -1) - self.cursor_pos[2] = self.cursor_pos[2] + 1 + if not handled and self.allowed_input.all and + not (char == "shift" or char == "ctrl" or char == "alt") then -- F-Keys handled = true end end @@ -1121,13 +1173,33 @@ else self.text = new_line end + -- update label + self.panel:setLabel(self.text) end -- make cursor visible self.cursor_counter = 0 self.cursor_state = true + return handled +end + +--! Handles actual text input. +function Textbox:textInput(text) + if not self.active then + return false + end + + local line = type(self.text) == "table" and self.text[self.cursor_pos[1]] or self.text + local new_line = line:sub(1, self.cursor_pos[2]) .. text .. line:sub(self.cursor_pos[2] + 1, -1) + self.cursor_pos[2] = self.cursor_pos[2] + #text + + if type(self.text) == "table" then + self.text[self.cursor_pos[1]] = new_line + else + self.text = new_line + end + -- update label self.panel:setLabel(self.text) - return handled end --[[ Limit input handled by textbox to specific classes of characters @@ -1262,14 +1334,14 @@ end function Window:hitTestPanel(x, y, panel) - local x, y = x - panel.x, y - panel.y - if panel.visible and x >= 0 and y >= 0 then + local xpos, ypos = x - panel.x, y - panel.y + if panel.visible and xpos >= 0 and ypos >= 0 then if panel.w and panel.h then - if x <= panel.w and y <= panel.h then + if xpos <= panel.w and ypos <= panel.h then return true end else - if self.panel_sprites:hitTest(panel.sprite_index, x, y) then + if self.panel_sprites:hitTest(panel.sprite_index, xpos, ypos) then return true end end @@ -1419,6 +1491,19 @@ return repaint end +function Window:onMouseWheel(x, y) + local repaint = false + if self.windows then + for _, window in ipairs(self.windows) do + if window:onMouseWheel(x, y) then + repaint = true + break -- Scroll has been handled. No need to look any further. + end + end + end + return repaint +end + local --[[persistable:window_drag_position_representation]] function getNicestPositionRepresentation(pos, size, dim_size) if size == dim_size then return 0.5 @@ -1448,8 +1533,8 @@ !param y The Y position of the cursor in window co-ordinatees. ]] function Window:beginDrag(x, y) - if not self.width or not self.height or not self.ui - or self.ui.app.runtime_config.lock_windows or not self.draggable then + if not self.width or not self.height or not self.ui or + self.ui.app.runtime_config.lock_windows or not self.draggable then -- Need width, height and UI to do a drag return false end @@ -1461,7 +1546,7 @@ sy = sy - y -- Calculate best positioning local w, h = TheApp.config.width, TheApp.config.height - if self.buttons_down.ctrl then + if TheApp.key_modifiers.ctrl then local px = round(sx / (w - self.width), 0.1) local py = round(sy / (h - self.height), 0.1) if px >= 1 then @@ -1494,6 +1579,10 @@ ]] function Window:onMouseMove(x, y, dx, dy) local repaint = false + + self.cursor_x = x + self.cursor_y = y + if self.windows then for _, window in ipairs(self.windows) do if window:onMouseMove(x - window.x, y - window.y, dx, dy) then @@ -1512,12 +1601,12 @@ else self.active_button.active = false btn.panel_for_sprite.lowered = btn.panel_lowered_normal - for _, btn in ipairs(self.buttons) do - if btn.enabled and btn.x <= x and x < btn.r and btn.y <= y and y < btn.b then - btn.panel_for_sprite.sprite_index = btn.sprite_index_active - btn.active = true - btn.panel_for_sprite.lowered = btn.panel_lowered_active - self.active_button = btn + for _, button in ipairs(self.buttons) do + if button.enabled and button.x <= x and x < button.r and button.y <= y and y < button.b then + button.panel_for_sprite.sprite_index = button.sprite_index_active + button.active = true + button.panel_for_sprite.lowered = button.panel_lowered_active + self.active_button = button repaint = true break end @@ -1629,7 +1718,6 @@ -- Tell the window to bring the specified sub-window to its bottom function Window:sendToBottom(window) - local window_index if self.windows then for i = 1, #self.windows do -- Search specified window in windows list if self.windows[i] == window then @@ -1706,11 +1794,11 @@ else text = elem.text end - local x, y = elem.tooltip_x, elem.tooltip_y - if x then x = x + self.x end -- NB: can be nil, then it means position at mouse cursor - if y then y = y + self.y end + local xpos, ypos = elem.tooltip_x, elem.tooltip_y + if xpos then xpos = xpos + self.x end -- NB: can be nil, then it means position at mouse cursor + if ypos then ypos = ypos + self.y end if text then - return { text = text, x = x, y = y } + return { text = text, x = xpos, y = ypos } end end diff -Nru corsix-th-0.30/CorsixTH/Lua/world.lua corsix-th-0.62/CorsixTH/Lua/world.lua --- corsix-th-0.30/CorsixTH/Lua/world.lua 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Lua/world.lua 2018-07-21 11:13:17.000000000 +0000 @@ -18,22 +18,29 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local pathsep = package.config:sub(1, 1) local TH = require"TH" local ipairs, _G, table_remove = ipairs, _G, table.remove -dofile "entities/patient" -dofile "entities/staff" -dofile "entities/vip" -dofile "staff_profile" -dofile "hospital" -dofile "calls_dispatcher" -dofile "research_department" +corsixth.require("entities.patient") +corsixth.require("entities.staff") +corsixth.require("entities.vip") +corsixth.require("entities.grim_reaper") +corsixth.require("entities.inspector") +corsixth.require("staff_profile") +corsixth.require("hospital") +corsixth.require("epidemic") +corsixth.require("calls_dispatcher") +corsixth.require("research_department") +corsixth.require("entity_map") +corsixth.require("date") --! Manages entities, rooms, and the date. class "World" +---@type World +local World = _G["World"] + local local_criteria_variable = { {name = "reputation", icon = 10, formats = 2}, {name = "balance", icon = 11, formats = 2}, @@ -44,6 +51,11 @@ {name = "population", icon = 11, formats = 1}, } +-- time between each damage caused by an earthquake +local earthquake_damage_time = 16 -- hours +local earthquake_warning_period = 600 -- hours between warning and real thing +local earthquake_warning_length = 25 -- length of early warning quake + function World:World(app) self.map = app.map self.wall_types = app.walls @@ -52,7 +64,7 @@ self.animation_manager = app.animation_manager self.pathfinder = TH.pathfinder() self.pathfinder:setMap(app.map.th) - self.entities = {} + self.entities = {} -- List of entities in the world. self.dispatcher = CallsDispatcher(self) self.objects = {} self.object_counts = { @@ -65,16 +77,25 @@ } self.objects_notify_occupants = {} self.rooms = {} -- List that can have gaps when a room is deleted, so use pairs to iterate. + self.entity_map = EntityMap(self.map) + + -- All information relating to the next or current earthquake, nil if + -- there is no scheduled earthquake. + -- Contains the following fields: + -- active (boolean) Whether we are currently running the warning or damage timers (after start_day of start_month is passed). + -- start_month (integer) The month the earthquake warning is triggered. + -- start_day (integer) The day of the month the earthquake warning is triggered. + -- size (integer) The amount of damage the earthquake causes (1-9). + -- remaining_damage (integer) The amount of damage this earthquake has yet to inflict. + -- damage_timer (integer) The number of hours until the earthquake next inflicts damage if active. + -- warning_timer (integer) The number of hours left until the real damaging earthquake begins. + self.next_earthquake = { active = false } -- Time - self.hours_per_day = 50 self.hours_per_tick = 1 self.tick_rate = 3 self.tick_timer = 0 - self.year = 1 - self.month = 1 -- January - self.day = 1 - self.hour = 0 + self.game_date = Date() self.room_information_dialogs_off = app.config.debug -- This is false when the game is paused. @@ -92,7 +113,6 @@ self.idle_cache = {} -- List of which goal criterion means what, and what number the corresponding icon has. self.level_criteria = local_criteria_variable - self.room_build_callbacks = {--[[a set rather than a list]]} self.room_remove_callbacks = {--[[a set rather than a list]]} self.room_built = {} -- List of room types that have been built self.hospitals = {} @@ -102,37 +122,47 @@ -- Also preserve this throughout future updates. self.original_savegame_version = app.savegame_version - self:initLevel(app) - self.hospitals[1] = Hospital(self, app.config.player_name) -- Player's hospital - self:initCompetitors() - self:initRooms() - -- Now the hospitals can concentrate their research. - for i, hospital in ipairs(self.hospitals) do + -- Initialize available rooms. + local avail_rooms = self:getAvailableRooms() + self.available_rooms = {} -- Both a list and a set, use ipairs to iterate through the available rooms. + for _, avail_room in ipairs(avail_rooms) do + local room = avail_room.room + self.available_rooms[#self.available_rooms + 1] = room + self.available_rooms[room.id] = room + end + + -- Initialize available diseases and winning conditions. + self:initLevel(app, avail_rooms) + + self.hospitals[1] = Hospital(self, avail_rooms, app.config.player_name) -- Player's hospital + self:initCompetitors(avail_rooms) + for _, hospital in ipairs(self.hospitals) do hospital.research:setResearchConcentration() end -- TODO: Add (working) AI and/or multiplayer hospitals -- TODO: Needs to be changed for multiplayer support - self:initStaff() + self.hospitals[1]:initStaff() + self.wall_id_by_block_id = {} for _, wall_type in ipairs(self.wall_types) do - for _, set in ipairs{"inside_tiles", "outside_tiles", "window_tiles"} do - for name, id in pairs(wall_type[set]) do + for _, set in ipairs({"inside_tiles", "outside_tiles", "window_tiles"}) do + for _, id in pairs(wall_type[set]) do self.wall_id_by_block_id[id] = wall_type.id end end end self.wall_set_by_block_id = {} for _, wall_type in ipairs(self.wall_types) do - for _, set in ipairs{"inside_tiles", "outside_tiles", "window_tiles"} do - for name, id in pairs(wall_type[set]) do + for _, set in ipairs({"inside_tiles", "outside_tiles", "window_tiles"}) do + for _, id in pairs(wall_type[set]) do self.wall_set_by_block_id[id] = set end end end self.wall_dir_by_block_id = {} for _, wall_type in ipairs(self.wall_types) do - for _, set in ipairs{"inside_tiles", "outside_tiles", "window_tiles"} do + for _, set in ipairs({"inside_tiles", "outside_tiles", "window_tiles"}) do for name, id in pairs(wall_type[set]) do self.wall_dir_by_block_id[id] = name end @@ -146,8 +176,9 @@ self:makeAvailableStaff(0) self:calculateSpawnTiles() + -- Next Events dates self:nextEmergency() - self:nextVip() + self.next_vip_date = self:_generateNextVipDate() -- earthquakes -- current_map_earthquakes is a counter that tracks which number of earthquake @@ -171,7 +202,7 @@ self:gameLog("Created game with savegame version " .. self.savegame_version .. ".") end ---! Register key shortcuts for controling the world (game speed, etc.) +--! Register key shortcuts for controlling the world (game speed, etc.) function World:setUI(ui) self.ui = ui self.ui:addKeyHandler("P", self, self.pauseOrUnpause, "Pause") @@ -181,6 +212,8 @@ self.ui:addKeyHandler("4", self, self.setSpeed, "Max speed") self.ui:addKeyHandler("5", self, self.setSpeed, "And then some more") + self.ui:addKeyHandler("=", self, self.adjustZoom, 1) + self.ui:addKeyHandler({"shift", "="}, self, self.adjustZoom, 5) self.ui:addKeyHandler("+", self, self.adjustZoom, 1) self.ui:addKeyHandler({"shift", "+"}, self, self.adjustZoom, 5) self.ui:addKeyHandler("-", self, self.adjustZoom, -1) @@ -193,7 +226,7 @@ local virtual_width = scr_w / (self.ui.zoom_factor or 1) -- The modifier is a normal distribution to make it more difficult to zoom at the extremes - local modifier = math.exp(1)^(-((self.ui.zoom_factor-1)^2)/(2 * 1))/(math.sqrt(2*math.pi)*1) + local modifier = math.exp(-((self.ui.zoom_factor - 1) ^ 2) / 2) / math.sqrt(2 * math.pi) if modifier < 0.05 or modifier > 1 then modifier = 0.05 @@ -204,32 +237,50 @@ return false end - return self.ui:setZoom(scr_w/virtual_width) + return self.ui:setZoom(scr_w / virtual_width) end -function World:initLevel(app) - local level_config = self.map.level_config +--! Initialize the game level (available diseases, winning conditions). +--!param app Game application. +--!param avail_rooms (list) Available rooms in the level. +function World:initLevel(app, avail_rooms) + local existing_rooms = {} + for _, avail_room in ipairs(avail_rooms) do + existing_rooms[avail_room.room.id] = true + end + -- Determine available diseases self.available_diseases = {} + local level_config = self.map.level_config local visual = level_config.visuals local non_visual = level_config.non_visuals - local added_diseases = 0 - for i, disease in ipairs(app.diseases) do + for _, disease in ipairs(app.diseases) do if not disease.pseudo then + local vis_id = disease.visuals_id + local nonvis_id = disease.non_visuals_id + local vis = 1 - if visual and (visual[disease.visuals_id] or non_visual[disease.non_visuals_id]) then - vis = disease.visuals_id and visual[disease.visuals_id].Value - or non_visual[disease.non_visuals_id].Value + if visual and (visual[vis_id] or non_visual[nonvis_id]) then + vis = vis_id and visual[vis_id].Value or non_visual[nonvis_id].Value + end + if vis ~= 0 then + for _, room_id in ipairs(disease.treatment_rooms) do + if existing_rooms[room_id] == nil then + print("Warning: Removing disease \"" .. disease.id .. + "\" due to missing treatment room \"" .. room_id .. "\".") + vis = 0 -- Missing treatment room, disease cannot be treated. Remove it. + break + end + end end -- TODO: Where the value is greater that 0 should determine the frequency of the patients if vis ~= 0 then self.available_diseases[#self.available_diseases + 1] = disease self.available_diseases[disease.id] = disease - added_diseases = added_diseases + 1 end end end - if added_diseases == 0 and not _MAP_EDITOR then + if #self.available_diseases == 0 and not self.map.level_number == "MAP EDITOR" then -- No diseases are needed if we're actually in the map editor! print("Warning: This level does not contain any diseases") end @@ -241,60 +292,6 @@ self.room_information_dialogs_off = not self.room_information_dialogs_off end -function World:initStaff() - local level_config = self.map.level_config - local hosp = self.hospitals[1] - if level_config.start_staff then - local i = 0 - for n, conf in ipairs(level_config.start_staff) do - local profile - local skill = 0 - local added_staff = true - if conf.Skill then - skill = conf.Skill / 100 - end - - if conf.Nurse == 1 then - profile = StaffProfile(self, "Nurse", _S.staff_class["nurse"]) - profile:init(skill) - elseif conf.Receptionist == 1 then - profile = StaffProfile(self, "Receptionist", _S.staff_class["receptionist"]) - profile:init(skill) - elseif conf.Handyman == 1 then - profile = StaffProfile(self, "Handyman", _S.staff_class["handyman"]) - profile:init(skill) - elseif conf.Doctor == 1 then - profile = StaffProfile(self, "Doctor", _S.staff_class["doctor"]) - - local shrink = 0 - local rsch = 0 - local surg = 0 - local jr, cons - - if conf.Shrink == 1 then shrink = 1 end - if conf.Surgeon == 1 then surg = 1 end - if conf.Researcher == 1 then rsch = 1 end - - if conf.Junior == 1 then jr = 1 - elseif conf.Consultant == 1 then cons = 1 - end - profile:initDoctor(shrink,surg,rsch,jr,cons,skill) - else - added_staff = false - end - if added_staff then - local staff = self:newEntity("Staff", 2) - staff:setProfile(profile) - -- TODO: Make a somewhat "nicer" placing algorithm. - staff:setTile(self.map.th:getCameraTile(1)) - staff:onPlaceInCorridor() - hosp.staff[#hosp.staff + 1] = staff - staff:setHospital(hosp) - end - end - end -end - --! Load goals to win and lose from the map, and store them in 'self.goals'. --! Also set 'self.winning_goal_count'. function World:determineWinningConditions() @@ -360,64 +357,51 @@ self.winning_goal_count = winning_goal_count end -function World:initRooms() - -- Combination of set and list. Use ipairs to iterate through all available rooms. - self.available_rooms = {} - - local obj = self.map.level_config.objects - local rooms = self.map.level_config.rooms - for i, room in ipairs(TheApp.rooms) do +--! Find the rooms available at the level. +--!return (list) Available rooms, with discovery state at start, and build_cost. +function World:getAvailableRooms() + local avail_rooms = {} + + local cfg_objects = self.map.level_config.objects + local cfg_rooms = self.map.level_config.rooms + for _, room in ipairs(TheApp.rooms) do -- Add build cost based on level files for all rooms. -- For now, sum it up so that the result is the same as before. -- TODO: Change the whole build process so that this value is -- the room cost only? (without objects) - local build_cost = rooms[room.level_config_id].Cost + local build_cost = cfg_rooms[room.level_config_id].Cost local available = true local is_discovered = true -- Make sure that all objects needed for this room are available for name, no in pairs(room.objects_needed) do - local spec = obj[TheApp.objects[name].thob] + local spec = cfg_objects[TheApp.objects[name].thob] if spec.AvailableForLevel == 0 then -- It won't be possible to build this room at all on the level. available = false elseif spec.StartAvail == 0 then - -- Ok, it will be availabe at some point just not from the beginning. + -- Ok, it will be available at some point just not from the beginning. is_discovered = false end -- Add cost for this object. - build_cost = build_cost + obj[TheApp.objects[name].thob].StartCost * no + build_cost = build_cost + cfg_objects[TheApp.objects[name].thob].StartCost * no end - -- Now define the total build cost for the room. In free build mode nothing - -- costs anything. - for _, hospital in ipairs(self.hospitals) do - hospital.research.research_progress[room] = { - build_cost = not self.free_build_mode and build_cost or 0, - } - end - if available then - self.available_rooms[#self.available_rooms + 1] = room - self.available_rooms[room.id] = room - if is_discovered then - for _, hospital in ipairs(self.hospitals) do - hospital.discovered_rooms[room] = true - end - else - for _, hospital in ipairs(self.hospitals) do - hospital.undiscovered_rooms[room] = true - end - end + if available then + avail_rooms[#avail_rooms + 1] = {room = room, is_discovered = is_discovered, build_cost = build_cost} end end + return avail_rooms end -function World:initCompetitors() +--! Initialize competing hospitals +--!param avail_rooms (list) Available rooms in the level. +function World:initCompetitors(avail_rooms) -- Add computer players -- TODO: Right now they're only names local level_config = self.map.level_config for key, value in pairs(level_config.computer) do if value.Playing == 1 then - self.hospitals[#self.hospitals + 1] = AIHospital(tonumber(key) + 1, self) + self.hospitals[#self.hospitals + 1] = AIHospital(tonumber(key) + 1, self, avail_rooms) end end end @@ -437,22 +421,25 @@ end end +--! Get the hospital controlled by the (single) player. +--!return (Hospital) The hospital controlled by the (single) player. function World:getLocalPlayerHospital() -- NB: UI code can get the hospital to use via ui.hospital -- TODO: Make this work in multiplayer? return self.hospitals[1] end --- Identify the tiles on the map suitable for spawning `Humanoid`s from. +--! Identify the tiles on the map suitable for spawning `Humanoid`s from. function World:calculateSpawnTiles() self.spawn_points = {} local w, h = self.map.width, self.map.height - for _, edge in ipairs{ + local directions = { {direction = "north", origin = {1, 1}, step = { 1, 0}}, {direction = "east" , origin = {w, 1}, step = { 0, 1}}, {direction = "south", origin = {w, h}, step = {-1, 0}}, {direction = "west" , origin = {1, h}, step = { 0, -1}}, - } do + } + for _, edge in ipairs(directions) do -- Find all possible spawn points on the edge local xs = {} local ys = {} @@ -475,7 +462,40 @@ end end +--! Function to determine whether a given disease is available for new patients. +--!param self (World) World object. +--!param disease (disease) Disease to test. +--!param hospital (Hospital) Hospital that needs a new patient. +--!return (boolean) Whether the disease is usable for new spawned patients. +local function isDiseaseUsableForNewPatient(self, disease, hospital) + if disease.only_emergency then return false end + if not disease.visuals_id then return true end + + -- level files can delay visuals to a given month + -- and / or until a given number of patients have arrived + local level_config = self.map.level_config + local hold_visual_months = level_config.gbv.HoldVisualMonths + local hold_visual_peep_count = level_config.gbv.HoldVisualPeepCount + + -- if the month is greater than either of these values then visuals will not appear in the game + if (hold_visual_months and hold_visual_months > self.game_date:monthOfGame()) or + (hold_visual_peep_count and hold_visual_peep_count > hospital.num_visitors) then + return false + end + + -- The value against #visuals_available determines from which month a disease can appear. + -- 0 means it can show up anytime. + return level_config.visuals_available[disease.visuals_id].Value < self.game_date:monthOfGame() +end + +--! Spawn a patient from a spawn point for the given hospital. +--!param hospital (Hospital) Hospital that the new patient should visit. +--!return (Patient entity) The spawned patient, or 'nil' if no patient spawned. function World:spawnPatient(hospital) + if not hospital then + hospital = self:getLocalPlayerHospital() + end + -- The level might not contain any diseases if #self.available_diseases < 1 then self.ui:addWindow(UIInformation(self.ui, {"There are no diseases on this level! Please add some to your level."})) @@ -485,56 +505,41 @@ self.ui:addWindow(UIInformation(self.ui, {"Could not spawn patient because no spawn points are available. Please place walkable tiles on the edge of your level."})) return end - if not hospital then - hospital = self:getLocalPlayerHospital() - end - --! What is the current month? - local current_month = (self.year - 1) * 12 + self.month - --! level files can delay visuals to a given month - --! and / or until a given number of patients have arrived - local hold_visual_months = self.map.level_config.gbv.HoldVisualMonths - local hold_visual_peep_count = self.map.level_config.gbv.HoldVisualPeepCount - --! Function to determine whether a given disease is visible and available. - --!param disease (disease) Disease to test. - --!return (boolean) Whether the disease is visible and available. - local function isVisualDiseaseAvailable(disease) - if not disease.visuals_id then - return true - end - --! if the month is greater than either of these values then visuals will not appear in the game - if hold_visual_months and hold_visual_months > current_month or - hold_visual_peep_count and hold_visual_peep_count > hospital.num_visitors then - return false - end - --! the value against #visuals_available determines from which month a disease can appear. 0 means it can show up anytime. - local level_config = self.map.level_config - if level_config.visuals_available[disease.visuals_id].Value >= current_month then - return false + + if not hospital:hasStaffedDesk() then return nil end + + -- Construct disease, take a random guess first, as a quick clear-sky attempt. + local disease = self.available_diseases[math.random(1, #self.available_diseases)] + if not isDiseaseUsableForNewPatient(self, disease, hospital) then + -- Lucky shot failed, do a proper calculation. + local usable_diseases = {} + for _, d in ipairs(self.available_diseases) do + if isDiseaseUsableForNewPatient(self, d, hospital) then + usable_diseases[#usable_diseases + 1] = d + end end - return true - end - if hospital:hasStaffedDesk() then - local spawn_point = self.spawn_points[math.random(1, #self.spawn_points)] - local patient = self:newEntity("Patient", 2) - local disease = self.available_diseases[math.random(1, #self.available_diseases)] - while disease.only_emergency or not isVisualDiseaseAvailable(disease) do - disease = self.available_diseases[math.random(1, #self.available_diseases)] - end - patient:setDisease(disease) - patient:setNextAction{name = "spawn", mode = "spawn", point = spawn_point} - patient:setHospital(hospital) + if #usable_diseases == 0 then return nil end - return patient + disease = usable_diseases[math.random(1, #usable_diseases)] end + + -- Construct patient. + local spawn_point = self.spawn_points[math.random(1, #self.spawn_points)] + local patient = self:newEntity("Patient", 2) + patient:setDisease(disease) + patient:setNextAction(SpawnAction("spawn", spawn_point)) + patient:setHospital(hospital) + return patient end +--A VIP is invited (or he invited himself) to the player hospital. +--!param name Name of the VIP function World:spawnVIP(name) local hospital = self:getLocalPlayerHospital() - local spawn_point = self.spawn_points[math.random(1, #self.spawn_points)] local vip = self:newEntity("Vip", 2) - vip:setType "VIP" + vip:setType("VIP") vip.name = name vip.enter_deaths = hospital.num_deaths vip.enter_visitors = hospital.num_visitors @@ -543,147 +548,111 @@ vip.enter_explosions = hospital.num_explosions local spawn_point = self.spawn_points[math.random(1, #self.spawn_points)] - vip:setNextAction{name = "spawn", mode = "spawn", point = spawn_point} + vip:setNextAction(SpawnAction("spawn", spawn_point)) vip:setHospital(hospital) vip:updateDynamicInfo() hospital.announce_vip = hospital.announce_vip + 1 - vip:queueAction{name = "seek_reception"} -end - -function World:createEarthquake() - -- Sanity check - if not self.earthquake_size then - return false - end - - -- the bigger the earthquake, the longer it lasts. We add one - -- further day, as we use those to give a small earthquake first, - -- before the bigger one begins - local stop_day = math.round(self.earthquake_size / 3) + 1 - - -- make sure the user has at least two days of an earthquake - if stop_day < 2 then - stop_day = 2 - end - - -- store the offsets so we can not shake the user to some too distant location - self.currentX = self.ui.screen_offset_x - self.currentY = self.ui.screen_offset_y - - -- we add an extra 1 at the end because we register the start of earthquakes at the end of the day - self.earthquake_stop_day = self.day + stop_day + 1 - - -- if the day the earthquake is supposed to stop on a day greater than the length of the current month (eg 34) - if self.earthquake_stop_day > self:getCurrentMonthLength() then - -- subtract the current length of the month so the earthquake will stop at the start of the next month - self.earthquake_stop_day = self.earthquake_stop_day - self:getCurrentMonthLength() - end - - -- Prepare machines for getting damage - at most as much as the severity of the earthquake +-1 - for _, room in pairs(self.rooms) do - for object, value in pairs(room.objects) do - if object.strength then - object.quake_points = self.earthquake_size + math.random(-1, 1) - end - end - end - - -- set a flag to indicate that we are now having an earthquake - self.active_earthquake = true - return true + vip:queueAction(SeekReceptionAction()) end +--! Perform actions to simulate an active earthquake. function World:tickEarthquake() + if self:isCurrentSpeed("Pause") then return end + -- check if this is the day that the earthquake is supposed to stop - if (self.day == self.earthquake_stop_day) then - self.active_earthquake = false - self.ui.tick_scroll_amount = false - -- if the earthqake measured more than 7 on the richter scale, tell the user about it - if (self.earthquake_size > 7) then - self.ui.adviser:say(_A.earthquake.ended:format(math.floor(self.earthquake_size))) - end - -- Make sure that machines got all the damage they should get. - for _, room in pairs(self.rooms) do - for object, value in pairs(room.objects) do - if object.strength and object.quake_points then - while object.quake_points > 0 do - object:machineUsed(room) - object.quake_points = object.quake_points - 1 - end - end - end + if self.next_earthquake.remaining_damage == 0 then + self.next_earthquake.active = false + self.ui:endShakeScreen() + -- if the earthquake measured more than 7 on the richter scale, tell the user about it + if self.next_earthquake.size > 7 then + self.ui.adviser:say(_A.earthquake.ended:format(math.floor(self.next_earthquake.size))) end -- set up the next earthquake date self:nextEarthquake() else - -- Multiplier for how much the screen moves around during the quake. - local multi = 4 - if (self.day > self.earthquake_stop_day) or (self.day < math.round(self.earthquake_size / 3)) then - -- if we are in the first two days of the earthquake, make it smaller - self.randomX = math.random(-(self.earthquake_size/2)*multi, (self.earthquake_size/2)*multi) - self.randomY = math.random(-(self.earthquake_size/2)*multi, (self.earthquake_size/2)*multi) - else - -- otherwise, hit the user with the full earthquake - self.randomX = math.random(-self.earthquake_size*multi, self.earthquake_size*multi) - self.randomY = math.random(-self.earthquake_size*multi, self.earthquake_size*multi) - end + local announcements = { + "quake001.wav", "quake002.wav", "quake003.wav", "quake004.wav", + } - -- if the game is not paused - if not self:isCurrentSpeed("Pause") then - -- Play the earthquake sound. It has different names depending on language used though. - if TheApp.audio:soundExists("quake2.wav") then - self.ui:playSound("quake2.wav") - else - self.ui:playSound("quake.wav") + -- start of warning quake + if self.next_earthquake.warning_timer == earthquake_warning_period then + self.ui:beginShakeScreen(0.2) + self.ui:playAnnouncement(announcements[math.random(1, #announcements)]) + end + + -- end of warning quake + if self.next_earthquake.warning_timer >= earthquake_warning_period - earthquake_warning_length and + self.next_earthquake.warning_timer - self.hours_per_tick < earthquake_warning_period - earthquake_warning_length then + self.ui:endShakeScreen() + end + + if self.next_earthquake.warning_timer > 0 then + self.next_earthquake.warning_timer = self.next_earthquake.warning_timer - self.hours_per_tick + -- nothing more to do during inactive warning period + if self.next_earthquake.warning_timer < earthquake_warning_period - earthquake_warning_length then + return end - -- shake the screen randomly to give the appearance of an earthquake - -- the greater the earthquake, the more the screen will shake - - -- restrict the amount the earthquake can shift the user left and right - if self.ui.screen_offset_x > (self.currentX + 600) then - if self.randomX > 0 then - self.randomX = -self.randomX - end - elseif self.ui.screen_offset_x < (self.currentX - 600) then - if self.randomX < 0 then - self.randomX = -self.randomX - end + -- start of real earthquake + if self.next_earthquake.warning_timer <= 0 then + self.ui:playAnnouncement(announcements[math.random(1, #announcements)]) end + end - -- restrict the amount the earthquake can shift the user up and down - if self.ui.screen_offset_y > (self.currentY + 600) then - if self.randomY > 0 then - self.randomY = -self.randomY - end - elseif self.ui.screen_offset_y < (self.currentY - 600) then - if self.randomY < 0 then - self.randomY = -self.randomY - end - end + -- All earthquakes start and end small (small earthquakes never become + -- larger), so when there has been less than 2 damage applied or only + -- 2 damage remaining to be applied, move the screen with less + -- intensity than otherwise. + if self.next_earthquake.remaining_damage <= 2 or + self.next_earthquake.size - self.next_earthquake.remaining_damage <= 2 then + self.ui:beginShakeScreen(0.5) + else + self.ui:beginShakeScreen(1) + end - self.ui.tick_scroll_amount = {x = self.randomX, y = self.randomY} + -- Play the earthquake sound. It has different names depending on language used though. + if TheApp.audio:soundExists("quake2.wav") then + self.ui:playSound("quake2.wav") + else + self.ui:playSound("quake.wav") + end - local hospital = self:getLocalPlayerHospital() - -- loop through the patients and allow the possibilty for them to fall over - for _, patient in ipairs(hospital.patients) do - local current = patient.action_queue[1] + -- do not continue to damage phase while in a warning quake + if self.next_earthquake.warning_timer > 0 then + return + end - if not patient.in_room and patient.falling_anim then + self.next_earthquake.damage_timer = self.next_earthquake.damage_timer - self.hours_per_tick + if self.next_earthquake.damage_timer <= 0 then + for _, room in pairs(self.rooms) do + for object, _ in pairs(room.objects) do + if object.strength then + object:machineUsed(room) + end + end + end - -- make the patients fall + self.next_earthquake.remaining_damage = self.next_earthquake.remaining_damage - 1 + self.next_earthquake.damage_timer = self.next_earthquake.damage_timer + earthquake_damage_time + end - -- jpirie: this is currently disabled. Calling this function - -- really screws up the action queue, sometimes the patients - -- end up with nil action queues, and sometimes the resumed - -- actions throw exceptions. Also, patients in the hospital - -- who have not yet found reception throw exceptions after - -- they visit reception. Some debugging needed here to get - -- this working. + local hospital = self:getLocalPlayerHospital() + -- loop through the patients and allow the possibility for them to fall over + for _, patient in ipairs(hospital.patients) do + if not patient.in_room and patient.falling_anim then + + -- make the patients fall + + -- jpirie: this is currently disabled. Calling this function + -- really screws up the action queue, sometimes the patients + -- end up with nil action queues, and sometimes the resumed + -- actions throw exceptions. Also, patients in the hospital + -- who have not yet found reception throw exceptions after + -- they visit reception. Some debugging needed here to get + -- this working. - -- patient:falling() - end + -- patient:falling() end end end @@ -701,8 +670,8 @@ } function World:makeAvailableStaff(month) local conf_entry = 0 - local conf = self.map.level_config.staff_levels - while conf[conf_entry + 1] and conf[conf_entry + 1].Month <= month do + local cfg_staff_levels = self.map.level_config.staff_levels + while cfg_staff_levels[conf_entry + 1] and cfg_staff_levels[conf_entry + 1].Month <= month do conf_entry = conf_entry + 1 end self.available_staff = {} @@ -711,7 +680,7 @@ local ind = conf_entry while not num do assert(ind >= 0, "Staff amount " .. info.conf .. " not existent (should at least be given by base_config).") - num = conf[ind][info.conf] + num = cfg_staff_levels[ind][info.conf] ind = ind - 1 end local group = {} @@ -729,7 +698,7 @@ !param y (integer) The 1-based Y co-ordinate of the tile to monitor. !param object (Object) Something with an `onOccupantChange` method, which will be called whenever a `Humanoid` enters or leaves the given tile. The method -will recieve one argument (after `self`), which will be `1` for an enter event +will receive one argument (after `self`), which will be `1` for an enter event and `-1` for a leave event. ]] function World:notifyObjectOfOccupants(x, y, object) @@ -768,8 +737,11 @@ until true end end +--! Change owner of a plot. +--!param parcel (int) Plot to change. +--!param owner (int) New owner (may be 0). function World:setPlotOwner(parcel, owner) - self.map.th:setPlotOwner(parcel, owner) + self.map:setPlotOwner(parcel, owner) if owner ~= 0 and self.delayed_map_objects then for info, p in pairs(self.delayed_map_objects) do if p == parcel then @@ -785,19 +757,6 @@ return self.animation_manager:getAnimLength(anim) end --- Register a function to be called whenever a room is built. ---!param callback (function) A function taking one argument: a `Room`. -function World:registerRoomBuildCallback(callback) - self.room_build_callbacks[callback] = true -end - --- Unregister a function from being called whenever a room is built. ---!param callback (function) A function previously passed to --- `registerRoomBuildCallback`. -function World:unregisterRoomBuildCallback(callback) - self.room_build_callbacks[callback] = nil -end - -- Register a function to be called whenever a room has been deactivated (crashed or edited). --!param callback (function) A function taking one argument: a `Room`. function World:registerRoomRemoveCallback(callback) @@ -816,8 +775,7 @@ -- Note: Room IDs will be unique, but they may not form continuous values -- from 1, as IDs of deleted rooms may not be re-issued for a while local class = room_info.class and _G[room_info.class] or Room - -- TODO: Take hospital based on the owner of the plot the room is built on - local hospital = self.hospitals[1] + local hospital = self:getHospital(x, y) local room = class(x, y, w, h, id, room_info, self, hospital, ...) self.rooms[id] = room @@ -825,15 +783,18 @@ return room end ---! Called when a room has been completely built and is ready to use +--! Called when a room has been completely built and is ready to use. +--!param room (Room) The new room. function World:markRoomAsBuilt(room) room:roomFinished() local diag_disease = self.hospitals[1].disease_casebook["diag_" .. room.room_info.id] if diag_disease and not diag_disease.discovered then self.hospitals[1].disease_casebook["diag_" .. room.room_info.id].discovered = true end - for callback in pairs(self.room_build_callbacks) do - callback(room) + for _, entity in ipairs(self.entities) do + if entity.notifyNewRoom then + entity:notifyNewRoom(room) + end end end @@ -890,7 +851,7 @@ } function World:getDate() - return self.month, self.day + return self.game_date:monthOfYear(), self.game_date:dayOfMonth() end -- Game speeds. The second value is the number of world clicks that pass for each @@ -906,11 +867,6 @@ ["Speed Up"] = {4, 1}, } --- Return the length of the current month -function World:getCurrentMonthLength() - return month_length[self.month] -end - function World:speedUp() self:setSpeed("Speed Up") end @@ -945,23 +901,39 @@ end if speed == "Pause" then -- stop screen shaking if there was an earthquake in progress - if self.active_earthquake then - self.ui.tick_scroll_amount = {x = 0, y = 0} + if self.next_earthquake.active then + self.ui:endShakeScreen() end -- By default actions are not allowed when the game is paused. self.user_actions_allowed = TheApp.config.allow_user_actions_while_paused elseif self:getCurrentSpeed() == "Pause" then self.user_actions_allowed = true end - self.prev_speed = self:getCurrentSpeed() + + local currentSpeed = self:getCurrentSpeed() + if currentSpeed ~= "Pause" and currentSpeed ~= "Speed Up" then + self.prev_speed = self:getCurrentSpeed() + end + + local was_paused = currentSpeed == "Pause" local numerator, denominator = unpack(tick_rates[speed]) self.hours_per_tick = numerator self.tick_rate = denominator + + if was_paused then + TheApp.audio:onEndPause() + end + -- Set the blue filter according to whether the user can build or not. TheApp.video:setBlueFilterActive(not self.user_actions_allowed) + return false +end + +function World:isPaused() + return self:isCurrentSpeed("Pause") end --- Dedicated function to allow unpausing by pressing 'p' again +--! Dedicated function to allow unpausing by pressing 'p' again function World:pauseOrUnpause() if not self:isCurrentSpeed("Pause") then self:setSpeed("Pause") @@ -987,9 +959,11 @@ 4.75 / 50, -- December } --- World ticks are translated to game ticks (or hours) depending on the +--! World ticks are translated to game ticks (or hours) depending on the -- current speed of the game. There are 50 hours in a TH day. function World:onTick() + if self.map.level_number == "MAP EDITOR" then return end + if self.tick_timer == 0 then if self.autosave_next_tick then self.autosave_next_tick = nil @@ -1001,36 +975,30 @@ if not lfs.attributes(dir .. "Autosaves", "modification") then lfs.mkdir(dir .. "Autosaves") end - local status, err = pcall(TheApp.save, TheApp, "Autosaves" .. pathsep .. "Autosave" .. self.month .. ".sav") + local status, err = pcall(TheApp.save, TheApp, dir .. "Autosaves" .. pathsep .. "Autosave" .. self.game_date:monthOfYear() .. ".sav") if not status then print("Error while autosaving game: " .. err) end end - if self.year == 1 and self.month == 1 and self.day == 1 and self.hour == 0 then - if not self.ui.start_tutorial then - self.ui:addWindow(UIWatch(self.ui, "initial_opening")) - self.ui:showBriefing() - end + if self.game_date == Date() and not self.ui.start_tutorial then + self.ui:addWindow(UIWatch(self.ui, "initial_opening")) + self.ui:showBriefing() end self.tick_timer = self.tick_rate - self.hour = self.hour + self.hours_per_tick - -- if an earthqake is supposed to be going on, call the earthquake function - if self.active_earthquake then + -- if an earthquake is supposed to be going on, call the earthquake function + if self.next_earthquake.active then self:tickEarthquake() end - + local new_game_date = self.game_date:plusHours(self.hours_per_tick) -- End of day/month/year - if self.hour >= self.hours_per_day then + if self.game_date:dayOfMonth() ~= new_game_date:dayOfMonth() then for _, hospital in ipairs(self.hospitals) do hospital:onEndDay() end self:onEndDay() - self.hour = self.hour - self.hours_per_day - self.day = self.day + 1 - if self.day > month_length[self.month] then - self.day = month_length[self.month] + if self.game_date:isLastDayOfMonth() then for _, hospital in ipairs(self.hospitals) do hospital:onEndMonth() end @@ -1039,32 +1007,26 @@ -- Bail out as the game has already been ended. return end - self.day = 1 - self.month = self.month + 1 - if self.month > 12 then - self.month = 12 - if self.year == 1 then - for _, hospital in ipairs(self.hospitals) do - hospital.initial_grace = false - end - end + + if self.game_date:isLastDayOfYear() then -- It is crucial that the annual report gets to initialize before onEndYear is called. -- Yearly statistics are reset there. self.ui:addWindow(UIAnnualReport(self.ui, self)) self:onEndYear() - self.year = self.year + 1 - self.month = 1 end end end + self.game_date = new_game_date + for i = 1, self.hours_per_tick do for _, hospital in ipairs(self.hospitals) do hospital:tick() end -- A patient might arrive to the player hospital. -- TODO: Multiplayer support. - if self.spawn_hours[self.hour + i-1] and self.hospitals[1].opened then - for k=1, self.spawn_hours[self.hour + i-1] do + local spawn_count = self.spawn_hours[self.game_date:hourOfDay() + i - 1] + if spawn_count and self.hospitals[1].opened then + for _ = 1, spawn_count do self:spawnPatient() end end @@ -1076,8 +1038,8 @@ end self.current_tick_entity = nil self.map:onTick() - self.map.th:updateTemperatures(outside_temperatures[self.month], - 0.25 + self.hospitals[1].radiator_heat * 0.3) + self.map.th:updateTemperatures(outside_temperatures[self.game_date:monthOfYear()], + 0.25 + self.hospitals[1].radiator_heat * 0.3) if self.ui then self.ui:onWorldTick() end @@ -1097,13 +1059,13 @@ end function World:setEndMonth() - self.day = month_length[self.month] - self.hour = self.hours_per_day - 1 + local first_day_of_next_month = Date(self.game_date:year(), self.game_date:monthOfYear() + 1) + self.game_date = first_day_of_next_month:plusHours(-1) end function World:setEndYear() - self.month = 12 - self:setEndMonth() + local first_day_of_next_year = Date(self.game_date:year() + 1) + self.game_date = first_day_of_next_year:plusHours(-1) end -- Called immediately prior to the ingame day changing. @@ -1119,35 +1081,29 @@ self.current_tick_entity = nil --check if it's time for a VIP visit - if (self.year - 1) * 12 + self.month == self.next_vip_month - and self.day == self.next_vip_day then + if self.game_date:isSameDay(self.next_vip_date) then if #self.rooms > 0 and self.ui.hospital:hasStaffedDesk() then self.hospitals[1]:createVip() else - self:nextVip() + self.next_vip_date = self:_generateNextVipDate() end end -- check if it's time for an earthquake, and the user is at least on level 5 - if (self.year - 1) * 12 + self.month == self.next_earthquake_month - and self.day == self.next_earthquake_day then + if self.game_date:monthOfGame() == self.next_earthquake.start_month and + self.game_date:dayOfMonth() == self.next_earthquake.start_day then -- warn the user that an earthquake is on the way - local announcements = { - "quake001.wav", "quake002.wav", "quake003.wav", "quake004.wav", - } - self.ui:playAnnouncement(announcements[math.random(1, #announcements)]) - - self:createEarthquake() + self.next_earthquake.active = true end -- Maybe it's time for an emergency? - if (self.year - 1) * 12 + self.month == self.next_emergency_month - and self.day == self.next_emergency_day then + if self.game_date:monthOfGame() == self.next_emergency_month and + self.game_date:dayOfMonth() == self.next_emergency_day then -- Postpone it if anything clock related is already underway. if self.ui:getWindow(UIWatch) then self.next_emergency_month = self.next_emergency_month + 1 local month_of_year = 1 + ((self.next_emergency_month - 1) % 12) - self.next_emergency_day = math.random(1, month_length[month_of_year]) + self.next_emergency_day = math.random(1, Date(1, month_of_year):lastDayOfMonth()) else -- Do it only for the player hospital for now. TODO: Multiplayer local control = self.map.level_config.emergency_control @@ -1183,9 +1139,10 @@ end -- Any patients tomorrow? self.spawn_hours = {} - if self.spawn_dates[self.day] then - for i = 1, self.spawn_dates[self.day] do - local hour = math.random(1, self.hours_per_day) + local day = self.game_date:dayOfMonth() + if self.spawn_dates[day] then + for _ = 1, self.spawn_dates[day] do + local hour = math.random(1, Date.hoursPerDay()) self.spawn_hours[hour] = self.spawn_hours[hour] and self.spawn_hours[hour] + 1 or 1 end end @@ -1193,35 +1150,39 @@ -- staff at the moment and making plants need water. end +function World:checkIfGameWon() + for i, _ in ipairs(self.hospitals) do + local res = self:checkWinningConditions(i) + if res.state == "win" then + self:winGame(i) + end + end +end + -- Called immediately prior to the ingame month changing. -- returns true if the game was killed due to the player losing function World:onEndMonth() - -- Check if a player has won the level. + -- Check if a player has won the level if the year hasn't ended, if it has the + -- annual report window will perform this check when it has been closed. + -- TODO.... this is a step closer to the way TH would check. -- What is missing is that if offer is declined then the next check should be -- either 6 months later or at the end of month 12 and then every 6 months - if self.month % 3 == 0 then - for i, hospital in ipairs(self.hospitals) do - local res = self:checkWinningConditions(i) - if res.state == "win" then - self:winGame(i) - end - end + if self.game_date:monthOfYear() % 3 == 0 and self.game_date:monthOfYear() < 12 then + self:checkIfGameWon() end - -- Change population share for the hospitals, TODO according to reputation. - -- Since there are no competitors yet the player's hospital can be considered - -- to be fairly good no matter what it looks like, so after gbv.AllocDelay - -- months, change the share to half of the new people. - if self.month >= self.map.level_config.gbv.AllocDelay then - self:getLocalPlayerHospital().population = 0.5 + local local_hospital = self:getLocalPlayerHospital() + local_hospital.population = 0.25 + if self.game_date:monthOfGame() >= self.map.level_config.gbv.AllocDelay then + local_hospital.population = local_hospital.population * self:getReputationImpact(local_hospital) end -- Also possibly change world spawn rate according to the level configuration. local index = 0 local popn = self.map.level_config.popn while popn[index] do - if popn[index].Month == self.month + (self.year - 1)*12 then + if popn[index].Month == self.game_date:monthOfGame() then self.monthly_spawn_increase = popn[index].Change break end @@ -1231,7 +1192,7 @@ self.spawn_rate = self.spawn_rate + self.monthly_spawn_increase self:updateSpawnDates() - self:makeAvailableStaff((self.year - 1) * 12 + self.month) + self:makeAvailableStaff(self.game_date:monthOfGame()) self.autosave_next_tick = true for _, entity in ipairs(self.entities) do if entity.checkForDeadlock then @@ -1250,18 +1211,39 @@ -- Use ceil so that at least one patient arrives (unless population = 0) no_of_spawns = math.ceil(no_of_spawns*self:getLocalPlayerHospital().population) self.spawn_dates = {} - for i = 1, no_of_spawns do - -- We are interested in the coming month, pick days from it at random. - local day = math.random(1, month_length[self.month % 12 + 1]) + for _ = 1, no_of_spawns do + -- We are interested in the next month, pick days from it at random. + local day = math.random(1, self.game_date:lastDayOfMonth()) self.spawn_dates[day] = self.spawn_dates[day] and self.spawn_dates[day] + 1 or 1 end end +--! Computes the impact of hospital reputation on the spawn rate. +--! The relation between reputation and its impact is linear. +--! Returns a percentage (as a float): +--! 1% if reputation < 253 +--! 60% if reputation == 400 +--! 100% if reputation == 500 +--! 140% if reputation == 600 +--! 180% if reputation == 700 +--! 300% if reputation == 1000 +--!param hospital (hospital): the hospital used to compute the +--! reputation impact +function World:getReputationImpact(hospital) + local result = 1 + ((hospital.reputation - 500) / 250) + + -- The result must be positive + if result <= 0 then + return 0.01 + else + return result + end +end + -- Called when it is time to determine what the -- next emergency should look like. function World:nextEmergency() local control = self.map.level_config.emergency_control - local current_month = (self.year - 1) * 12 + self.month -- Does this level use random emergencies? if control and (control[0].Random or control[0].Mean) then -- Support standard values for mean and variance @@ -1269,20 +1251,11 @@ local variance = control[0].Variance or 30 -- How many days until next emergency? local days = math.round(math.n_random(mean, variance)) - local next_month = self.month + local emergency_date = self.game_date:plusDays(days) - -- Walk forward to get the resulting month and day. - if days > month_length[next_month] - self.day then - days = days - (month_length[next_month] - self.day) - next_month = next_month + 1 - end - while days > month_length[(next_month - 1) % 12 + 1] do - days = days - month_length[(next_month - 1) % 12 + 1] - next_month = next_month + 1 - end -- Make it the same format as for "controlled" emergencies - self.next_emergency_month = next_month + (self.year - 1) * 12 - self.next_emergency_day = days + self.next_emergency_month = emergency_date:monthOfGame() + self.next_emergency_day = emergency_date:dayOfMonth() else if not self.next_emergency_no then self.next_emergency_no = 0 @@ -1290,12 +1263,12 @@ repeat self.next_emergency_no = self.next_emergency_no + 1 -- Level three is missing [5]. - if not control[self.next_emergency_no] - and control[self.next_emergency_no + 1] then + if not control[self.next_emergency_no] and + control[self.next_emergency_no + 1] then self.next_emergency_no = self.next_emergency_no + 1 end - until not control[self.next_emergency_no] - or control[self.next_emergency_no].EndMonth >= current_month + until not control[self.next_emergency_no] or + control[self.next_emergency_no].EndMonth >= self.game_date:monthOfGame() end local emergency = control[self.next_emergency_no] @@ -1306,14 +1279,14 @@ else -- Generate the next month and day the emergency should occur at. -- Make sure it doesn't happen in the past. - local start = math.max(emergency.StartMonth, self.month + (self.year - 1) * 12) + local start = math.max(emergency.StartMonth, self.game_date:monthOfGame()) local next_month = math.random(start, emergency.EndMonth) self.next_emergency_month = next_month local day_start = 1 if start == emergency.EndMonth then - day_start = self.day + day_start = self.game_date:dayOfMonth() end - local day_end = month_length[(next_month - 1) % 12 + 1] + local day_end = Date(1, next_month):lastDayOfMonth() self.next_emergency_day = math.random(day_start, day_end) end end @@ -1321,68 +1294,43 @@ -- Called when it is time to have another VIP function World:nextVip() - local current_month = (self.year - 1) * 12 + self.month + self.next_vip_date = self:_generateNextVipDate() +end +-- PRIVATE method to generate the next VIP date +function World:_generateNextVipDate() -- Support standard values for mean and variance local mean = 180 local variance = 30 -- How many days until next vip? local days = math.round(math.n_random(mean, variance)) - local next_month = self.month - - -- Walk forward to get the resulting month and day. - if days > month_length[next_month] - self.day then - days = days - (month_length[next_month] - self.day) - next_month = next_month + 1 - end - while days > month_length[(next_month - 1) % 12 + 1] do - days = days - month_length[(next_month - 1) % 12 + 1] - next_month = next_month + 1 - end - self.next_vip_month = next_month + (self.year - 1) * 12 - self.next_vip_day = days + return self.game_date:plusDays(days) end -- Called when it is time to have another earthquake function World:nextEarthquake() + self.next_earthquake = {} + self.next_earthquake.active = false + + local level_config = self.map.level_config -- check carefully that no value that we are going to use is going to be nil - if self.map.level_config.quake_control and - self.map.level_config.quake_control[self.current_map_earthquake] and - self.map.level_config.quake_control[self.current_map_earthquake].Severity ~= 0 then - -- this map has rules to follow when making earthquakes, let's follow them - local control = self.map.level_config.quake_control[self.current_map_earthquake] - self.next_earthquake_month = math.random(control.StartMonth, control.EndMonth) - self.next_earthquake_day = math.random(1, month_length[(self.next_earthquake_month % 12)+1]) - self.earthquake_size = control.Severity + if level_config.quake_control and level_config.quake_control[self.current_map_earthquake] and + level_config.quake_control[self.current_map_earthquake].Severity ~= 0 then + -- this map has rules to follow when making earthquakes, let's follow them + local control = level_config.quake_control[self.current_map_earthquake] + self.next_earthquake.start_month = math.random(control.StartMonth, control.EndMonth) + + -- Month length of the start of the earthquake. From start to finish + -- earthquakes do not persist for >= a month so we can wrap all days + -- after the start around the month length unambiguously. + local eqml = month_length[(self.next_earthquake.start_month % 12) + 1] + self.next_earthquake.start_day = math.random(1, eqml) + + self.next_earthquake.size = control.Severity + self.next_earthquake.remaining_damage = self.next_earthquake.size + self.next_earthquake.damage_timer = earthquake_damage_time + self.next_earthquake.warning_timer = earthquake_warning_period self.current_map_earthquake = self.current_map_earthquake + 1 - else - if (tonumber(self.map.level_number) and tonumber(self.map.level_number) >= 5) or - (not tonumber(self.map.level_number)) then - local current_month = (self.year - 1) * 12 + self.month - - -- Support standard values for mean and variance - local mean = 180 - local variance = 30 - -- How many days until next earthquake? - local days = math.round(math.n_random(mean, variance)) - local next_month = self.month - - -- Walk forward to get the resulting month and day. - if days > month_length[next_month] - self.day then - days = days - (month_length[next_month] - self.day) - next_month = next_month + 1 - end - while days > month_length[(next_month - 1) % 12 + 1] do - days = days - month_length[(next_month - 1) % 12 + 1] - next_month = next_month + 1 - end - self.next_earthquake_month = next_month + (self.year - 1) * 12 - self.next_earthquake_day = days - - -- earthquake can be between 1 and 10 (non-inclusive) on the richter scale - -- Make quakes at around 4 more probable. - self.earthquake_size = math.round(math.min(math.max(math.n_random(4,2), 1), 9)) - end end end @@ -1406,7 +1354,7 @@ local hospital = self.hospitals[player_no] -- Go through the goals - for i, goal in ipairs(self.goals) do + for _, goal in ipairs(self.goals) do local current_value = hospital[goal.name] -- If max_min is 1 the value must be > than the goal condition. -- If 0 it must be < than the goal condition. @@ -1418,7 +1366,7 @@ -- -1000 too, but how often does that happen? Probably not more often -- than having exactly e.g. 200 in reputation, -- which is handled correctly. - if (current_value - goal.lose_value)*max_min > 0 then + if (current_value - goal.lose_value) * max_min > 0 then result.state = "lose" result.reason = goal.name result.limit = goal.lose_value @@ -1432,7 +1380,7 @@ current_value = current_value - hospital.loan end -- Is this goal not fulfilled yet? - if (current_value - goal.win_value)*max_min <= 0 then + if (current_value - goal.win_value) * max_min <= 0 then result.state = "nothing" end end @@ -1440,6 +1388,8 @@ return result end +--! Process that the given player number won the game. +--!param player_no (integer) Number of the player who just won. function World:winGame(player_no) if player_no == 1 then -- Player won. TODO: Needs to be changed for multiplayer local text = {} @@ -1447,41 +1397,22 @@ local bonus_rate = math.random(4,9) local with_bonus = self.ui.hospital.cheated and 0 or (self.ui.hospital.player_salary * bonus_rate) / 100 self.ui.hospital.salary_offer = math.floor(self.ui.hospital.player_salary + with_bonus) - if tonumber(self.map.level_number) then - local no = tonumber(self.map.level_number) - local repeated_offer = false -- TODO whether player was asked previously to advance and declined - local has_next = no < 12 and not TheApp.using_demo_files - -- Letters 1-4 normal - -- Letters 5-8 repeated offer - -- Letters 9-12 last level - local letter_idx = math.random(1, 4) + (not has_next and 8 or repeated_offer and 4 or 0) - for key, value in ipairs(_S.letter[letter_idx]) do - text[key] = value - end - text[1] = text[1]:format(self.hospitals[player_no].name) - text[2] = text[2]:format(self.hospitals[player_no].salary_offer) - text[3] = text[3]:format(_S.level_names[self.map.level_number + 1]) - if has_next then - choice_text = _S.fax.choices.accept_new_level - choice = 1 - else - choice_text = _S.fax.choices.return_to_main_menu - choice = 2 - end + if type(self.map.level_number) == "number" or self.campaign_info then + text, choice_text, choice = self:getCampaignWinningText(player_no) else - -- TODO: When custom levels can contain sentences this should be changed to something better. + local level_info = TheApp:readLevelFile(self.map.level_number) text[1] = _S.letter.dear_player:format(self.hospitals[player_no].name) - text[2] = _S.letter.custom_level_completed + text[2] = level_info.end_praise and level_info.end_praise or _S.letter.custom_level_completed text[3] = _S.letter.return_to_main_menu choice_text = _S.fax.choices.return_to_main_menu - choice = 2 + choice = "return_to_main_menu" end local message = { {text = text[1]}, {text = text[2]}, {text = text[3]}, choices = { - {text = choice_text, choice = choice == 1 and "accept_new_level" or "return_to_main_menu"}, + {text = choice_text, choice = choice}, {text = _S.fax.choices.decline_new_level, choice = "stay_on_level"}, }, } @@ -1505,6 +1436,69 @@ end end +--! Finds what text the winning fax should contain, and which choices the player has. +--!param player_no (integer) Which player that will see the message. +--!return (string, string, string) Text to show in the fax, text that accompanies +--! the "continue"-choice the player has, and whether it is the "return_to_main_menu" +--! choice or the "accept_new_level" choice. +function World:getCampaignWinningText(player_no) + local text = {} + local choice_text, choice + local repeated_offer = false -- TODO whether player was asked previously to advance and declined + local has_next = false + if type(self.map.level_number) == "number" then + local no = tonumber(self.map.level_number) + has_next = no < 12 and not TheApp.using_demo_files + -- Standard letters 1-4: normal + -- Standard letters 5-8: repeated offer + -- Standard letters 9-12: last level + local letter_idx = math.random(1, 4) + (not has_next and 8 or repeated_offer and 4 or 0) + for key, value in ipairs(_S.letter[letter_idx]) do + text[key] = value + end + text[1] = text[1]:format(self.hospitals[player_no].name) + text[2] = text[2]:format(self.hospitals[player_no].salary_offer) + text[3] = text[3]:format(_S.level_names[self.map.level_number + 1]) + else + local campaign_info = self.campaign_info + local next_level_name + if campaign_info then + for i, level in ipairs(campaign_info.levels) do + if self.map.level_number == level then + has_next = i < #campaign_info.levels + if has_next then + local next_level_info = TheApp:readLevelFile(campaign_info.levels[i + 1]) + if not next_level_info then + return {_S.letter.campaign_level_missing:format(campaign_info.levels[i + 1]), "", ""}, + _S.fax.choices.return_to_main_menu, + "return_to_main_menu" + end + next_level_name = next_level_info.name + end + break + end + end + end + local level_info = TheApp:readLevelFile(self.map.level_number) + text[1] = _S.letter.dear_player:format(self.hospitals[player_no].name) + if has_next then + text[2] = level_info.end_praise and level_info.end_praise:format(next_level_name) or _S.letter.campaign_level_completed:format(next_level_name) + text[3] = "" + else + text[2] = campaign_info.winning_text and campaign_info.winning_text or _S.letter.campaign_completed + text[3] = "" + end + end + if has_next then + choice_text = _S.fax.choices.accept_new_level + choice = "accept_new_level" + else + choice_text = _S.fax.choices.return_to_main_menu + choice = "return_to_main_menu" + end + return text, choice_text, choice +end + --! Cause the player with the player number player_no to lose. --!param player_no (number) The number of the player which should lose. --!param reason (string) [optional] The name of the criterion the player lost to. @@ -1530,7 +1524,7 @@ end -- This is done here instead of in onEndMonth so that the player gets -- the chance to receive money or reputation from trophies and awards first. - for i, hospital in ipairs(self.hospitals) do + for i, _ in ipairs(self.hospitals) do local res = self:checkWinningConditions(i) if res.state == "lose" then self:loseGame(i, res.reason, res.limit) @@ -1579,23 +1573,36 @@ return cache.x[idx], cache.y[idx] end -local face_dir = { - [0] = "south", - [1] = "west", - [2] = "north", - [3] = "east", -} +--[[ +This function checks if a tile has no entity on it and (optionally) if it is not +in a room. +!param x (integer) the queried tile's x coordinate. +!param y (integer) the queried tile's y coordinate. +!param not_in_room (boolean) If set, also check the tile is not in a room. +!return (boolean) whether all checks hold. +--]] +function World:isTileEmpty(x, y, not_in_room) + if #self.entity_map:getHumanoidsAtCoordinate(x, y) ~= 0 or + #self.entity_map:getObjectsAtCoordinate(x, y) ~= 0 then + return false + end + if not_in_room then + return self:getRoom(x, y) == nil + end + return true +end function World:getFreeBench(x, y, distance) local bench, rx, ry, bench_distance local object_type = self.object_types.bench - self.pathfinder:findObject(x, y, object_type.thob, distance, function(x, y, d, dist) - local b = self:getObject(x, y, "bench") + x, y, distance = math.floor(x), math.floor(y), math.ceil(distance) + self.pathfinder:findObject(x, y, object_type.thob, distance, function(xpos, ypos, d, dist) + local b = self:getObject(xpos, ypos, "bench") if b and not b.user and not b.reserved_for then local orientation = object_type.orientations[b.direction] if orientation.pathfind_allowed_dirs[d] then - rx = x + orientation.use_position[1] - ry = y + orientation.use_position[2] + rx = xpos + orientation.use_position[1] + ry = ypos + orientation.use_position[2] bench = b bench_distance = dist return true @@ -1605,7 +1612,12 @@ return bench, rx, ry, bench_distance end --- This helper function checks if the given tile is part of a nearby object (walkable tiles count as part of the object) +--! Checks whether the given tile is part of a nearby object (walkable tiles +-- count as part of the object) +--!param x X position of the given tile. +--!param y Y position of the given tile. +--!param distance The number of tiles away from the tile to search. +--!return (boolean) Whether the tile is part of a nearby object. function World:isTilePartOfNearbyObject(x, y, distance) for o in pairs(self:findAllObjectsNear(x, y, distance)) do for _, xy in ipairs(o:getWalkableTiles()) do @@ -1638,8 +1650,8 @@ thob = obj_type.thob end - local callback = function(x, y, d) - local obj = self:getObject(x, y, object_type_name) + local callback = function(xpos, ypos, d) + local obj = self:getObject(xpos, ypos, object_type_name) if obj then objects[obj] = true end @@ -1691,8 +1703,8 @@ if type(object_type_name) == "table" then local original_callback = callback callback = function(x, y, ...) - local obj = self:getObject(x, y, object_type_name) - if obj then + local cb_obj = self:getObject(x, y, object_type_name) + if cb_obj then return original_callback(x, y, ...) end end @@ -1705,7 +1717,7 @@ end self.pathfinder:findObject(humanoid.tile_x, humanoid.tile_y, thob, distance, callback) - -- These return values are only relevent for the default callback - are nil + -- These return values are only relevant for the default callback - are nil -- for custom callbacks return obj, ox, oy end @@ -1713,7 +1725,7 @@ function World:findFreeObjectNearToUse(humanoid, object_type_name, which, current_object) -- If which == nil or false, then the nearest object is taken. -- If which == "far", then the furthest object is taken. - -- If which == "near", then the nearest object is taken with 50% probabilty, the second nearest with 25%, and so on + -- If which == "near", then the nearest object is taken with 50% probability, the second nearest with 25%, and so on -- Other values for which may be added in the future. -- Specify current_object if you want to exclude the currently used object from the search local object, ox, oy @@ -1762,10 +1774,10 @@ distance = 2^30 end for _, r in pairs(self.rooms) do repeat - if r.built and (not room_type_id or r.room_info.id == room_type_id) and r.is_active and r.door.queue.max_size ~= 0 then + if r.built and (not room_type_id or r.room_info.id == room_type_id) and r.is_active then local x, y = r:getEntranceXY(false) local d = self:getPathDistance(humanoid.tile_x, humanoid.tile_y, x, y) - if d > distance then + if not d or d > distance then break -- continue end local this_score = d @@ -1827,6 +1839,10 @@ entity:onDestroy() end +function World:newObjectType(new_object) + self.object_types[new_object.id] = new_object +end + --! Creates a new object by finding the object_type from the "id" variable and -- calls its class constructor. --!param id (string) The unique id of the object to be created. @@ -1849,6 +1865,179 @@ return entity end +function World:canNonSideObjectBeSpawnedAt(x, y, objects_id, orientation, spawn_rooms_id, player_id) + local object = self.object_types[objects_id] + local objects_footprint = object.orientations[orientation].footprint + for _, tile in ipairs(objects_footprint) do + local tiles_world_x = x + tile[1] + local tiles_world_y = y + tile[2] + if not self:isOnMap(tiles_world_x, tiles_world_y) then + return false + end + + if not self:willObjectsFootprintTileBeWithinItsAllowedRoomIfLocatedAt(x, y, object, spawn_rooms_id).within_room then + return false + end + + if not self:isFootprintTileBuildableOrPassable(x, y, tile, objects_footprint, "buildable", player_id) then + return false + end + end + return not self:wouldNonSideObjectBreakPathfindingIfSpawnedAt(x, y, object, orientation, spawn_rooms_id) +end + +--! Test whether the given coordinate is on the map. +--!param x (int) X position of the coordinate to test. +--!param y (int) Y position of the coordinate to test. +--!return (boolean) Whether the provided position is on the map. +function World:isOnMap(x, y) + return x >= 1 and x <= self.map.width and y >= 1 and y <= self.map.height +end + +--- +-- @param allowed_rooms_id_parameter Should be nil when the object is allowed to be placed in any room. +-- @return {within_room, roomId} +--- +function World:willObjectsFootprintTileBeWithinItsAllowedRoomIfLocatedAt(x, y, object, allowed_rooms_id_parameter) + local xy_rooms_id = self.map.th:getCellFlags(x, y, {}).roomId + + if allowed_rooms_id_parameter then + return {within_room = allowed_rooms_id_parameter == xy_rooms_id, roomId = allowed_rooms_id_parameter} + elseif xy_rooms_id == 0 then + return {within_room = object.corridor_object ~= nil, roomId = xy_rooms_id} + else + for _, additional_objects_name in pairs(self.rooms[xy_rooms_id].room_info.objects_additional) do + if TheApp.objects[additional_objects_name].thob == object.thob then + return {within_room = true, roomId = xy_rooms_id} + end + end + for needed_objects_name, _ in pairs(self.rooms[xy_rooms_id].room_info.objects_needed) do + if TheApp.objects[needed_objects_name].thob == object.thob then + return {within_room = true, roomId = xy_rooms_id} + end + end + return {within_room = false, roomId = xy_rooms_id} + end +end + +--- +-- A footprint tile will either need to be buildable or passable so this function +-- checks if its buildable/passable using the tile's appropriate flag and then returns this +-- flag's boolean value or false if the tile isn't valid. +--- +function World:isFootprintTileBuildableOrPassable(x, y, tile, footprint, requirement_flag, player_id) + local function isTileValid(xpos, ypos, complete_cell, flags, flag_name, need_side) + if complete_cell or need_side then + return flags[flag_name] + end + for _, fp_tile in ipairs(footprint) do + if fp_tile[1] == xpos and fp_tile[2] == ypos then + return flags[flag_name] + end + end + return true + end + + local direction_parameters = { + north = { x = 0, y = -1, buildable_flag = "buildableNorth", passable_flag = "travelNorth", needed_side = "need_north_side"}, + east = { x = 1, y = 0, buildable_flag = "buildableEast", passable_flag = "travelEast", needed_side = "need_east_side"}, + south = { x = 0, y = 1, buildable_flag = "buildableSouth", passable_flag = "travelSouth", needed_side = "need_south_side"}, + west = { x = -1, y = 0, buildable_flag = "buildableWest", passable_flag = "travelWest", needed_side = "need_west_side"} + } + local flags = {} + local requirement_met = self.map.th:getCellFlags(x, y, flags)[requirement_flag] and + (player_id == 0 or player_id == flags.owner) + + if requirement_met then + -- For each direction check that the tile is valid: + for _, direction in pairs(direction_parameters) do + local x1, y1 = tile[1] + direction["x"], tile[2] + direction["y"] + if not isTileValid(x1, y1, tile.complete_cell, flags, direction["buildable_flag"], tile[direction["needed_side"]]) then + return false + end + end + return true + else + return false + end +end + +--- +-- Check that pathfinding still works, i.e. that placing the object +-- wouldn't disconnect one part of the hospital from another. To do +-- this, we provisionally mark the footprint as unpassable (as it will +-- become when the object is placed), and then check that the cells +-- surrounding the footprint have not had their connectedness changed. +--- +function World:wouldNonSideObjectBreakPathfindingIfSpawnedAt(x, y, object, objects_orientation, spawn_rooms_id) + local objects_footprint = object.orientations[objects_orientation].footprint + local map = self.map.th + + local function setFootprintTilesPassable(passable) + for _, tile in ipairs(objects_footprint) do + if not tile.only_passable then + map:setCellFlags(x + tile[1], y + tile[2], {passable = passable}) + end + end + end + + local function isIsolated(xpos, ypos) + setFootprintTilesPassable(false) + local result = not self.pathfinder:isReachableFromHospital(xpos, ypos) + setFootprintTilesPassable(true) + return result + end + + local all_good = true + + --1. Find out which footprint tiles are passable now before this function makes some unpassable + --during its test: + local tiles_passable_flags = {} + for _, tile in ipairs(objects_footprint) do + table.insert(tiles_passable_flags, map:getCellFlags(x + tile[1], y + tile[2], {}).passable) + end + + --2. Find out which tiles adjacent to the footprint would become isolated: + setFootprintTilesPassable(false) + local prev_x, prev_y + for _, tile in ipairs(object.orientations[objects_orientation].adjacent_to_solid_footprint) do + local xpos = x + tile[1] + local ypos = y + tile[2] + local flags = {} + if map:getCellFlags(xpos, ypos, flags).roomId == spawn_rooms_id and flags.passable then + if prev_x then + if not self.pathfinder:findDistance(xpos, ypos, prev_x, prev_y) then + -- There is no route between the two map nodes. In most cases, + -- this means that connectedness has changed, though there is + -- one rare situation where the above test is insufficient. If + -- (xpos, ypos) is a passable but isolated node outside the hospital + -- and (prev_x, prev_y) is in the corridor, then the two will + -- not be connected now, but critically, neither were they + -- connected before. + if not isIsolated(xpos, ypos) then + if not isIsolated(prev_x, prev_y) then + all_good = false + break + end + else + xpos = prev_x + ypos = prev_y + end + end + end + prev_x = xpos + prev_y = ypos + end + end + + -- 3. For each footprint tile passable flag set to false by step 2 undo this change: + for tiles_index, tile in ipairs(objects_footprint) do + map:setCellFlags(x + tile[1], y + tile[2], {passable = tiles_passable_flags[tiles_index]}) + end + + return not all_good +end + --! Notifies the world that an object has been placed, notifying -- interested entities in the vicinity of the new arrival. --!param entity (Entity) The entity that was just placed. @@ -1864,32 +2053,44 @@ self.entities[#self.entities + 1] = entity -- If it is a bench we're placing, notify queueing patients in the vicinity if id == "bench" and entity.tile_x and entity.tile_y then - for _, patient in ipairs(self.entities) do - if class.is(patient, Patient) then - if math.abs(patient.tile_x - entity.tile_x) < 7 and - math.abs(patient.tile_y - entity.tile_y) < 7 then - patient:notifyNewObject(id) + local notify_distance = 6 + local w, h = self.map.th:size() + for tx = math.max(1, entity.tile_x - notify_distance), math.min(w, entity.tile_x + notify_distance) do + for ty = math.max(1, entity.tile_y - notify_distance), math.min(h, entity.tile_y + notify_distance) do + for _, patient in ipairs(self.entity_map:getHumanoidsAtCoordinate(tx, ty)) do + if class.is(patient, Patient) then + patient:notifyNewObject(id) + end end end end end if id == "reception_desk" then - if not self.ui.start_tutorial - and not self.hospitals[1]:hasStaffOfCategory("Receptionist") then + if not self.ui.start_tutorial and + not self.hospitals[1]:hasStaffOfCategory("Receptionist") then -- TODO: Will not work correctly for multiplayer self.ui.adviser:say(_A.room_requirements.reception_need_receptionist) - elseif self.hospitals[1]:hasStaffOfCategory("Receptionist") and self.object_counts["reception_desk"] == 1 - and not self.hospitals[1].receptionist_msg and self.month > 3 then + elseif self.hospitals[1]:hasStaffOfCategory("Receptionist") and + self.object_counts["reception_desk"] == 1 and + not self.hospitals[1].receptionist_msg and self.game_date:monthOfGame() > 3 then self.ui.adviser:say(_A.warnings.no_desk_5) self.hospitals[1].receptionist_msg = true end - -- A new reception desk? Then add it to the reception desk set. - self:getLocalPlayerHospital().reception_desks[entity] = true end -- If it is a plant it might be advisable to hire a handyman if id == "plant" and not self.hospitals[1]:hasStaffOfCategory("Handyman") then self.ui.adviser:say(_A.staff_advice.need_handyman_plants) end + if id == "gates_to_hell" then + entity:playEntitySounds("LAVA00*.WAV", {0,1350,1150,950,750,350}, + {0,1450,1250,1050,850,450}, 40) + entity:setTimer(entity.world:getAnimLength(2550), + --[[persistable:lava_hole_spawn_animation_end]] + function(anim_entity) + anim_entity:setAnimation(1602) + end) + entity:setAnimation(2550) + end end --! Notify the world of an object being removed from a tile @@ -1940,11 +2141,20 @@ return true end +--! Retrieve all objects from a given position. +--!param x (int) X position of the object to retrieve. +--!param y (int) Y position of the object to retrieve. function World:getObjects(x, y) local index = (y - 1) * self.map.width + x return self.objects[index] end +--! Retrieve one object from a given position. +--!param x (int) X position of the object to retrieve. +--!param y (int) Y position of the object to retrieve. +--!param id Id to search, nil gets first object, string gets first object with +--! that id, set of strings gets first object that matches an entry in the set. +--!return (Object or nil) The found object, or nil if the object is not found. function World:getObject(x, y, id) local objects = self:getObjects(x, y) if objects then @@ -1967,37 +2177,75 @@ return -- nil end -function World:getObjectsById(id) - if not id then - return self.objects - end +--! Remove all cleanable litter from a given tile. +--!param x (int) X position of the tile to clean. +--!param y (int) Y position of the tile to clean. +function World:removeAllLitter(x, y) + local litters = {} + local objects = self:getObjects(x, y) + if not objects then return end - local ret = {} - if type(id) == "table" then - for position, obj_list in pairs(self.objects) do - for _, obj in ipairs(obj_list) do - if id[obj.object_type.id] then - table.insert(ret, obj) - end - end + for _, obj in ipairs(objects) do + if obj.object_type.id == "litter" and obj:isCleanable() then + litters[#litters + 1] = obj end - else - for position, obj_list in pairs(self.objects) do - for _, obj in ipairs(obj_list) do - if obj.object_type.id == id then - table.insert(ret, obj) - end - end + end + for _, litter in ipairs(litters) do litter:remove() end +end + +--! Prepare all tiles of the footprint for build of an object. +--!param object_footprint Footprint of the object being build. +--!param x (int) X position of the object +--!param y (int) Y position of the object +function World:prepareFootprintTilesForBuild(object_footprint, x, y) + local hospital = self:getLocalPlayerHospital() + + for _, tile in ipairs(object_footprint) do + if tile.complete_cell or not (tile.passable or tile.only_passable) then + self:removeAllLitter(x + tile[1], y + tile[2]) + hospital:removeRatholeXY(x + tile[1], y + tile[2]) end end +end + +--! Prepare all tiles in the given rectangle for building a room. +--!param x (int) Start x position of the area. +--!param y (int) Start y position of the area. +--!param w (int) Number of tiles in x direction. +--!param h (int) Number of tiles in y direction. +function World:prepareRectangleTilesForBuild(x, y, w, h) + local hospital = self:getLocalPlayerHospital() - return ret + x = x - 1 + y = y - 1 + for dx = 1, w do + for dy = 1, h do + self:removeAllLitter(x + dx, y + dy) + if dx == 1 or dx == w or dy == 1 or dy == h then hospital:removeRatholeXY(x + dx, y + dy) end + end + end end +--! Get the room at a given tile location. +--!param x (int) X position of the queried tile. +--!param y (int) Y position of the queried tile. +--!return (Room) Room of the tile, or 'nil'. function World:getRoom(x, y) return self.rooms[self.map:getRoomId(x, y)] end +--! Get the hospital at a given tile location. +--!param x (int) X position of the queried tile. +--!param y (int) Y position of the queried tile. +--!return (Hospital) Hospital at the given location or 'nil'. +function World:getHospital(x, y) + local th = self.map.th + + local flags = th:getCellFlags(x, y) + if not flags.hospital then return nil end + return self.hospitals[flags.owner] +end + --! Returns localized name of the room, internal required staff name -- and localized name of staff required. function World:getRoomNameAndRequiredStaffName(room_id) @@ -2041,7 +2289,7 @@ function World:dumpGameLog() local config_path = TheApp.command_line["config-file"] or "" local pathsep = package.config:sub(1, 1) - config_path = config_path:match("^(.-)[^".. pathsep .."]*$") + config_path = config_path:match("^(.-)[^" .. pathsep .. "]*$") local gamelog_path = config_path .. "gamelog.txt" local fi, err = io.open(gamelog_path, "w") if fi then @@ -2054,9 +2302,14 @@ end end --- Because the save file only saves one thob per tile if they are more that information +--! Because the save file only saves one thob per tile if they are more that information -- will be lost. To solve this after a load we need to set again all the thobs on each tile. function World:resetAnimations() + -- Erase entities from the map if they want. + for _, entity in ipairs(self.entities) do + entity:eraseObject() + end + -- Add them again. for _, entity in ipairs(self.entities) do entity:resetAnimation() end @@ -2118,7 +2371,7 @@ plant = 0, general = 0, } - for position, obj_list in pairs(self.objects) do + for _, obj_list in pairs(self.objects) do for _, obj in ipairs(obj_list) do local count_cat = obj.object_type.count_category if count_cat then @@ -2129,7 +2382,7 @@ end if old < 43 then self.object_counts.reception_desk = 0 - for position, obj_list in pairs(self.objects) do + for _, obj_list in pairs(self.objects) do for _, obj in ipairs(obj_list) do local count_cat = obj.object_type.count_category if count_cat and count_cat == "reception_desk" then @@ -2140,7 +2393,7 @@ end if old < 47 then self.object_counts.bench = 0 - for position, obj_list in pairs(self.objects) do + for _, obj_list in pairs(self.objects) do for _, obj in ipairs(obj_list) do local count_cat = obj.object_type.count_category if count_cat and count_cat == "bench" then @@ -2159,8 +2412,9 @@ end if old < 17 then -- Added another object - local _, shield = pcall(dofile, "objects" .. pathsep .. "radiation_shield") - local _, shield_b = pcall(dofile, "objects" .. pathsep .. "radiation_shield_b") + local pathsep = package.config:sub(1, 1) + local _, shield = pcall(corsixth.require, "objects" .. pathsep .. "radiation_shield") + local _, shield_b = pcall(corsixth.require, "objects" .. pathsep .. "radiation_shield_b") shield.slave_type = shield_b shield.slave_type.master_type = shield Object.processTypeDefinition(shield) @@ -2238,7 +2492,7 @@ if self.map.level_config.quake_control then while true do if self.map.level_config.quake_control[self.current_map_earthquake] and - self.map.level_config.quake_control[self.current_map_earthquake] ~= 0 then + self.map.level_config.quake_control[self.current_map_earthquake] ~= 0 then -- Check to see if the start month has passed local control = self.map.level_config.quake_control[self.current_map_earthquake] if control.StartMonth <= self.month + 12 * (self.year - 1) then @@ -2303,19 +2557,110 @@ self.ui:addKeyHandler({"shift", "+"}, self, self.adjustZoom, 5) self.ui:addKeyHandler({"shift", "-"}, self, self.adjustZoom, -5) end + + if old < 103 then + -- If a room has patients who no longer exist in its + -- humanoids_enroute table because of #133 remove them: + for _, room in pairs(self.rooms) do + for patient, _ in pairs(room.humanoids_enroute) do + if patient.tile_x == nil then + room.humanoids_enroute[patient] = nil + end + end + end + end + if old < 124 then + self.game_date = Date(self.year, self.month, self.day, self.hour) + -- self.next_vip_month is number of months since the game start + self.next_vip_date = Date(1, self.next_vip_month, self.next_vip_day) + end + -- Now let things inside the world react. for _, cat in pairs({self.hospitals, self.entities, self.rooms}) do for _, obj in pairs(cat) do obj:afterLoad(old, new) end end + if old < 80 then self:determineWinningConditions() end + if old >= 87 then + self:playLoadedEntitySounds() + end + + if old < 88 then + --Populate the entity map + self.entity_map = EntityMap(self.map) + for _, e in ipairs(self.entities) do + local x, y = e.tile_x, e.tile_y + if x and y then + self.entity_map:addEntity(x,y,e) + end + end + end + if old < 108 then + self.room_build_callbacks = nil + end + if old < 113 then -- Make cleanable littered tiles buildable. + for x = 1, self.map.width do + for y = 1, self.map.height do + local litter = self:getObject(x, y, "litter") + if litter and litter:isCleanable() then self.map:setCellFlags(x, y, {buildable=true}) end + end + end + end + if old < 115 then + self.next_earthquake = { + start_month = self.next_earthquake_month, + start_day = self.next_earthquake_day, + size = self.earthquake_size, + active = self.earthquake_active or false + } + self.next_earthquake_month = nil + self.next_earthquake_day = nil + self.earthquake_stop_day = nil + self.earthquake_size = nil + self.earthquake_active = nil + self.randomX = nil + self.randomY = nil + self.currentX = nil + self.currentY = nil + + if self.next_earthquake.active then + local rd = 0 + for _, room in pairs(self.rooms) do + for object, _ in pairs(room.objects) do + if object.quake_points then + rd = math.max(rd, object.quake_points) + object.quake_points = nil + end + end + end + self.next_earthquake.remaining_damage = rd + self.next_earthquake.damage_timer = earthquake_damage_time + self.next_earthquake.warning_timer = 0 + else + self.next_earthquake.remaining_damage = self.next_earthquake.size + self.next_earthquake.damage_timer = earthquake_damage_time + self.next_earthquake.warning_timer = earthquake_warning_period + end + end + if old < 120 then + -- Issue #1105 updates to fix any broken saves with travel flags for side objects + self:resetSideObjects() + end + self.savegame_version = new end +function World:playLoadedEntitySounds() + for _, entity in pairs(self.entities) do + entity:playAfterLoadSound() + end +end + --[[ There is a problem with room editing in that it resets all the partial passable flags (travelNorth, travelSouth etc.) in the corridor, a workaround is calling this function after the room was edited so that all edge only objects, that set partial passable flags set @@ -2329,3 +2674,36 @@ end end end + +--[[ When placing doors and objects the passable tiles need to be checked for overlapping +passable tiles. This presents problems with objects like Bench where the passable tile +is not for exclusive use of the Bench (another object can share that same tile) +the footprint.shareable differentiates shareable passable tiles, and exclusive use +passable tiles (the norm for most objects)]] +--!param x (int) x map tile position +--!param y (int) y map tile position +--!param distance (int) searchable distance for nearby objects +--!return (boolean) indicating if exclusively passable or not +function World:isTileExclusivelyPassable(x, y, distance) + for o in pairs(self:findAllObjectsNear(x, y, distance)) do + if o and o.footprint then + for _, footprint in pairs(o.footprint) do + if footprint[1] + o.tile_x == x and footprint[2] + o.tile_y == y and footprint.only_passable and not footprint.shareable then + return false + end + end + else + -- doors don't have a footprint but objects can't be built blocking them either + for _, footprint in pairs(o:getWalkableTiles()) do + if o.object_type and o.object_type.thob ~= 62 and footprint[1] == x and footprint[2] == y then + return false + end + end + end + end + return true +end + +function World:date() + return self.game_date:clone() +end diff -Nru corsix-th-0.30/CorsixTH/Luatest/.busted corsix-th-0.62/CorsixTH/Luatest/.busted --- corsix-th-0.30/CorsixTH/Luatest/.busted 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/.busted 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,5 @@ +return { + default = { + lpath = "../Lua/?.lua", + }, +} diff -Nru corsix-th-0.30/CorsixTH/Luatest/class_test_base.lua corsix-th-0.62/CorsixTH/Luatest/class_test_base.lua --- corsix-th-0.30/CorsixTH/Luatest/class_test_base.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/class_test_base.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,47 @@ +--[[ Copyright (c) 2014 Edvin "Lego3" Linge + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +-- Use this file to easily get started creating unit tests for CorsixTH +-- classes. + +require("busted") + +require("non_strict") +require("class") +local say = require("say") +local assert = require("luassert") + +function permanent() + return function() + return {} + end +end + +function values() + return function() + return nil + end +end + +function assertion_matches(_, arguments) + return string.match(arguments[1], arguments[2]) ~= nil +end +say:set("assertion.matches", "Expected substring fail.\n: %s\n:%s") +assert:register("assertion", "matches", assertion_matches, "assertion.matches") diff -Nru corsix-th-0.30/CorsixTH/Luatest/corsixth.lua corsix-th-0.62/CorsixTH/Luatest/corsixth.lua --- corsix-th-0.30/CorsixTH/Luatest/corsixth.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/corsixth.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,25 @@ +--[[ Copyright (c) 2017 Stephen "TheCycoONE" Baker + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +-- A stub implementation of the corsixth object to bypass the persistence +-- C++ code. + +_G['corsixth'] = {} +corsixth.require = require; diff -Nru corsix-th-0.30/CorsixTH/Luatest/non_strict.lua corsix-th-0.62/CorsixTH/Luatest/non_strict.lua --- corsix-th-0.30/CorsixTH/Luatest/non_strict.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/non_strict.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,69 @@ +--[[ Copyright (c) 2014 Edvin "Lego3" Linge + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +-- When running unittests we cannot restrict global variables as is usually +-- done, since the busted library relies on being able to do so. +-- We still need to mimic the possibility to call the functions available +-- in strict.lua though. + +local strict_mt = {} +local allowed_globals = setmetatable({}, {__mode = "k"}) + +local function newindex(t, k, v) + rawset(t, k, v) +end + +local function index(t, k) + return nil +end + +local function restrict(ni, i, ...) + strict_mt.__newindex = ni + strict_mt.__index = i + return ... +end +restrict(newindex, index) + +--!! Wrap a function so that it is freely able to set global variables +--[[ Some existing functions (for example, `require`) should be allowed to read + and write global variables without having to worry about declaring them + with `strict_declare_global`. + !param fn The function which should be able to freely set globals + !return A new function which acts just as `fn` and is free to set globals + !example + require = destrict(require) ]] +function destrict(fn) + return function(...) + local ni, i = strict_mt.__newindex, strict_mt.__index + strict_mt.__newindex, strict_mt.__index = nil, nil + return restrict(ni, i, fn(...)) + end +end + +--!! Declare a global variable so that it can later be used +--[[!param name The name of the global to declare + !example + strict_declare_global "some_var" + some_var = 42 ]] +function strict_declare_global(name) + allowed_globals[name] = true +end + +setmetatable(_G, strict_mt) diff -Nru corsix-th-0.30/CorsixTH/Luatest/README.txt corsix-th-0.62/CorsixTH/Luatest/README.txt --- corsix-th-0.30/CorsixTH/Luatest/README.txt 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/README.txt 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,29 @@ +UNIT TESTING + +In order to run the unit test suite you need a unit test framework called Busted. +The easiest way to get it is through Luarocks. All information can be found at + +http://olivinelabs.com/busted/ + +The framework uses its own syntax, which is also described at the above location. + + +RUNNING UNIT TESTS + +When you have Busted on your system, run the following command from +the CorsixTH/Luatest folder to run all tests: + +(Windows) +busted --lpath=../Lua/\?.lua + +(Linux) +busted --lpath=../Lua/?.lua + + +CREATING UNIT TESTS + +If you have added functionality to an existing file you will need to extend +the unit test suite for that file. It is found in the Luatest/spec folder using +the same hierarchy as in the normal Lua folder. All test files are called +_spec.lua. If you have created a new lua file, then +you also create a new *_spec.lua test file. diff -Nru corsix-th-0.30/CorsixTH/Luatest/spec/class_spec.lua corsix-th-0.62/CorsixTH/Luatest/spec/class_spec.lua --- corsix-th-0.30/CorsixTH/Luatest/spec/class_spec.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/spec/class_spec.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,76 @@ +--[[ Copyright (c) 2014 Edvin "Lego3" Linge + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +require("class_test_base") + +class "ParentClass" + +function ParentClass:ParentClass(name) + self.class_name = name +end + +class "ChildClass" (ParentClass) + +function ChildClass:ChildClass(name) + self:ParentClass(name) +end + +describe("A class in CorsixTH ", function() + local child_class, parent_class + + setup(function() + child_class = ChildClass("TheChild") + parent_class = ParentClass("TheParent") + end) + + it("should be instansiatable", function() + assert.are.equal("TheChild", child_class.class_name) + assert.are.equal("TheParent", parent_class.class_name) + end) + + it("should be the same for many instances of the same type, including inheritance", function() + assert.truthy(class.is(child_class, ChildClass)) + assert.falsy(class.is(parent_class, ChildClass)) + + assert.truthy(class.is(child_class, ParentClass)) + assert.truthy(class.is(parent_class, ParentClass)) + end) + + it("should have a name", function() + assert.are.equal("ChildClass", class.name(ChildClass)) + assert.are.equal("ParentClass", class.name(ParentClass)) + assert.are.equal(nil, class.name(NoRealClass)) + end) + + it("should know if it has a superclass", function() + assert.are.equal(ParentClass, class.superclass(ChildClass)) + assert.are.equal(nil, class.superclass(ParentClass)) + assert.has_error(class.superclass, NoRealClass) + end) + + it("should have a type", function() + assert.are.equal("ChildClass", class.type(child_class)) + assert.are.equal("ParentClass", class.type(parent_class)) + end) + + it("should make the metatable available", function() + assert.are.equal(getmetatable(parent_class), parent_class._metatable) + end) +end) diff -Nru corsix-th-0.30/CorsixTH/Luatest/spec/date_spec.lua corsix-th-0.62/CorsixTH/Luatest/spec/date_spec.lua --- corsix-th-0.30/CorsixTH/Luatest/spec/date_spec.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/spec/date_spec.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,185 @@ +--[[ Copyright (c) 2018 Pavel "sofo" Schoffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +require("class_test_base") + +require("date") + +describe("Date", function() + it("can return correct month last day", function() + assert.are.equal(Date(1, 1):lastDayOfMonth(), 31) + assert.are.equal(Date(1, 2):lastDayOfMonth(), 28) + assert.are.equal(Date(1, 6):lastDayOfMonth(), 30) + assert.are.equal(Date(1, 12):lastDayOfMonth(), 31) + end) + + it("default works", function() + local date = Date(5, 12, 22, 5) + assert.are.equal(date:hourOfDay(), 5) + assert.are.equal(date:dayOfMonth(), 22) + assert.are.equal(date:monthOfYear(), 12) + assert.are.equal(date:year(), 5) + + date = Date(5, 12, 22) + assert.are.equal(date:hourOfDay(), 0) + assert.are.equal(date:dayOfMonth(), 22) + assert.are.equal(date:monthOfYear(), 12) + assert.are.equal(date:year(), 5) + + date = Date(4, 12) + assert.are.equal(date:dayOfMonth(), 1) + assert.are.equal(date:monthOfYear(), 12) + assert.are.equal(date:year(), 4) + + date = Date(24) + assert.are.equal(date:dayOfMonth(), 1) + assert.are.equal(date:monthOfYear(), 1) + assert.are.equal(date:year(), 24) + + date = Date() + assert.are.equal(date:dayOfMonth(), 1) + assert.are.equal(date:monthOfYear(), 1) + assert.are.equal(date:year(), 1) + end) + + it("cannot be wrong date", function() + local date = Date(1, 14) + assert.are.equal(date:monthOfYear(), 2) + + date = Date(1, 24) + assert.are.equal(date:monthOfYear(), 12) + end) + + it("can handle hour adjustmentse", function() + local date = Date(1, 1, 5, 50) + assert.are.equal(6, date:dayOfMonth()) + assert.are.equal(0, date:hourOfDay()) + + date = Date(1, 1, 1, 55) + assert.are.equal(2, date:dayOfMonth()) + assert.are.equal(5, date:hourOfDay()) + end) + + it("can add and read months", function() + local date = Date():plusMonths(1) + assert.are.equal(date:monthOfYear(), 2) + + date = Date(20, 12):plusMonths(1) + assert.are.equal(date:monthOfYear(), 1) + end) + + it("can handle complex adjustments", function() + local date = Date(2,2,31,55) + assert.are.equal("2-03-04T05", date:tostring()) + + date = Date(1,12,31,55) + assert.are.equal("2-01-01T05", date:tostring()) + + -- 31 - January, 28 - February, 7 - March + date = Date(1,1,66) + assert.are.equal("1-03-07T00", date:tostring()) + end) + + it("can print date", function() + local date = Date(2,12,1,6) + assert.are.equal("2-12-01T06", date:tostring()) + end) + it("can add days", function() + local date = Date(2,12,30) + -- 1 - December, 29 - January + date = date:plusDays(30) + assert.are.equal("3-01-29T00", date:tostring()) + + date = Date(1,3,15) + -- 16 - March, 30 - April, 31 - June, 13 - July + date = date:plusDays(90) + assert.are.equal("1-06-13T00", date:tostring()) + end) + it("can add years", function() + local date = Date(3, 2, 1, 6) + local expected_date = Date(8, 2, 1, 6) + + local adjusted_date = date:plusYears(5) + assert.True(expected_date == adjusted_date) + end) + it("can add hours", function() + local date = Date(1,1,1,5) + + local adjusted_date = date:plusHours(50) + assert.are.equals(2, adjusted_date:dayOfMonth()) + assert.are.equals(5, adjusted_date:hourOfDay()) + end) + it("can add negative hours", function() + local date = Date(3,1,1,0) + local expected_date = Date(2,12,31,49) + + local adjusted_date = date:plusHours(-1) + assert.True(expected_date == adjusted_date) + end) + it("can add negative days", function() + local date = Date(3,1,1) + local adjusted_date = date:plusDays(-40) + local expected_date = Date(2,11,22) + + assert.True(expected_date == adjusted_date) + end) + it("can tell the last days", function() + local date = Date(1,12,3) + assert.False(date:isLastDayOfMonth()) + assert.False(date:isLastDayOfYear()) + + date = Date(1,1,31) + assert.True(date:isLastDayOfMonth()) + assert.False(date:isLastDayOfYear()) + + date = Date(1,12,31) + assert.True(date:isLastDayOfMonth()) + assert.True(date:isLastDayOfYear()) + end) + it("get total elapsed month", function() + local date = Date(8,11,1) + assert.are.equals(95, date:monthOfGame()) + end) + it("can get compared", function() + local date1 = Date(3,2,1) + local other_date1 = Date(3,2,1) + local date2 = Date(1,2,3) + local date_with_different_hour = Date(3,2,1,40) + assert.True(date1 == other_date1) + assert.False(date1 == date2) + assert.True(date1 > date2) + assert.False(date1 < date2) + assert.True(date1 >= other_date1) + assert.False(date_with_different_hour == date1) + assert.True(date_with_different_hour > date1) + end) + it("can clone itself", function() + local origin_date = Date(12,3,2,6) + local clone_date = origin_date:clone() + assert.True(origin_date == clone_date) + end) + it("can provide hours per day", function() + assert.equals(50, Date.hoursPerDay()) + end) + it("can chack if two days are the same", function() + assert.True(Date(1,2,3,5):isSameDay(Date(1,2,3,9))) + assert.False(Date(1,2,3):isSameDay(Date(1,4,3))) + end) +end) diff -Nru corsix-th-0.30/CorsixTH/Luatest/spec/dialogs/bottom_pannel_spec.lua corsix-th-0.62/CorsixTH/Luatest/spec/dialogs/bottom_pannel_spec.lua --- corsix-th-0.30/CorsixTH/Luatest/spec/dialogs/bottom_pannel_spec.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/spec/dialogs/bottom_pannel_spec.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,82 @@ +--[[ Copyright (c) 2018 Stephen E. Baker + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +describe("Bottom Panel:", function() + local bottom_panel; + local mock_canvas; + local font; + + setup(function() + require("corsixth") + require("class_test_base") + require("TH") + + require("window") + require("dialogs/bottom_panel") + end) + + before_each(function() + TheApp.world.gameLog = function() end + + font = { + draw = function() end, + drawWrapped = function() end, + } + TheApp.gfx.loadFont = function() return font end + + local mock_ui = {} + mock_ui.app = _G['TheApp'] + mock_ui.addKeyHandler = function() end + + mock_canvas = {} + + bottom_panel = UIBottomPanel(mock_ui) + + mock(font, 'draw') + mock(font, 'drawWrapped') + mock(TheApp.world, 'gameLog') + end) + + it("Set nil dynamic info", function() + bottom_panel:setDynamicInfo(nil) + bottom_panel:drawDynamicInfo(mock_canvas, 0, 0) + + assert.stub(TheApp.world.gameLog).was_not.called_with(TheApp.world, "Dynamic info is missing text!") + end) + + it("Set dynamic info without text", function() + local dynamic_info = {} + + bottom_panel:setDynamicInfo(dynamic_info) + bottom_panel:drawDynamicInfo(mock_canvas, 0, 0) + + assert.stub(TheApp.world.gameLog).was.called_with(TheApp.world, "Dynamic info is missing text!") + end) + + it("Set dynamic info with text", function() + local dynamic_info = { text = { "test text" } } + + bottom_panel:setDynamicInfo(dynamic_info) + bottom_panel:drawDynamicInfo(mock_canvas, 0, 0) + + assert.stub(TheApp.world.gameLog).was_not.called_with(TheApp.world, "Dynamic info is missing text!") + assert.stub(font.drawWrapped).was.called_with(font, mock_canvas, "test text", 20, 10, 240) + end) +end) diff -Nru corsix-th-0.30/CorsixTH/Luatest/spec/entities/humanoid_spec.lua corsix-th-0.62/CorsixTH/Luatest/spec/entities/humanoid_spec.lua --- corsix-th-0.30/CorsixTH/Luatest/spec/entities/humanoid_spec.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/spec/entities/humanoid_spec.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,73 @@ +--[[ Copyright (c) 2018 Pavel "sofo" Schoffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +require("class_test_base") + +require("entity") +require("entities.humanoid") + +describe("Humanoid:", function() + local function getHumanoid() + local animation = {setHitTestResult = function() end} + return Humanoid(animation) + end + + it("Gets the current action", function() + local humanoid = getHumanoid() + + local action1 = {name = "fake1"} + local action2 = {name = "fake2"} + humanoid:queueAction(action1) + humanoid:queueAction(action2) + + local recievedAction = humanoid:getCurrentAction() + + assert.equal(action1, recievedAction) + end) + it("Throws error if no action is queued", function() + local humanoid = getHumanoid() + + local state, error = pcall(humanoid.getCurrentAction, humanoid) + + assert.False(state) + local expected_message = "Action queue was empty. This should never happen." + assert.matches(error, expected_message) + assert.matches(error, "humanoid %-") + end) + it("Can represent itself as a string", function() + local humanoid = getHumanoid() + humanoid.humanoid_class = "class" + + local result = humanoid:tostring() + + assert.matches(result, "humanoid[ -]*class.*class") + assert.matches(result, "Warmth.*Happiness.*Fatigue") + assert.matches(result, "Actions: %[%]") + end) + it("Can add actions to a representation", function() + local humanoid = getHumanoid() + humanoid.action_queue = {{name = "A1", room_type = "room"}, {name = "A2"}} + + local result = humanoid:tostring() + + assert.matches(result, "Actions.*%[A1 %- room, A2%]") + end) + +end) diff -Nru corsix-th-0.30/CorsixTH/Luatest/spec/entities/machine_spec.lua corsix-th-0.62/CorsixTH/Luatest/spec/entities/machine_spec.lua --- corsix-th-0.30/CorsixTH/Luatest/spec/entities/machine_spec.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/spec/entities/machine_spec.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,76 @@ +--[[ Copyright (c) 2014 Pavel "sofo" Schoffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +require("class_test_base") + +require("entity") +require("entities/object") +require("entities/machine") + +describe("object.lua: ", function() + local stub_world = {map = {}} + local tile_x, tile_y, direction = 10, 10, "west" + + local function createMachineWithFakeInput() + stub(stub_world, "getLocalPlayerHospital") + stub(stub_world, "addObjectToTile") + stub(stub_world, "clearCaches") + local offset = {0, 0} + local orientation = { + render_attach_position = offset, + use_position = {0, 0} + } + local fake_object_type = { + ticks = false, + idle_animations = {west = true}, + orientations = {west = orientation} + } + return Machine(stub_world, fake_object_type, tile_x, tile_y, direction) + end + + it("can update dynamic Info", function() + local machine = createMachineWithFakeInput() + machine:updateDynamicInfo() + assert.are.equal(1, machine.times_used) + assert.are.equal(1, machine.total_usage) + end) + it("can transfer state", function() + local machine1 = createMachineWithFakeInput() + machine1:updateDynamicInfo() + local machine2 = createMachineWithFakeInput() + + machine2:setState(machine1:getState()) + + assert.are.equal(machine1.times_used, machine2.times_used) + assert.are.equal(machine1.total_usage, machine2.total_usage) + end) + it("setting null state doesn't clear values", function() + local machine = createMachineWithFakeInput() + machine:updateDynamicInfo() + + assert.are.equal(1, machine.times_used) + assert.are.equal(1, machine.total_usage) + + machine:setState(nil) + + assert.are.equal(1, machine.times_used) + assert.are.equal(1, machine.total_usage) + end) +end) diff -Nru corsix-th-0.30/CorsixTH/Luatest/spec/entities/object_spec.lua corsix-th-0.62/CorsixTH/Luatest/spec/entities/object_spec.lua --- corsix-th-0.30/CorsixTH/Luatest/spec/entities/object_spec.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/spec/entities/object_spec.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,53 @@ +--[[ Copyright (c) 2014 Edvin "Lego3" Linge + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +require("class_test_base") + +require("entity") +require("entities.object") + +describe("object.lua: ", function() + local stub_world = {map = {}} + local fake_object_type = {ticks = false, idle_animations = {west = true}} + local tile_x, tile_y, direction = 10, 10, "west" + + local function createObjectWithFakeInput() + stub(stub_world, "getLocalPlayerHospital") + stub(stub_world, "addObjectToTile") + stub(stub_world, "clearCaches") + return Object(stub_world, fake_object_type, tile_x, tile_y, direction) + end + + it("can create Object objects", function() + local object = createObjectWithFakeInput() + + assert.are.equal(fake_object_type, object.object_type) + assert.are.equal(stub_world.map, object.world.map) + end) + it("can transfer state", function() + local object1 = createObjectWithFakeInput() + object1.times_used = object1.times_used + 7 + local object2 = createObjectWithFakeInput() + assert.are_not.equal(object1.times_used, object2.times_used) + + object2:setState(object1:getState()) + assert.are.equal(object1.times_used, object2.times_used) + end) +end) diff -Nru corsix-th-0.30/CorsixTH/Luatest/spec/entities/staff_spec.lua corsix-th-0.62/CorsixTH/Luatest/spec/entities/staff_spec.lua --- corsix-th-0.30/CorsixTH/Luatest/spec/entities/staff_spec.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/spec/entities/staff_spec.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,44 @@ +--[[ Copyright (c) 2018 Pavel "sofo" Schoffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +require("class_test_base") + +require("entity") +require("entities.humanoid") +require("entities.staff") + +describe("Staff:", function() + local function getStaff() + local animation = {setHitTestResult = function() end} + return Staff(animation) + end + + it("Can represent doctor as a string", function() + local doctor = getStaff() + doctor.humanoid_class = "Doctor" + local name = "WHITMAN" + doctor.profile = {skill = 0.5, is_psychiatrist = 0.5, name = name} + + local result = doctor:tostring() + + assert.matches(result, "humanoid.*" .. name .. ".*class.*Doctor") + assert.matches(result, "Skills.*0%.5.*Psych.*0%.5") + end) +end) diff -Nru corsix-th-0.30/CorsixTH/Luatest/TH.lua corsix-th-0.62/CorsixTH/Luatest/TH.lua --- corsix-th-0.30/CorsixTH/Luatest/TH.lua 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Luatest/TH.lua 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,76 @@ +--[[ Copyright (c) 2014 Edvin "Lego3" Linge + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +-- A stub implementation of the TH C++ object, to be able to run +-- unit tests without any backend. + +TheApp = { + gfx = { + loadMainCursor = function() end, + loadSpriteTable = function() end, + loadFont = function() return { + draw = function() end, + drawWrapped = function() end, + } end, + }, + runtime_config = {}, + config = { + width = 600, + height = 800, + }, + world = { + speed = "Normal", + isCurrentSpeed = function(self, s) return s == self.speed end, + gameLog = function() end, + }, +} + +local sub_S = setmetatable({key = ''}, { + __index = function(t, k) + t.key = t.key .. '.' .. k + return t + end, + + __tostring = function(t) + return t.key + end, +}) + +_G['_S'] = setmetatable({key = ''}, { + __index = function(_, k) + sub_S.key = '_S.' .. k + return sub_S + end, + + __tostring = function(_) + return '_S' + end, +}) + +return { + animation = function() + return { + setHitTestResult = function() end, + setAnimation = function() end, + setDrawingLayer = function() end, + setTile = function() end, + } + end +} Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/CorsixTH/__MACOSX/SDLMain/._SDLMain.m and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/CorsixTH/__MACOSX/SDLMain/._SDLMain.m differ diff -Nru corsix-th-0.30/CorsixTH/RequiredResources.txt corsix-th-0.62/CorsixTH/RequiredResources.txt --- corsix-th-0.30/CorsixTH/RequiredResources.txt 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/RequiredResources.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -# rsync compatible filter file which is used post-build -# to help with copying the required resources into the -# bundles for the Mac build. - -- .svn -- .DS_Store -- CVS -+ CorsixTH.lua -+ Lua/ -+ Lua/** -+ Levels/ -+ Levels/* -+ Bitmap/ -+ Bitmap/aux_ui.* -+ Bitmap/tree_ctrl.* -+ Bitmap/mainmenu1080.dat -+ Bitmap/mainmenu1080.pal -- * diff -Nru corsix-th-0.30/CorsixTH/run-corsix-th-dev.sh.in corsix-th-0.62/CorsixTH/run-corsix-th-dev.sh.in --- corsix-th-0.30/CorsixTH/run-corsix-th-dev.sh.in 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/run-corsix-th-dev.sh.in 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,3 @@ +#!/bin/sh + +"@CMAKE_CURRENT_BINARY_DIR@/corsix-th" --interpreter="@CMAKE_SOURCE_DIR@/CorsixTH/CorsixTH.lua" $@ diff -Nru corsix-th-0.30/CorsixTH/run-corsix-th-dev.sh.in.apple corsix-th-0.62/CorsixTH/run-corsix-th-dev.sh.in.apple --- corsix-th-0.30/CorsixTH/run-corsix-th-dev.sh.in.apple 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/run-corsix-th-dev.sh.in.apple 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,3 @@ +#!/bin/sh + +"@CMAKE_CURRENT_BINARY_DIR@/CorsixTH.app/Contents/MacOS/CorsixTH" --interpreter="@CMAKE_SOURCE_DIR@/CorsixTH/CorsixTH.lua" $@ diff -Nru corsix-th-0.30/CorsixTH/SDLMain/CMakeLists.txt corsix-th-0.62/CorsixTH/SDLMain/CMakeLists.txt --- corsix-th-0.30/CorsixTH/SDLMain/CMakeLists.txt 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/SDLMain/CMakeLists.txt 2018-07-21 11:13:17.000000000 +0000 @@ -1,8 +1,6 @@ -IF(APPLE) - find_package(SDL REQUIRED) - - set(CMAKE_OSX_ARCHITECTURES "x86_64;i386;ppc") - include_directories(${SDL_INCLUDE_DIR}) - - add_library (SDLmain STATIC SDLMain.m) -endif(APPLE) +if(APPLE) + find_package(SDL2 REQUIRED) + set(CMAKE_OSX_ARCHITECTURES "x86_64") + include_directories(${SDL_INCLUDE_DIR}) + add_library (SDL2main STATIC SDLMain.m) +endif() diff -Nru corsix-th-0.30/CorsixTH/Src/bootstrap.cpp corsix-th-0.62/CorsixTH/Src/bootstrap.cpp --- corsix-th-0.30/CorsixTH/Src/bootstrap.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/bootstrap.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -20,8 +20,10 @@ SOFTWARE. */ #include "lua.hpp" -#include +#include "th_lua.h" #include "config.h" +#include +#include /* Often, an error occurs during the CorsixTH startup process. Examples of such errors include: @@ -38,22 +40,17 @@ homemade bitmap font, as we cannot rely on TH fonts being present). */ -int g_iBootstrapCodeLineNumStart = __LINE__ + 2; -const char* g_sBootstrapCode[] = { +static const int first_bootstrap_code_line_number = __LINE__ + 2; +static const char* bootstrap_code[] = { "local lines, dat, tab, pal, err = {}, ...", "local function t(s) return s:gsub('\\t', ' ') end", "for s in tostring(err):gmatch'[^\\r\\n]+' do lines[#lines+1] = t(s) end", "local TH, SDL, rnc = require'TH', require'sdl', require'rnc'.decompress", "if not SDL.init('video') then error'Unable to initialise video' end", - "SDL.wm.setCaption('CorsixTH - Error during startup')", "local w, h = 640, 480", -#ifdef CORSIX_TH_USE_OGL_RENDERER - "local modes = {'hardware', 'doublebuf', 'opengl'}", -#else - "local modes = {'hardware', 'doublebuf'}", -#endif "local function dernc(x) return x:match'^RNC' and assert(rnc(x)) or x end", - "local video = TheApp and TheApp.video or TH.surface(w, h, unpack(modes))", + "local video = TheApp and TheApp.video or TH.surface(w, h)", + "video:setCaption('CorsixTH - Error during startup')", "local palette, sheet, font = TH.palette(), TH.sheet(), TH.bitmap_font()", "if not palette:load(dernc(pal)) then error'Unable to load palette' end", "sheet:setPalette(palette)", @@ -89,12 +86,12 @@ " end))", " if running then print(e) end", "until where ~= 'callback'", - NULL + nullptr }; /* Start autogenerated content */ /* Data from bootstrap_font.tab inserted by mkbootstrap.lua: */ -const unsigned char g_aBootstrapFontTab[] = { +static const std::vector bootstrap_font_tab = { 0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x05, 0x46, 0x00, 0x00, 0x01, 0xE1, 0xFB, 0xF2, 0x66, 0x51, 0xBE, 0xEF, 0x0C, 0x09, 0x59, 0x60, 0x10, 0x34, 0x43, 0x54, 0xA6, 0x46, 0xA2, 0x08, 0x00, 0xA0, 0xC4, 0x01, 0xF6, 0x3D, 0x00, 0x00, 0xAF, @@ -136,7 +133,7 @@ 0x29, 0x40, 0x52, 0x7D, 0x0F }; /* Data from bootstrap_font.dat inserted by mkbootstrap.lua: */ -const unsigned char g_aBootstrapFontDat[] = { +static const std::vector bootstrap_font_dat = { 0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x13, 0x68, 0x00, 0x00, 0x05, 0xEC, 0xD3, 0x6C, 0x7E, 0xAB, 0xBE, 0xEF, 0x94, 0x90, 0x81, 0x61, 0x50, 0x34, 0x44, 0x33, 0x33, 0x53, 0x66, 0x64, 0x64, 0x26, 0x20, 0x60, 0x47, 0x1E, 0x01, 0xFF, 0x84, @@ -257,7 +254,7 @@ 0x02, 0xAC, 0x9A, 0x43, 0x10, 0xB5, 0x0A, 0xA0, 0x17, 0x1C, 0xA6, 0x00, 0x9B }; /* Data from bootstrap_font.pal inserted by mkbootstrap.lua: */ -const unsigned char g_aBootstrapFontPal[] = { +static const std::vector bootstrap_font_pal = { 0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB7, 0xFF, 0x76, 0x79, 0xBE, 0xEF, 0x90, 0x10, 0x90, 0x05, 0x01, 0x02, 0x00, 0x00, 0x20, 0x2B, 0x04, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0xB6, 0x00, 0x00, 0x00, @@ -265,7 +262,7 @@ }; /* End autogenerated content */ -// Lua reader function for loading g_sBootstrapCode +// Lua reader function for loading bootstrap_code static const char* read_bootstrap_line(lua_State *L, void *data, size_t *size) { int& iLine = *reinterpret_cast(data); @@ -277,36 +274,39 @@ } else { - const char *s = g_sBootstrapCode[iLine / 2]; - if(s == NULL) + const char *s = bootstrap_code[iLine / 2]; + if(s == nullptr) { *size = 0; - return NULL; + return nullptr; } else { - *size = strlen(s); + *size = std::strlen(s); return s; } } } -int Bootstrap_lua_resources(lua_State *L) +static inline void push(lua_State *L, std::vector data) { -#define push(x) lua_pushlstring(L, reinterpret_cast(x), sizeof(x)) - push(g_aBootstrapFontDat); - push(g_aBootstrapFontTab); - push(g_aBootstrapFontPal); -#undef push + lua_pushlstring(L, reinterpret_cast(data.data()), data.size()); +} + +int bootstrap_lua_resources(lua_State *L) +{ + push(L, bootstrap_font_dat); + push(L, bootstrap_font_tab); + push(L, bootstrap_font_pal); return 3; } -int Bootstrap_lua_error_report(lua_State *L) +int bootstrap_lua_error_report(lua_State *L) { - int iLine = -g_iBootstrapCodeLineNumStart; - if(lua_load(L, read_bootstrap_line, &iLine, "@bootstrap.cpp") == 0) + int iLine = -first_bootstrap_code_line_number; + if(luaT_load(L, read_bootstrap_line, &iLine, "@bootstrap.cpp", "t") == 0) { - Bootstrap_lua_resources(L); + bootstrap_lua_resources(L); lua_pushvalue(L, 1); lua_call(L, 4, 0); return 0; diff -Nru corsix-th-0.30/CorsixTH/Src/bootstrap.h corsix-th-0.62/CorsixTH/Src/bootstrap.h --- corsix-th-0.30/CorsixTH/Src/bootstrap.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/bootstrap.h 2018-07-21 11:13:17.000000000 +0000 @@ -25,9 +25,9 @@ #include "lua.hpp" //! Push onto the stack the bootstrap font data file, table file and palette. -int Bootstrap_lua_resources(lua_State *L); +int bootstrap_lua_resources(lua_State *L); //! Provide an onscreen report of the error message on the top of the stack. -int Bootstrap_lua_error_report(lua_State *L); +int bootstrap_lua_error_report(lua_State *L); #endif // CORSIX_TH_BOOTSTRAP_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/config.h.in corsix-th-0.62/CorsixTH/Src/config.h.in --- corsix-th-0.30/CorsixTH/Src/config.h.in 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/config.h.in 2018-07-21 11:13:17.000000000 +0000 @@ -23,21 +23,7 @@ #ifndef CORSIX_TH_CONFIG_H_ #define CORSIX_TH_CONFIG_H_ -/** Rendering engine choice **/ -// SDL - Multiplatform, but suboptimal on some platforms -// DirectX 9 - Windows only, but always has HW accellerated (alpha) blitting -// OpenGL - Faster than SDL on supported platforms, but DX9 may still be -// preferable on Windows (not yet finished, but should work). -#ifndef CORSIX_TH_RENDERING_ENGINE_DEFINED -#cmakedefine CORSIX_TH_USE_OGL_RENDERER -#cmakedefine CORSIX_TH_USE_DX9_RENDERER -#cmakedefine CORSIX_TH_USE_SDL_RENDERER -#endif //CORSIX_TH_RENDERING_ENGINE_DEFINED - -// When OpenGL is used as the rendering engine, try to make use of the -// extension which allows for rendering to a texture. This must be enabled to -// allow the zooming feature to work. -#define CORSIX_TH_USE_OGL_RENDER_TO_TEXTURE +#cmakedefine CORSIX_TH_INTERPRETER_PATH "@CORSIX_TH_INTERPRETER_PATH@" /** Windows Platform SDK usage **/ // When compiling on Windows, the platform SDK should be used. However, when @@ -47,14 +33,6 @@ #define CORSIX_TH_USE_WIN32_SDK #endif -/** SDL options **/ -// On Windows, the default is to use the copy of SDLmain which is included with -// CorsixTH (SDL_main_win32.c), but a prebuilt SDLmain library can be used -// instead. -#ifdef CORSIX_TH_USE_WIN32_SDK -#define CORSIX_TH_USE_INCLUDED_SDL_MAIN -#endif - /** Audio options **/ // SDL_mixer is used for ingame audio. If this library is not present on your // system, then you can comment out the next line and the game will not have @@ -62,25 +40,19 @@ #cmakedefine CORSIX_TH_USE_SDL_MIXER /** Movie options **/ -// FFMPEG is used for in game movies. If this library is not present on your -// system, then you can comment out the next line and the game will not have -// movies. +// FFMPEG or LibAV are used for in game movies. +// If this library is not present on your system, then you can comment out the +// next line and the game will not have movies. #cmakedefine CORSIX_TH_USE_FFMPEG - +#ifndef CORSIX_TH_USE_FFMPEG +#cmakedefine CORSIX_TH_USE_LIBAV +#endif /** Font options **/ // FreeType2 can be used for font support beyond the CP437 bitmap fonts which // come with Theme Hospital. It must be used if translations like Russian or // Chinese are desired. #cmakedefine CORSIX_TH_USE_FREETYPE2 -/** Environment detection **/ -#if defined(__amd64__) || defined(__IA64__) || defined(__x86_64__) || \ - defined(__x86_64) || defined(_M_IA64) || defined(_IA64) || \ - defined(_M_X64) || defined(_WIN64) || defined(__ia64__) || \ - defined(__amd64) || defined (_LP64) || defined(__ia64) -#define CORSIX_TH_64BIT -#endif - #ifdef _MSC_VER #define CORSIX_TH_USE_PACK_PRAGMAS 1 #define CORSIX_TH_PACKED_FLAGS @@ -93,23 +65,27 @@ #ifndef __STDC_CONSTANT_MACROS # define __STDC_CONSTANT_MACROS #endif -#include -#cmakedefine CORSIX_TH_HAS_STDINT_H -#cmakedefine CORSIX_TH_HAS_MALLOC_H -#cmakedefine CORSIX_TH_HAS_ALLOCA_H -#ifdef CORSIX_TH_HAS_STDINT_H -#include -#else -// Some compilers (e.g. MSVC) don't have stdint.h, so define the bits we use -// from stdint.h -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef signed __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -#endif // CORSIX_TH_HAS_STDINT +#include +#include + +/** Environment detection **/ +#if UINTPTR_MAX == UINT64_MAX +#define CORSIX_TH_64BIT +#endif + +// We bring in the most common stddef and stdint types to avoid typing +using std::size_t; +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; +using std::int8_t; +using std::int16_t; +using std::int32_t; +using std::int64_t; + +/** Visual Leak Detector **/ +// In Visual Studio, Visual Leak Detector can be used to find memory leaks. +#cmakedefine CORSIX_TH_USE_VLD #endif // CORSIX_TH_CONFIG_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/cp437_table.h corsix-th-0.62/CorsixTH/Src/cp437_table.h --- corsix-th-0.30/CorsixTH/Src/cp437_table.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/cp437_table.h 2018-07-21 11:13:17.000000000 +0000 @@ -1,4 +1,4 @@ -static const uint16_t g_aCP437toUnicode[0x80] = { +static const uint16_t cp437_to_unicode_table[0x80] = { /* 0x00 through 0x7F need no translation */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, diff -Nru corsix-th-0.30/CorsixTH/Src/cp936_table.h corsix-th-0.62/CorsixTH/Src/cp936_table.h --- corsix-th-0.30/CorsixTH/Src/cp936_table.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/cp936_table.h 2018-07-21 11:13:17.000000000 +0000 @@ -4,7 +4,7 @@ // 1st byte is between 0x81 and 0xFE (subtract 0x81 for table lookup) // 2nd byte is between 0x40 and 0xFE (subtract 0x40 for table lookup) // Unspecified codes are mapped to 0x003F -static const uint16_t g_aCP936toUnicode[126][191] = { +static const uint16_t cp936_to_unicode_table[126][191] = { { 0x4E02, 0x4E04, 0x4E05, 0x4E06, 0x4E0F, 0x4E12, 0x4E17, 0x4E1F, 0x4E20, 0x4E21, 0x4E23, 0x4E26, 0x4E29, 0x4E2E, 0x4E2F, 0x4E31, diff -Nru corsix-th-0.30/CorsixTH/Src/iso_fs.cpp corsix-th-0.62/CorsixTH/Src/iso_fs.cpp --- corsix-th-0.30/CorsixTH/Src/iso_fs.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/iso_fs.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -21,71 +21,64 @@ */ #include "iso_fs.h" -#include -#include -#include -#ifdef CORSIX_TH_HAS_MALLOC_H -#include // for alloca -#endif -#ifdef CORSIX_TH_HAS_ALLOCA_H -#include -#endif +#include +#include +#include +#include #include -IsoFilesystem::IsoFilesystem() +iso_filesystem::iso_filesystem() { - m_fRawFile = NULL; - m_sError = NULL; - m_pFiles = NULL; - m_iNumFiles = 0; - m_iFileTableSize = 0; - m_cPathSeparator = '\\'; + raw_file = nullptr; + error = nullptr; + files = nullptr; + file_count = 0; + file_table_size = 0; + path_seperator = '\\'; } -IsoFilesystem::~IsoFilesystem() +iso_filesystem::~iso_filesystem() { - _clear(); + clear(); } -void IsoFilesystem::_clear() +void iso_filesystem::clear() { - if(m_sError) - { - delete[] m_sError; - m_sError = NULL; - } - if(m_pFiles) + delete[] error; + error = nullptr; + + if(files) { - for(size_t i = 0; i < m_iNumFiles; ++i) - delete[] m_pFiles[i].sPath; - delete[] m_pFiles; - m_pFiles = NULL; - m_iNumFiles = 0; - m_iFileTableSize = 0; + for(size_t i = 0; i < file_count; ++i) + delete[] files[i].path; + delete[] files; + files = nullptr; + file_count = 0; + file_table_size = 0; } } -void IsoFilesystem::setPathSeparator(char cSeparator) +void iso_filesystem::set_path_separator(char cSeparator) { - m_cPathSeparator = cSeparator; + path_seperator = cSeparator; } -enum IsoVolumeDescriptorType +enum iso_volume_descriptor_type : uint8_t { - VDT_PRIVARY_VOLUME = 0x01, + vdt_privary_volume = 0x01, // Other type numbers are either reserved for future use, or are not // interesting to us. - VDT_TERMINATOR = 0xFF, + vdt_terminator = 0xFF, }; -enum IsoDirEntFlag +enum iso_dir_ent_flag : uint8_t { - DEF_HIDDEN = 0x01, - DEF_DIRECTORY = 0x02, - DEF_MULTI_EXTENT = 0x80, + def_hidden = 0x01, + def_directory = 0x02, + def_multi_extent = 0x80, }; -template static inline T ReadNativeInt(const unsigned char *p) +template static inline T read_native_int(const uint8_t *p) { // ISO 9660 commonly encodes multi-byte integers as little endian followed // by big endian. Note that the first byte of iEndianness will be a zero on @@ -94,31 +87,31 @@ return reinterpret_cast(p)[*reinterpret_cast(&iEndianness)]; } -bool IsoFilesystem::initialise(FILE* fRawFile) +bool iso_filesystem::initialise(FILE* fRawFile) { - m_fRawFile = fRawFile; - _clear(); + raw_file = fRawFile; + clear(); // Until we know better, assume that sectors are 2048 bytes. - m_iSectorSize = 2048; + sector_size = 2048; // The first 16 sectors are reserved for bootable media. // Volume descriptor records follow this, with one record per sector. - for(uint32_t iSector = 16; _seekToSector(iSector); ++iSector) + for(uint32_t iSector = 16; seek_to_sector(iSector); ++iSector) { - unsigned char aBuffer[190]; - if(!_readData(sizeof(aBuffer), aBuffer)) + uint8_t aBuffer[190]; + if(!read_data(sizeof(aBuffer), aBuffer)) break; // CD001 is a standard identifier, \x01 is a version number - if(memcmp(aBuffer + 1, "CD001\x01", 6) == 0) + if(std::memcmp(aBuffer + 1, "CD001\x01", 6) == 0) { - if(aBuffer[0] == VDT_PRIVARY_VOLUME) + if(aBuffer[0] == vdt_privary_volume) { - m_iSectorSize = ReadNativeInt(aBuffer + 128); - _findHospDirectory(aBuffer + 156, 34, 0); - if(m_iNumFiles == 0) + sector_size = read_native_int(aBuffer + 128); + find_hosp_directory(aBuffer + 156, 34, 0); + if(file_count == 0) { - _setError("Could not find Theme Hospital data directory."); + set_error("Could not find Theme Hospital data directory."); return false; } else @@ -126,32 +119,32 @@ return true; } } - else if(aBuffer[0] == VDT_TERMINATOR) + else if(aBuffer[0] == vdt_terminator) break; } } - _setError("Could not find primary volume descriptor."); + set_error("Could not find primary volume descriptor."); return false; } -int IsoFilesystem::_fileNameComp(const void* lhs, const void* rhs) +int iso_filesystem::filename_compare(const void* lhs, const void* rhs) { - return strcmp( - reinterpret_cast(lhs)->sPath, - reinterpret_cast(rhs)->sPath); + return std::strcmp( + reinterpret_cast(lhs)->path, + reinterpret_cast(rhs)->path); } -char IsoFilesystem::_normalise(char c) +char iso_filesystem::normalise(char c) { if(c == '_') // underscore to hyphen return '-'; else if('a' <= c && c <= 'z') // ASCII lowercase to ASCII uppercase - return c - 'a' + 'A'; + return static_cast(c - 'a' + 'A'); else return c; } -void IsoFilesystem::_trimIdentifierVersion(const unsigned char* sIdent, uint8_t& iLength) +void iso_filesystem::trim_identifier_version(const uint8_t* sIdent, uint8_t& iLength) { for(uint8_t i = 0; i < iLength; ++i) { @@ -163,7 +156,7 @@ } } -int IsoFilesystem::_findHospDirectory(const unsigned char *pDirEnt, int iDirEntsSize, int iLevel) +int iso_filesystem::find_hosp_directory(const uint8_t *pDirEnt, int iDirEntsSize, int iLevel) { // Sanity check // Apart from at the root level, directory record arrays must take up whole @@ -172,7 +165,7 @@ if((iLevel != 0 && (iDirEntsSize & 0x7FF)) || iLevel > 16) return 0; - unsigned char *pBuffer = NULL; + uint8_t *pBuffer = nullptr; uint32_t iBufferSize = 0; for(; iDirEntsSize > 0; iDirEntsSize -= *pDirEnt, pDirEnt += *pDirEnt) { @@ -183,12 +176,12 @@ continue; } - uint32_t iDataSector = ReadNativeInt(pDirEnt + 2); - uint32_t iDataLength = ReadNativeInt(pDirEnt + 10); + uint32_t iDataSector = read_native_int(pDirEnt + 2); + uint32_t iDataLength = read_native_int(pDirEnt + 10); uint8_t iFlags = pDirEnt[25]; uint8_t iIdentLength = pDirEnt[32]; - _trimIdentifierVersion(pDirEnt + 33, iIdentLength); - if(iFlags & DEF_DIRECTORY) + trim_identifier_version(pDirEnt + 33, iIdentLength); + if(iFlags & def_directory) { // The names "\x00" and "\x01" are used for the current directory // the parent directory respectively. We only want to visit these @@ -199,15 +192,15 @@ { delete[] pBuffer; iBufferSize = iDataLength; - pBuffer = new unsigned char[iBufferSize]; + pBuffer = new uint8_t[iBufferSize]; } - if(_seekToSector(iDataSector) && _readData(iDataLength, pBuffer)) + if(seek_to_sector(iDataSector) && read_data(iDataLength, pBuffer)) { - int iFoundLevel = _findHospDirectory(pBuffer, iDataLength, iLevel + 1); + int iFoundLevel = find_hosp_directory(pBuffer, iDataLength, iLevel + 1); if(iFoundLevel != 0) { if(iFoundLevel == 2) - _buildFileLookupTable(iDataSector, iDataLength, ""); + build_file_lookup_table(iDataSector, iDataLength, ""); delete[] pBuffer; return iFoundLevel + 1; } @@ -224,7 +217,7 @@ int i = 0; for(; i < 10; ++i) { - if(_normalise(pDirEnt[33 + i]) != sName[i]) + if(normalise(pDirEnt[33 + i]) != sName[i]) break; } if(i == 10) @@ -239,24 +232,24 @@ return 0; } -void IsoFilesystem::_buildFileLookupTable(uint32_t iSector, int iDirEntsSize, const char* sPrefix) +void iso_filesystem::build_file_lookup_table(uint32_t iSector, int iDirEntsSize, const char* sPrefix) { // Sanity check // Apart from at the root level, directory record arrays must take up whole // sectors, whose sizes are powers of two and at least 2048. // Path lengths shouldn't exceed 256 either (or at least not for the files // which we're interested in). - size_t iLen = strlen(sPrefix); + size_t iLen = std::strlen(sPrefix); if((iLen != 0 && (iDirEntsSize & 0x7FF)) || (iLen > 256)) return; - unsigned char *pBuffer = new unsigned char[iDirEntsSize]; - if(!_seekToSector(iSector) || !_readData(iDirEntsSize, pBuffer)) + uint8_t *pBuffer = new uint8_t[iDirEntsSize]; + if(!seek_to_sector(iSector) || !read_data(iDirEntsSize, pBuffer)) { delete[] pBuffer; return; } - unsigned char *pDirEnt = pBuffer; + uint8_t *pDirEnt = pBuffer; for(; iDirEntsSize > 0; iDirEntsSize -= *pDirEnt, pDirEnt += *pDirEnt) { // There is zero padding so that no record spans multiple sectors. @@ -266,42 +259,42 @@ continue; } - uint32_t iDataSector = ReadNativeInt(pDirEnt + 2); - uint32_t iDataLength = ReadNativeInt(pDirEnt + 10); + uint32_t iDataSector = read_native_int(pDirEnt + 2); + uint32_t iDataLength = read_native_int(pDirEnt + 10); uint8_t iFlags = pDirEnt[25]; uint8_t iIdentLength = pDirEnt[32]; - _trimIdentifierVersion(pDirEnt + 33, iIdentLength); + trim_identifier_version(pDirEnt + 33, iIdentLength); // Build new path char *sPath = new char[iLen + iIdentLength + 2]; - memcpy(sPath, sPrefix, iLen); + std::memcpy(sPath, sPrefix, iLen); #ifdef _MSC_VER #pragma warning(disable: 4996) #endif - std::transform(pDirEnt + 33, pDirEnt + 33 + iIdentLength, sPath + iLen, _normalise); + std::transform(pDirEnt + 33, pDirEnt + 33 + iIdentLength, sPath + iLen, normalise); #ifdef _MSC_VER #pragma warning(default: 4996) #endif sPath[iLen + iIdentLength] = 0; - if(iFlags & DEF_DIRECTORY) + if(iFlags & def_directory) { // None of the directories which we're interested in have length 1. // This also avoids the dummy "current" and "parent" directories. if(iIdentLength > 1) { - sPath[iLen + iIdentLength] = m_cPathSeparator; + sPath[iLen + iIdentLength] = path_seperator; sPath[iLen + iIdentLength + 1] = 0; - _buildFileLookupTable(iDataSector, iDataLength, sPath); + build_file_lookup_table(iDataSector, iDataLength, sPath); } } else { - _file_t *pFile = _allocFileRecord(); - pFile->sPath = sPath; - pFile->iSector = iDataSector; - pFile->iSize = iDataLength; - sPath = NULL; + file_metadata *file = allocate_file_record(); + file->path = sPath; + file->sector = iDataSector; + file->size = iDataLength; + sPath = nullptr; } delete[] sPath; } @@ -311,62 +304,62 @@ { // The lookup table will be ordered by the underlying ordering of the // disk, which isn't quite the ordering we want. - qsort(m_pFiles, m_iNumFiles, sizeof(_file_t), _fileNameComp); + qsort(files, file_count, sizeof(file_metadata), filename_compare); } } -IsoFilesystem::_file_t* IsoFilesystem::_allocFileRecord() +iso_filesystem::file_metadata* iso_filesystem::allocate_file_record() { - if(m_iNumFiles == m_iFileTableSize) + if(file_count == file_table_size) { - size_t iNewTableSize = m_iFileTableSize * 2 + 1; - _file_t* pNewFiles = new _file_t[iNewTableSize]; - memcpy(pNewFiles, m_pFiles, sizeof(_file_t) * m_iNumFiles); - delete[] m_pFiles; - m_pFiles = pNewFiles; - m_iFileTableSize = iNewTableSize; + size_t iNewTableSize = file_table_size * 2 + 1; + file_metadata* pNewFiles = new file_metadata[iNewTableSize]; + std::memcpy(pNewFiles, files, sizeof(file_metadata) * file_count); + delete[] files; + files = pNewFiles; + file_table_size = iNewTableSize; } - return m_pFiles + m_iNumFiles++; + return files + file_count++; } -void IsoFilesystem::visitDirectoryFiles(const char* sPath, +void iso_filesystem::visit_directory_files(const char* sPath, void (*fnCallback)(void*, const char*), void* pCallbackData) const { - size_t iLen = strlen(sPath) + 1; - char *sNormedPath = (char*)alloca(iLen); + size_t iLen = std::strlen(sPath) + 1; + std::vector sNormedPath(iLen); for(size_t i = 0; i < iLen; ++i) - sNormedPath[i] = _normalise(sPath[i]); + sNormedPath[i] = normalise(sPath[i]); // Inefficient (better would be to binary search for first and last files // which begin with sPath), but who cares - this isn't called often - for(size_t i = 0; i < m_iNumFiles; ++i) + for(size_t i = 0; i < file_count; ++i) { - const char *sName = m_pFiles[i].sPath; - if(strlen(sName) >= iLen && memcmp(sNormedPath, sName, iLen - 1) == 0) + const char *sName = files[i].path; + if(std::strlen(sName) >= iLen && std::memcmp(sNormedPath.data(), sName, iLen - 1) == 0) { sName += iLen - 1; - if(*sName == m_cPathSeparator) + if(*sName == path_seperator) ++sName; - if(strchr(sName, m_cPathSeparator) == NULL) + if(std::strchr(sName, path_seperator) == nullptr) fnCallback(pCallbackData, sName); } } } -IsoFilesystem::file_handle_t IsoFilesystem::findFile(const char* sPath) const +iso_filesystem::file_handle iso_filesystem::find_file(const char* sPath) const { - size_t iLen = strlen(sPath) + 1; - char *sNormedPath = (char*)alloca(iLen); + size_t iLen = std::strlen(sPath) + 1; + std::vector sNormedPath(iLen); for(size_t i = 0; i < iLen; ++i) - sNormedPath[i] = _normalise(sPath[i]); + sNormedPath[i] = normalise(sPath[i]); // Standard binary search over sorted list of files - int iLower = 0, iUpper = static_cast(m_iNumFiles); + int iLower = 0, iUpper = static_cast(file_count); while(iLower != iUpper) { int iMid = (iLower + iUpper) / 2; - int iComp = strcmp(sNormedPath, m_pFiles[iMid].sPath); + int iComp = std::strcmp(sNormedPath.data(), files[iMid].path); if(iComp == 0) return iMid + 1; else if(iComp < 0) @@ -377,78 +370,78 @@ return 0; } -uint32_t IsoFilesystem::getFileSize(file_handle_t iFile) const +uint32_t iso_filesystem::get_file_size(file_handle iFile) const { - if(iFile <= 0 || static_cast(iFile) > m_iNumFiles) + if(iFile <= 0 || static_cast(iFile) > file_count) return 0; else - return m_pFiles[iFile - 1].iSize; + return files[iFile - 1].size; } -bool IsoFilesystem::getFileData(file_handle_t iFile, unsigned char *pBuffer) +bool iso_filesystem::get_file_data(file_handle iFile, uint8_t *pBuffer) { - if(iFile <= 0 || static_cast(iFile) > m_iNumFiles) + if(iFile <= 0 || static_cast(iFile) > file_count) { - _setError("Invalid file handle."); + set_error("Invalid file handle."); return false; } else { - return _seekToSector(m_pFiles[iFile - 1].iSector) && - _readData(m_pFiles[iFile - 1].iSize, pBuffer); + return seek_to_sector(files[iFile - 1].sector) && + read_data(files[iFile - 1].size, pBuffer); } } -const char* IsoFilesystem::getError() const +const char* iso_filesystem::get_error() const { - return m_sError; + return error; } -bool IsoFilesystem::_seekToSector(uint32_t iSector) +bool iso_filesystem::seek_to_sector(uint32_t iSector) { - if(!m_fRawFile) + if(!raw_file) { - _setError("No raw file."); + set_error("No raw file."); return false; } - if(fseek(m_fRawFile, m_iSectorSize * static_cast(iSector), SEEK_SET) == 0) + if(std::fseek(raw_file, sector_size * static_cast(iSector), SEEK_SET) == 0) return true; else { - _setError("Unable to seek to sector %i.", static_cast(iSector)); + set_error("Unable to seek to sector %i.", static_cast(iSector)); return false; } } -bool IsoFilesystem::_readData(uint32_t iByteCount, unsigned char *pBuffer) +bool iso_filesystem::read_data(uint32_t iByteCount, uint8_t *pBuffer) { - if(!m_fRawFile) + if(!raw_file) { - _setError("No raw file."); + set_error("No raw file."); return false; } - if(fread(pBuffer, 1, iByteCount, m_fRawFile) == iByteCount) + if(std::fread(pBuffer, 1, iByteCount, raw_file) == iByteCount) return true; else { - _setError("Unable to read %i bytes.", static_cast(iByteCount)); + set_error("Unable to read %i bytes.", static_cast(iByteCount)); return false; } } -void IsoFilesystem::_setError(const char* sFormat, ...) +void iso_filesystem::set_error(const char* sFormat, ...) { - if(m_sError == NULL) + if(error == nullptr) { // None of the errors which we generate will be longer than 1024. - m_sError = new char[1024]; + error = new char[1024]; } va_list a; va_start(a, sFormat); #ifdef _MSC_VER #pragma warning(disable: 4996) #endif - vsprintf(m_sError, sFormat, a); + std::vsprintf(error, sFormat, a); #ifdef _MSC_VER #pragma warning(default: 4996) #endif @@ -457,21 +450,21 @@ static int l_isofs_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_isofs_set_path_separator(lua_State *L) { - IsoFilesystem *pSelf = luaT_testuserdata(L); - pSelf->setPathSeparator(luaL_checkstring(L, 2)[0]); + iso_filesystem *pSelf = luaT_testuserdata(L); + pSelf->set_path_separator(luaL_checkstring(L, 2)[0]); lua_settop(L, 1); return 1; } static int l_isofs_set_root(lua_State *L) { - IsoFilesystem *pSelf = luaT_testuserdata(L); + iso_filesystem *pSelf = luaT_testuserdata(L); FILE *fIso = *luaT_testuserdata(L, 2); if(pSelf->initialise(fIso)) { @@ -483,30 +476,30 @@ else { lua_pushnil(L); - lua_pushstring(L, pSelf->getError()); + lua_pushstring(L, pSelf->get_error()); return 2; } } static int l_isofs_read_contents(lua_State *L) { - IsoFilesystem *pSelf = luaT_testuserdata(L); + iso_filesystem *pSelf = luaT_testuserdata(L); const char* sFilename = luaL_checkstring(L, 2); - IsoFilesystem::file_handle_t iFile = pSelf->findFile(sFilename); - if(!IsoFilesystem::isHandleGood(iFile)) + iso_filesystem::file_handle iFile = pSelf->find_file(sFilename); + if(!iso_filesystem::isHandleGood(iFile)) { lua_pushnil(L); lua_pushfstring(L, "Could not find \'%s\' in .iso image", sFilename); return 2; } - void* pBuffer = lua_newuserdata(L, pSelf->getFileSize(iFile)); - if(!pSelf->getFileData(iFile, reinterpret_cast(pBuffer))) + void* pBuffer = lua_newuserdata(L, pSelf->get_file_size(iFile)); + if(!pSelf->get_file_data(iFile, reinterpret_cast(pBuffer))) { lua_pushnil(L); - lua_pushstring(L, pSelf->getError()); + lua_pushstring(L, pSelf->get_error()); return 2; } - lua_pushlstring(L, reinterpret_cast(pBuffer), pSelf->getFileSize(iFile)); + lua_pushlstring(L, reinterpret_cast(pBuffer), pSelf->get_file_size(iFile)); return 1; } @@ -520,11 +513,11 @@ static int l_isofs_list_files(lua_State *L) { - IsoFilesystem *pSelf = luaT_testuserdata(L); + iso_filesystem *pSelf = luaT_testuserdata(L); const char* sPath = luaL_checkstring(L, 2); lua_settop(L, 2); lua_newtable(L); - pSelf->visitDirectoryFiles(sPath, l_isofs_list_files_callback, L); + pSelf->visit_directory_files(sPath, l_isofs_list_files_callback, L); return 1; } @@ -542,7 +535,7 @@ lua_pushvalue(L, -1); lua_replace(L, luaT_environindex); - lua_pushcclosure(L, luaT_stdgc, 0); + luaT_pushcclosure(L, luaT_stdgc, 0); lua_setfield(L, -2, "__gc"); // Methods table @@ -554,7 +547,7 @@ lua_setfield(L, -2, "setPathSeparator"); lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); - lua_pushcclosure(L, l_isofs_set_root, 1); + luaT_pushcclosure(L, l_isofs_set_root, 1); lua_setfield(L, -2, "setRoot"); lua_pushcfunction(L, l_isofs_read_contents); diff -Nru corsix-th-0.30/CorsixTH/Src/iso_fs.h corsix-th-0.62/CorsixTH/Src/iso_fs.h --- corsix-th-0.30/CorsixTH/Src/iso_fs.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/iso_fs.h 2018-07-21 11:13:17.000000000 +0000 @@ -22,7 +22,7 @@ #include "config.h" #include "th_lua.h" -#include +#include //! Layer for reading Theme Hospital files out of an .iso disk image /*! @@ -33,14 +33,14 @@ searches for the Theme Hospital data files, and can then be used to read these data files. */ -class IsoFilesystem +class iso_filesystem { public: - IsoFilesystem(); - ~IsoFilesystem(); + iso_filesystem(); + ~iso_filesystem(); //! Set the character to be used between components in file paths - void setPathSeparator(char cSeparator); + void set_path_separator(char cSeparator); //! Load an .iso disk image and search for Theme Hospital data files /*! @@ -55,16 +55,16 @@ /*! Can be called after initialise() or getFileData() return false. */ - const char* getError() const; + const char* get_error() const; - typedef int file_handle_t; + using file_handle = int; //! Find a file in the loaded .iso disk image /*! If (and only if) the given file could not be found, then isHandleGood() will return false on the returned handle. */ - file_handle_t findFile(const char* sPath) const; + file_handle find_file(const char* sPath) const; //! Iterate all files of the .iso disk image within a given directory /*! @@ -74,18 +74,18 @@ of a file which is in sPath. \param pCallbackData Opaque value to be called to fnCallback. */ - void visitDirectoryFiles(const char* sPath, + void visit_directory_files(const char* sPath, void (*fnCallback)(void*, const char*), void* pCallbackData) const; //! Test if a file handle from findFile() is good or is invalid - static inline bool isHandleGood(file_handle_t x) {return x != 0;} + static inline bool isHandleGood(file_handle x) {return x != 0;} //! Get the size (in bytes) of a file in the loaded .iso disk image /*! \param iFile A file handle returned by findFile() */ - uint32_t getFileSize(file_handle_t iFile) const; + uint32_t get_file_size(file_handle iFile) const; //! Get the contents of a file in the loaded .iso disk image /*! @@ -93,35 +93,35 @@ \param pBuffer The buffer to place the resulting data in \return true on success, false on failure - call getError() for reason */ - bool getFileData(file_handle_t iFile, unsigned char *pBuffer); + bool get_file_data(file_handle iFile, uint8_t *pBuffer); -protected: - struct _file_t +private: + struct file_metadata { - char *sPath; - uint32_t iSector; - uint32_t iSize; + char *path; + uint32_t sector; + uint32_t size; }; - FILE* m_fRawFile; - char* m_sError; - _file_t* m_pFiles; - size_t m_iNumFiles; - size_t m_iFileTableSize; - long m_iSectorSize; - char m_cPathSeparator; + FILE* raw_file; + char* error; + file_metadata* files; + size_t file_count; + size_t file_table_size; + long sector_size; + char path_seperator; //! Free any memory in use - void _clear(); + void clear(); //! Set the last error, printf-style - void _setError(const char* sFormat, ...); + void set_error(const char* sFormat, ...); //! Seek to a logical sector of the disk image - bool _seekToSector(uint32_t iSector); + bool seek_to_sector(uint32_t iSector); //! Read data from the disk image - bool _readData(uint32_t iByteCount, unsigned char *pBuffer); + bool read_data(uint32_t iByteCount, uint8_t *pBuffer); //! Scan the given array of directory entries for a Theme Hospital file /*! @@ -133,7 +133,7 @@ contains a Theme Hospital data file. 2 if the given array is the top-level Theme Hospital data directory. Other values otherwise. */ - int _findHospDirectory(const unsigned char *pDirEnt, int iDirEntsSize, int iLevel); + int find_hosp_directory(const uint8_t *pDirEnt, int iDirEntsSize, int iLevel); //! Build the list of Theme Hospital data files /*! @@ -142,14 +142,14 @@ \param iDirEntsSize The number of bytes in the directory entry array. \param sPrefix The path name to prepend to filenames in the directory. */ - void _buildFileLookupTable(uint32_t iSector, int iDirEntsSize, const char* sPrefix); + void build_file_lookup_table(uint32_t iSector, int iDirEntsSize, const char* sPrefix); - //! Return the next free entry in m_pFiles - _file_t* _allocFileRecord(); + //! Return the next free entry in files + file_metadata* allocate_file_record(); - static char _normalise(char c); - static int _fileNameComp(const void* lhs, const void* rhs); - static void _trimIdentifierVersion(const unsigned char* sIdent, uint8_t& iLength); + static char normalise(char c); + static int filename_compare(const void* lhs, const void* rhs); + static void trim_identifier_version(const uint8_t* sIdent, uint8_t& iLength); }; int luaopen_iso_fs(lua_State *L); diff -Nru corsix-th-0.30/CorsixTH/Src/jit_opt.h corsix-th-0.62/CorsixTH/Src/jit_opt.h --- corsix-th-0.30/CorsixTH/Src/jit_opt.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/jit_opt.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1242 +0,0 @@ -/* -** Copyright (C) 2005-2008 Mike Pall. All rights reserved. -** -** Permission is hereby granted, free of charge, to any person obtaining -** a copy of this software and associated documentation files (the -** "Software"), to deal in the Software without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Software, and to -** permit persons to whom the Software is furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -** -*/ - -/* -** LuaJIT's opt.lua compiled to Lua bytecode -*/ -static const unsigned char jit_opt_lua[] = { - 0x1B, 'L' , 'u' , 'a' , 0x51, 0x00, 0x01, 0x04, 0x04, 0x04, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x21, 0xC3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x41, 0x40, 0x00, - 0x00, 0x8A, 0x40, 0x01, 0x00, 0x89, 0xC0, 0x40, 0x81, 0x89, 0x40, 0x41, 0x82, - 0x89, 0xC0, 0x41, 0x83, 0x89, 0x40, 0x42, 0x84, 0x89, 0xC0, 0x42, 0x85, 0xC5, - 0x00, 0x03, 0x00, 0x01, 0x41, 0x03, 0x00, 0xDC, 0x80, 0x00, 0x01, 0x05, 0x81, - 0x03, 0x00, 0x46, 0xC1, 0xC3, 0x01, 0x57, 0x00, 0xC4, 0x02, 0x16, 0x00, 0x00, - 0x80, 0x42, 0x41, 0x00, 0x00, 0x42, 0x01, 0x80, 0x00, 0x81, 0x41, 0x04, 0x00, - 0x1C, 0x41, 0x80, 0x01, 0x05, 0x01, 0x03, 0x00, 0x41, 0x81, 0x04, 0x00, 0x1C, - 0x81, 0x00, 0x01, 0x45, 0xC1, 0x04, 0x00, 0x85, 0x01, 0x05, 0x00, 0xC5, 0x41, - 0x05, 0x00, 0x05, 0x82, 0x05, 0x00, 0x46, 0xC2, 0x45, 0x02, 0x86, 0x02, 0x46, - 0x02, 0xC6, 0x42, 0x46, 0x02, 0x06, 0x83, 0x46, 0x02, 0x45, 0xC3, 0x06, 0x00, - 0x86, 0x03, 0xC7, 0x01, 0xC2, 0x03, 0x80, 0x00, 0x02, 0x04, 0x80, 0x00, 0x9C, - 0x43, 0x80, 0x01, 0x81, 0x43, 0x07, 0x00, 0xE4, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x04, 0x00, 0x00, 0x00, 0x02, 0x24, 0x44, 0x00, 0x00, 0x64, 0x84, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x05, 0xA4, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, - 0x00, 0x00, 0x80, 0x05, 0xE4, 0x04, 0x01, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, - 0x00, 0x80, 0x05, 0x24, 0x45, 0x01, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x80, 0x06, 0x00, 0x00, 0x80, 0x03, 0x64, 0x85, 0x01, - 0x00, 0x00, 0x00, 0x80, 0x04, 0xA4, 0xC5, 0x01, 0x00, 0x00, 0x00, 0x80, 0x02, - 0x00, 0x00, 0x80, 0x05, 0xE4, 0x05, 0x02, 0x00, 0x00, 0x00, 0x80, 0x0A, 0x00, - 0x00, 0x80, 0x05, 0x0A, 0x86, 0x06, 0x00, 0x64, 0x46, 0x02, 0x00, 0x09, 0x46, - 0x06, 0x8F, 0x64, 0x86, 0x02, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x46, 0x86, - 0x8F, 0x64, 0xC6, 0x02, 0x00, 0x09, 0x46, 0x06, 0x90, 0x64, 0x06, 0x03, 0x00, - 0x09, 0x46, 0x86, 0x90, 0x64, 0x46, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x09, - 0x46, 0x06, 0x91, 0x64, 0x86, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, - 0x00, 0x05, 0x09, 0x46, 0x86, 0x91, 0x64, 0xC6, 0x03, 0x00, 0x00, 0x00, 0x80, - 0x09, 0x00, 0x00, 0x00, 0x0A, 0x09, 0x46, 0x06, 0x92, 0x09, 0x06, 0x84, 0x92, - 0x09, 0x06, 0x04, 0x93, 0x64, 0x06, 0x04, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, - 0x00, 0x80, 0x02, 0x09, 0x46, 0x86, 0x93, 0x64, 0x46, 0x04, 0x00, 0x09, 0x46, - 0x06, 0x94, 0x64, 0x86, 0x04, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, - 0x0A, 0x09, 0x46, 0x86, 0x94, 0x09, 0x86, 0x05, 0x95, 0x09, 0x86, 0x85, 0x95, - 0x09, 0x86, 0x05, 0x96, 0x09, 0x86, 0x85, 0x96, 0x09, 0x86, 0x05, 0x97, 0x09, - 0x86, 0x85, 0x97, 0x09, 0x86, 0x05, 0x98, 0x09, 0x86, 0x85, 0x98, 0x64, 0xC6, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x09, 0x46, 0x06, 0x99, 0x64, 0x06, 0x05, - 0x00, 0x09, 0x46, 0x86, 0x99, 0x64, 0x46, 0x05, 0x00, 0x00, 0x00, 0x00, 0x09, - 0x09, 0x46, 0x06, 0x9A, 0x64, 0x86, 0x05, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, - 0x00, 0x80, 0x05, 0x09, 0x46, 0x86, 0x9A, 0x64, 0xC6, 0x05, 0x00, 0x00, 0x00, - 0x80, 0x05, 0x09, 0x46, 0x06, 0x9B, 0x64, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x09, 0x46, 0x86, 0x9B, 0x64, 0x46, 0x06, 0x00, 0x00, 0x00, 0x80, 0x0B, - 0x09, 0x46, 0x06, 0x9C, 0x09, 0xC6, 0x85, 0x9C, 0x64, 0x86, 0x06, 0x00, 0x00, - 0x00, 0x80, 0x08, 0x09, 0x46, 0x06, 0x9D, 0x64, 0xC6, 0x06, 0x00, 0x00, 0x00, - 0x80, 0x08, 0x09, 0x46, 0x86, 0x9D, 0x64, 0x06, 0x07, 0x00, 0x00, 0x00, 0x80, - 0x0A, 0x00, 0x00, 0x80, 0x05, 0x09, 0x46, 0x06, 0x9E, 0x09, 0x06, 0x84, 0x9E, - 0x64, 0x46, 0x07, 0x00, 0x00, 0x00, 0x80, 0x0A, 0x00, 0x00, 0x80, 0x02, 0x00, - 0x00, 0x80, 0x05, 0x09, 0x46, 0x06, 0x9F, 0x64, 0x86, 0x07, 0x00, 0x00, 0x00, - 0x80, 0x05, 0x09, 0x46, 0x86, 0x9F, 0x64, 0xC6, 0x07, 0x00, 0x00, 0x00, 0x80, - 0x02, 0x09, 0x46, 0x06, 0xA0, 0x09, 0x06, 0x84, 0xA0, 0x64, 0x06, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x04, 0x09, - 0x46, 0x06, 0xA1, 0x64, 0x46, 0x08, 0x00, 0x09, 0x46, 0x86, 0xA1, 0x64, 0x86, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, - 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x04, - 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00, 0x00, 0x06, 0x83, - 0x06, 0x80, 0x0D, 0x24, 0xC7, 0x08, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, - 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x64, 0x07, 0x09, 0x00, 0x00, 0x00, 0x00, 0x04, - 0xA4, 0x47, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x80, 0x0E, 0x00, 0x00, 0x80, 0x0D, 0xC5, 0x07, 0x11, - 0x00, 0x25, 0x08, 0x00, 0x00, 0xDC, 0x47, 0x00, 0x00, 0xE4, 0x87, 0x09, 0x00, - 0x00, 0x00, 0x80, 0x08, 0xC7, 0x47, 0x11, 0x00, 0xE4, 0xC7, 0x09, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xC7, 0x87, 0x11, 0x00, 0x87, 0xC7, 0x11, 0x00, 0x87, 0x07, - 0x12, 0x00, 0x1E, 0x00, 0x80, 0x00, 0x49, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, 0x63, 0x6F, - 0x64, 0x65, 0x73, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xAF, 0x40, - 0x04, 0x0B, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x63, 0x6B, 0x73, 0x6C, 0x6F, - 0x74, 0x73, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x62, 0x40, 0x04, - 0x07, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x04, 0x07, 0x00, 0x00, 0x00, 0x63, - 0x6F, 0x6E, 0x73, 0x74, 0x73, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x69, 0x40, 0x04, 0x05, 0x00, 0x00, 0x00, 0x73, 0x75, 0x62, 0x73, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x40, 0x04, 0x08, 0x00, 0x00, 0x00, - 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, - 0x6A, 0x69, 0x74, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x61, 0x73, 0x73, 0x65, - 0x72, 0x74, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x00, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6F, 0x6E, 0x5F, 0x6E, 0x75, 0x6D, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xBC, 0xC3, 0x40, 0x04, 0x25, 0x00, 0x00, 0x00, 0x4C, 0x75, 0x61, 0x4A, 0x49, - 0x54, 0x20, 0x63, 0x6F, 0x72, 0x65, 0x2F, 0x6C, 0x69, 0x62, 0x72, 0x61, 0x72, - 0x79, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6D, 0x69, 0x73, - 0x6D, 0x61, 0x74, 0x63, 0x68, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x6A, 0x69, - 0x74, 0x2E, 0x75, 0x74, 0x69, 0x6C, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x74, - 0x79, 0x70, 0x65, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x72, 0x61, 0x77, 0x67, - 0x65, 0x74, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x6E, 0x65, 0x78, 0x74, 0x00, - 0x04, 0x06, 0x00, 0x00, 0x00, 0x70, 0x63, 0x61, 0x6C, 0x6C, 0x00, 0x04, 0x09, - 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x04, - 0x06, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x00, 0x04, 0x06, 0x00, - 0x00, 0x00, 0x68, 0x69, 0x6E, 0x74, 0x73, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, - 0x66, 0x68, 0x69, 0x6E, 0x74, 0x73, 0x00, 0x04, 0x0D, 0x00, 0x00, 0x00, 0x67, - 0x65, 0x74, 0x6D, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x04, - 0x04, 0x00, 0x00, 0x00, 0x6F, 0x66, 0x66, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0xBF, 0x04, 0x05, 0x00, 0x00, 0x00, 0x4D, 0x4F, 0x56, 0x45, - 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x4C, 0x4F, 0x41, 0x44, 0x4B, 0x00, 0x04, - 0x09, 0x00, 0x00, 0x00, 0x4C, 0x4F, 0x41, 0x44, 0x42, 0x4F, 0x4F, 0x4C, 0x00, - 0x04, 0x08, 0x00, 0x00, 0x00, 0x4C, 0x4F, 0x41, 0x44, 0x4E, 0x49, 0x4C, 0x00, - 0x04, 0x09, 0x00, 0x00, 0x00, 0x47, 0x45, 0x54, 0x55, 0x50, 0x56, 0x41, 0x4C, - 0x00, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x47, 0x45, 0x54, 0x47, 0x4C, 0x4F, 0x42, - 0x41, 0x4C, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x47, 0x45, 0x54, 0x54, 0x41, - 0x42, 0x4C, 0x45, 0x00, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x53, 0x45, 0x54, 0x47, - 0x4C, 0x4F, 0x42, 0x41, 0x4C, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x53, 0x45, - 0x54, 0x55, 0x50, 0x56, 0x41, 0x4C, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x53, - 0x45, 0x54, 0x54, 0x41, 0x42, 0x4C, 0x45, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, - 0x4E, 0x45, 0x57, 0x54, 0x41, 0x42, 0x4C, 0x45, 0x00, 0x04, 0x05, 0x00, 0x00, - 0x00, 0x53, 0x45, 0x4C, 0x46, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x41, 0x44, - 0x44, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x53, 0x55, 0x42, 0x00, 0x04, 0x04, - 0x00, 0x00, 0x00, 0x4D, 0x55, 0x4C, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x44, - 0x49, 0x56, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x4D, 0x4F, 0x44, 0x00, 0x04, - 0x04, 0x00, 0x00, 0x00, 0x50, 0x4F, 0x57, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, - 0x4C, 0x54, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x4C, 0x45, 0x00, 0x04, 0x04, - 0x00, 0x00, 0x00, 0x55, 0x4E, 0x4D, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x4E, - 0x4F, 0x54, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x4C, 0x45, 0x4E, 0x00, 0x04, - 0x07, 0x00, 0x00, 0x00, 0x43, 0x4F, 0x4E, 0x43, 0x41, 0x54, 0x00, 0x04, 0x04, - 0x00, 0x00, 0x00, 0x4A, 0x4D, 0x50, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x45, - 0x51, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x54, 0x45, 0x53, 0x54, 0x00, 0x04, - 0x08, 0x00, 0x00, 0x00, 0x54, 0x45, 0x53, 0x54, 0x53, 0x45, 0x54, 0x00, 0x04, - 0x05, 0x00, 0x00, 0x00, 0x43, 0x41, 0x4C, 0x4C, 0x00, 0x04, 0x09, 0x00, 0x00, - 0x00, 0x54, 0x41, 0x49, 0x4C, 0x43, 0x41, 0x4C, 0x4C, 0x00, 0x04, 0x07, 0x00, - 0x00, 0x00, 0x52, 0x45, 0x54, 0x55, 0x52, 0x4E, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x00, 0x46, 0x4F, 0x52, 0x4C, 0x4F, 0x4F, 0x50, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x00, 0x46, 0x4F, 0x52, 0x50, 0x52, 0x45, 0x50, 0x00, 0x04, 0x09, 0x00, 0x00, - 0x00, 0x54, 0x46, 0x4F, 0x52, 0x4C, 0x4F, 0x4F, 0x50, 0x00, 0x04, 0x08, 0x00, - 0x00, 0x00, 0x53, 0x45, 0x54, 0x4C, 0x49, 0x53, 0x54, 0x00, 0x04, 0x06, 0x00, - 0x00, 0x00, 0x43, 0x4C, 0x4F, 0x53, 0x45, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, - 0x43, 0x4C, 0x4F, 0x53, 0x55, 0x52, 0x45, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, - 0x56, 0x41, 0x52, 0x41, 0x52, 0x47, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x6D, - 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x61, 0x74, - 0x74, 0x61, 0x63, 0x68, 0x5F, 0x63, 0x61, 0x6C, 0x6C, 0x68, 0x69, 0x6E, 0x74, - 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x67, 0x65, 0x74, 0x6C, 0x65, 0x76, 0x65, - 0x6C, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x73, 0x65, 0x74, 0x6C, 0x65, 0x76, - 0x65, 0x6C, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x0D, 0x44, 0x00, 0x00, 0x00, 0x4A, - 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x01, 0x41, - 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, - 0x02, 0x5C, 0x81, 0x81, 0x01, 0x49, 0x80, 0x40, 0x02, 0x0C, 0x41, 0x40, 0x02, - 0x17, 0xC0, 0xC0, 0x02, 0x16, 0xC0, 0x00, 0x80, 0x0C, 0xC1, 0x01, 0x02, 0x92, - 0x02, 0x00, 0x02, 0x49, 0x80, 0x40, 0x05, 0x16, 0x40, 0x0A, 0x80, 0x17, 0x00, - 0xC1, 0x02, 0x16, 0x00, 0x01, 0x80, 0x92, 0x02, 0x00, 0x02, 0xCD, 0xC2, 0x01, - 0x05, 0x49, 0x80, 0xC0, 0x05, 0x49, 0x80, 0x40, 0x05, 0x16, 0x80, 0x08, 0x80, - 0x17, 0x40, 0xC1, 0x02, 0x16, 0x40, 0x00, 0x80, 0x16, 0x80, 0x08, 0x80, 0x16, - 0x80, 0x07, 0x80, 0x5A, 0x02, 0x00, 0x00, 0x16, 0x80, 0x01, 0x80, 0x8C, 0x42, - 0x40, 0x02, 0xC6, 0x82, 0x82, 0x00, 0xDA, 0x42, 0x00, 0x00, 0x16, 0x00, 0x06, - 0x80, 0xCC, 0x40, 0xC0, 0x01, 0x89, 0x80, 0x82, 0x01, 0x16, 0x40, 0x05, 0x80, - 0x17, 0x80, 0xC1, 0x02, 0x16, 0x80, 0x01, 0x80, 0x84, 0x02, 0x80, 0x00, 0x86, - 0xC2, 0x41, 0x05, 0xC0, 0x02, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x9C, 0x82, - 0x80, 0x01, 0x0C, 0x81, 0x02, 0x02, 0x16, 0x00, 0x03, 0x80, 0x17, 0x00, 0xC2, - 0x02, 0x16, 0x40, 0x01, 0x80, 0x57, 0x00, 0x40, 0x04, 0x16, 0xC0, 0x00, 0x80, - 0x0C, 0x41, 0x40, 0x02, 0x92, 0x02, 0x00, 0x02, 0x49, 0x80, 0x40, 0x05, 0x16, - 0x00, 0x01, 0x80, 0x17, 0x40, 0xC2, 0x02, 0x16, 0x80, 0x00, 0x80, 0x17, 0x00, - 0x40, 0x04, 0x16, 0x00, 0x00, 0x80, 0x0C, 0x41, 0x40, 0x02, 0x86, 0x02, 0x81, - 0x00, 0x9A, 0x02, 0x00, 0x00, 0x16, 0x80, 0xF1, 0x7F, 0x17, 0x00, 0xC0, 0x01, - 0x16, 0x00, 0x00, 0x80, 0x5E, 0x00, 0x00, 0x01, 0x06, 0xC1, 0x00, 0x01, 0xCD, - 0x40, 0xC0, 0x01, 0x16, 0x00, 0xF0, 0x7F, 0x1E, 0x00, 0x80, 0x00, 0x0A, 0x00, - 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x01, 0x01, 0x04, 0x04, 0x00, 0x00, - 0x00, 0x4A, 0x4D, 0x50, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x46, 0x4F, 0x52, - 0x4C, 0x4F, 0x4F, 0x50, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x52, 0x45, 0x54, - 0x55, 0x52, 0x4E, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x43, 0x4C, 0x4F, 0x53, - 0x55, 0x52, 0x45, 0x00, 0x04, 0x0B, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x6F, 0x73, - 0x75, 0x72, 0x65, 0x6E, 0x75, 0x70, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x4C, - 0x4F, 0x41, 0x44, 0x42, 0x4F, 0x4F, 0x4C, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, - 0x53, 0x45, 0x54, 0x4C, 0x49, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x6E, 0x00, - 0x00, 0x00, 0x01, 0x06, 0x00, 0x0A, 0x0D, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, - 0x00, 0x86, 0x01, 0x40, 0x03, 0x8C, 0x81, 0x01, 0x01, 0xC6, 0xC1, 0x80, 0x00, - 0x09, 0xC0, 0x01, 0x03, 0x80, 0x01, 0x80, 0x01, 0xCC, 0x41, 0x81, 0x01, 0xCD, - 0x41, 0xC0, 0x03, 0x01, 0x42, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x80, 0x49, 0x80, - 0xC0, 0x04, 0x9F, 0x41, 0xFF, 0x7F, 0x1E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x54, 0x59, 0x50, 0x45, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, - 0x05, 0x0E, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, - 0xDC, 0x80, 0x00, 0x01, 0x57, 0x00, 0xC0, 0x01, 0x16, 0xC0, 0x00, 0x80, 0x57, - 0x40, 0xC0, 0x01, 0x16, 0x40, 0x00, 0x80, 0x17, 0x80, 0xC0, 0x01, 0x16, 0xC0, - 0x00, 0x80, 0x04, 0x01, 0x80, 0x00, 0x06, 0xC1, 0x40, 0x02, 0x0C, 0x01, 0x81, - 0x00, 0x09, 0x80, 0x00, 0x02, 0x1E, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x07, 0x00, 0x00, 0x00, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x00, 0x04, - 0x07, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00, 0x04, 0x06, - 0x00, 0x00, 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x04, 0x05, 0x00, 0x00, - 0x00, 0x54, 0x59, 0x50, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x09, 0x1A, - 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x5C, 0x81, - 0x00, 0x01, 0x57, 0x00, 0xC0, 0x02, 0x16, 0x40, 0x00, 0x80, 0x17, 0x40, 0xC0, - 0x02, 0x16, 0xC0, 0x00, 0x80, 0x84, 0x01, 0x80, 0x00, 0x86, 0x81, 0x40, 0x03, - 0x8C, 0x81, 0x01, 0x01, 0x09, 0xC0, 0x00, 0x03, 0x19, 0x00, 0x81, 0x81, 0x16, - 0xC0, 0x02, 0x80, 0x86, 0x01, 0x81, 0x00, 0xC4, 0x01, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x03, 0xDC, 0x81, 0x00, 0x01, 0x57, 0x00, 0xC1, 0x03, 0x16, 0x40, 0x00, - 0x80, 0x17, 0x40, 0xC1, 0x03, 0x16, 0xC0, 0x00, 0x80, 0x04, 0x02, 0x80, 0x00, - 0x06, 0x82, 0x41, 0x04, 0x0C, 0x02, 0x02, 0x01, 0x09, 0x80, 0x01, 0x04, 0x1E, - 0x00, 0x80, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x74, - 0x61, 0x62, 0x6C, 0x65, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x75, 0x73, 0x65, - 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x54, 0x59, - 0x50, 0x45, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x07, 0x00, 0x00, 0x00, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x00, 0x04, 0x07, - 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00, 0x04, 0x08, 0x00, - 0x00, 0x00, 0x54, 0x59, 0x50, 0x45, 0x4B, 0x45, 0x59, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x08, 0x37, 0x00, 0x00, 0x00, 0x17, 0x00, 0x40, 0x01, 0x16, 0x40, - 0x00, 0x80, 0xC3, 0x00, 0x80, 0x01, 0xDE, 0x00, 0x00, 0x01, 0xC4, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x80, 0x00, 0xDC, 0x80, 0x00, 0x01, 0x17, 0x40, 0xC0, 0x01, - 0x16, 0x80, 0x01, 0x80, 0xC4, 0x00, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x40, - 0x01, 0x00, 0x01, 0xDC, 0x80, 0x80, 0x01, 0x57, 0x00, 0xC0, 0x01, 0x16, 0x00, - 0x00, 0x80, 0xDE, 0x00, 0x00, 0x01, 0xC4, 0x00, 0x00, 0x01, 0x00, 0x01, 0x80, - 0x00, 0xDC, 0x80, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x40, 0x01, 0x80, 0x01, - 0x1C, 0x81, 0x00, 0x01, 0x17, 0x40, 0x40, 0x02, 0x16, 0xC0, 0x03, 0x80, 0x04, - 0x01, 0x80, 0x00, 0x40, 0x01, 0x80, 0x01, 0x81, 0x81, 0x00, 0x00, 0x1C, 0x81, - 0x80, 0x01, 0x44, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x02, 0x5C, 0x81, 0x00, - 0x01, 0x17, 0x40, 0xC0, 0x02, 0x16, 0x80, 0x01, 0x80, 0x44, 0x01, 0x80, 0x00, - 0x80, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x00, 0x01, 0x5C, 0x81, 0x80, 0x01, 0x57, - 0x00, 0xC0, 0x02, 0x16, 0x00, 0x00, 0x80, 0x5E, 0x01, 0x00, 0x01, 0x06, 0xC1, - 0x40, 0x00, 0x06, 0x41, 0x00, 0x02, 0x17, 0x00, 0x40, 0x02, 0x16, 0x00, 0x02, - 0x80, 0x44, 0x01, 0x00, 0x00, 0x80, 0x01, 0x80, 0x00, 0x5C, 0x81, 0x00, 0x01, - 0x17, 0x40, 0xC0, 0x02, 0x16, 0xC0, 0x00, 0x80, 0x44, 0x01, 0x80, 0x01, 0x80, - 0x01, 0x80, 0x00, 0x5C, 0x81, 0x00, 0x01, 0x00, 0x01, 0x80, 0x02, 0x1E, 0x01, - 0x00, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06, - 0x00, 0x00, 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x00, 0x5F, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x04, 0x09, 0x00, 0x00, - 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x76, 0x61, 0x6C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x01, - 0x04, 0x00, 0x09, 0x17, 0x00, 0x00, 0x00, 0x06, 0x01, 0x40, 0x00, 0x52, 0x01, - 0x00, 0x01, 0x06, 0x41, 0x01, 0x02, 0x17, 0x40, 0x40, 0x02, 0x16, 0x00, 0x04, - 0x80, 0x04, 0x01, 0x00, 0x00, 0x46, 0x81, 0x40, 0x00, 0x8D, 0xC1, 0x40, 0x01, - 0x1C, 0x01, 0x81, 0x01, 0x17, 0xC0, 0x80, 0x02, 0x16, 0x80, 0x02, 0x80, 0x57, - 0x00, 0x41, 0x02, 0x16, 0x40, 0x01, 0x80, 0x57, 0x40, 0x41, 0x02, 0x16, 0xC0, - 0x00, 0x80, 0x17, 0x80, 0x41, 0x02, 0x16, 0x00, 0x01, 0x80, 0x17, 0xC0, 0x00, - 0x03, 0x16, 0x80, 0x00, 0x80, 0xC2, 0x01, 0x80, 0x00, 0x06, 0xC2, 0x80, 0x00, - 0xDE, 0x01, 0x80, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, - 0x05, 0x00, 0x00, 0x00, 0x6C, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x05, 0x00, - 0x00, 0x00, 0x66, 0x75, 0x6E, 0x63, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xF0, 0x3F, 0x04, 0x06, 0x00, 0x00, 0x00, 0x4C, 0x4F, 0x41, 0x44, 0x4B, - 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x4C, 0x4F, 0x41, 0x44, 0x42, 0x4F, 0x4F, - 0x4C, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x4C, 0x4F, 0x41, 0x44, 0x4E, 0x49, - 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, - 0xB7, 0x00, 0x00, 0x00, 0x02, 0x07, 0x00, 0x0C, 0x2F, 0x00, 0x00, 0x00, 0xC6, - 0x01, 0x81, 0x00, 0x06, 0x42, 0x81, 0x00, 0x17, 0x00, 0xC0, 0x03, 0x16, 0x40, - 0x00, 0x80, 0xC0, 0x01, 0x00, 0x04, 0x16, 0x80, 0x00, 0x80, 0x17, 0x00, 0x40, - 0x04, 0x16, 0x00, 0x00, 0x80, 0x00, 0x02, 0x80, 0x03, 0x44, 0x02, 0x00, 0x00, - 0x80, 0x02, 0x80, 0x03, 0x5C, 0x82, 0x00, 0x01, 0x84, 0x02, 0x00, 0x00, 0xC0, - 0x02, 0x00, 0x04, 0x9C, 0x82, 0x00, 0x01, 0x17, 0x80, 0x82, 0x04, 0x16, 0xC0, - 0x04, 0x80, 0x17, 0x40, 0xC0, 0x04, 0x16, 0x80, 0x02, 0x80, 0x57, 0x80, 0x40, - 0x03, 0x16, 0x40, 0x01, 0x80, 0xD0, 0xC2, 0xC0, 0x03, 0x17, 0x00, 0xC1, 0x05, - 0x16, 0x80, 0x00, 0x80, 0xD0, 0xC2, 0x40, 0x04, 0x57, 0x00, 0xC1, 0x05, 0x16, - 0x40, 0x00, 0x80, 0xC1, 0x41, 0x01, 0x00, 0x16, 0x00, 0x00, 0x80, 0xC1, 0xC1, - 0x00, 0x00, 0x57, 0x00, 0xC0, 0x03, 0x16, 0x00, 0x02, 0x80, 0xC4, 0x02, 0x80, - 0x00, 0xC6, 0x82, 0xC1, 0x05, 0xCC, 0xC2, 0x02, 0x01, 0x09, 0xC0, 0x81, 0x05, - 0x16, 0xC0, 0x00, 0x80, 0xC4, 0x02, 0x80, 0x00, 0xC6, 0x82, 0xC1, 0x05, 0xCC, - 0xC2, 0x02, 0x01, 0x09, 0xC0, 0xC1, 0x05, 0x57, 0x00, 0x42, 0x03, 0x16, 0x80, - 0x00, 0x80, 0x57, 0x40, 0x42, 0x03, 0x16, 0x00, 0x00, 0x80, 0x49, 0xC0, 0x81, - 0x01, 0x1E, 0x00, 0x80, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, - 0x00, 0x00, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x00, 0x04, 0x04, 0x00, 0x00, - 0x00, 0x44, 0x49, 0x56, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, - 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x3F, 0x04, 0x05, 0x00, 0x00, 0x00, 0x54, 0x59, - 0x50, 0x45, 0x00, 0x01, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x4C, 0x54, 0x00, - 0x04, 0x03, 0x00, 0x00, 0x00, 0x4C, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xBA, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, - 0x0B, 0x16, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, - 0x00, 0x02, 0x80, 0x00, 0x40, 0x02, 0x00, 0x01, 0x80, 0x02, 0x00, 0x02, 0x9C, - 0xC1, 0x80, 0x02, 0xDA, 0x01, 0x00, 0x00, 0x16, 0x80, 0x02, 0x80, 0x17, 0x00, - 0x81, 0x01, 0x16, 0x00, 0x02, 0x80, 0x04, 0x02, 0x80, 0x00, 0x06, 0x02, 0x40, - 0x04, 0x0C, 0x02, 0x02, 0x01, 0x09, 0x40, 0x40, 0x04, 0x17, 0x80, 0xC0, 0x02, - 0x16, 0x80, 0x00, 0x80, 0x06, 0xC2, 0x40, 0x00, 0x4C, 0x02, 0x41, 0x01, 0x09, - 0x42, 0xC1, 0x04, 0x06, 0x02, 0x81, 0x00, 0x49, 0x00, 0x82, 0x01, 0x1E, 0x00, - 0x80, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x43, 0x4F, - 0x4D, 0x42, 0x49, 0x4E, 0x45, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x6C, 0x69, 0x76, 0x65, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, - 0x00, 0x06, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x86, 0x01, 0x81, 0x00, 0x49, - 0x80, 0x81, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, - 0x01, 0x06, 0x00, 0x09, 0x06, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0xC6, - 0x01, 0x40, 0x00, 0x00, 0x02, 0x00, 0x02, 0x9C, 0x81, 0x80, 0x01, 0x49, 0x80, - 0x81, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, - 0x00, 0x00, 0x66, 0x75, 0x6E, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xCE, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, - 0x06, 0x00, 0x00, 0x00, 0x57, 0x00, 0x40, 0x02, 0x16, 0x00, 0x00, 0x80, 0x82, - 0x41, 0x00, 0x00, 0x82, 0x01, 0x80, 0x00, 0x49, 0x80, 0x81, 0x01, 0x1E, 0x00, - 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x00, 0x00, 0x00, - 0xD4, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x07, 0x00, 0x00, 0x00, 0x80, - 0x01, 0x80, 0x01, 0xC0, 0x01, 0x00, 0x02, 0x01, 0x02, 0x00, 0x00, 0xA0, 0x01, - 0x00, 0x80, 0x49, 0x40, 0xC0, 0x04, 0x9F, 0x41, 0xFF, 0x7F, 0x1E, 0x00, 0x80, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, - 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x00, 0x00, 0x00, - 0xD8, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x09, 0x07, 0x00, 0x00, 0x00, 0x84, - 0x01, 0x00, 0x00, 0x86, 0x01, 0x40, 0x03, 0xC6, 0x41, 0x40, 0x00, 0x00, 0x02, - 0x00, 0x02, 0x9C, 0x81, 0x80, 0x01, 0x49, 0x80, 0x81, 0x01, 0x1E, 0x00, 0x80, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x75, 0x70, 0x76, - 0x61, 0x6C, 0x75, 0x65, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x66, 0x75, 0x6E, - 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, - 0xDC, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x0C, 0x0B, 0x00, 0x00, 0x00, 0x84, - 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x06, 0x02, 0x40, 0x00, 0x06, 0x42, - 0x40, 0x04, 0x44, 0x02, 0x80, 0x00, 0x86, 0x82, 0x40, 0x00, 0xC0, 0x02, 0x00, - 0x02, 0x5C, 0x02, 0x80, 0x01, 0x9C, 0x81, 0x00, 0x00, 0x49, 0x80, 0x81, 0x01, - 0x1E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, - 0x73, 0x74, 0x61, 0x74, 0x73, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x65, 0x6E, - 0x76, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x66, 0x75, 0x6E, 0x63, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0x00, 0x00, 0x00, 0xE2, 0x00, 0x00, - 0x00, 0x02, 0x06, 0x00, 0x0D, 0x0F, 0x00, 0x00, 0x00, 0x86, 0x01, 0x81, 0x00, - 0xC4, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, 0x80, 0x00, 0x80, - 0x02, 0x00, 0x01, 0xC0, 0x02, 0x00, 0x03, 0x00, 0x03, 0x80, 0x02, 0xDC, 0x41, - 0x00, 0x03, 0xC4, 0x01, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, - 0x03, 0x86, 0x42, 0x81, 0x00, 0xDC, 0x81, 0x00, 0x02, 0x49, 0xC0, 0x81, 0x01, - 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, - 0x0D, 0x18, 0x00, 0x00, 0x00, 0x86, 0xC1, 0x80, 0x00, 0xC4, 0x01, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, 0x80, 0x00, 0x80, 0x02, 0x00, 0x01, 0xC0, - 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0xDC, 0x41, 0x00, 0x03, 0xC4, 0x01, - 0x80, 0x00, 0x00, 0x02, 0x00, 0x03, 0xDC, 0x81, 0x00, 0x01, 0x57, 0x00, 0xC0, - 0x03, 0x16, 0x00, 0x01, 0x80, 0xC4, 0x01, 0x80, 0x00, 0x00, 0x02, 0x00, 0x03, - 0xDC, 0x81, 0x00, 0x01, 0x17, 0x40, 0xC0, 0x03, 0x16, 0x00, 0x01, 0x80, 0xC6, - 0x41, 0x81, 0x00, 0x57, 0x80, 0xC0, 0x03, 0x16, 0x40, 0x00, 0x80, 0x06, 0xC2, - 0x40, 0x00, 0x09, 0xC2, 0x01, 0x03, 0x1E, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x04, - 0x09, 0x00, 0x00, 0x00, 0x75, 0x73, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, - 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x76, 0x61, - 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, - 0xF3, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x8A, - 0x01, 0x00, 0x00, 0x49, 0x80, 0x81, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x00, 0x00, - 0xFA, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x0D, 0x11, 0x00, 0x00, 0x00, 0x86, - 0x01, 0x81, 0x00, 0xC4, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, - 0x80, 0x00, 0x80, 0x02, 0x00, 0x01, 0xC0, 0x02, 0x00, 0x03, 0x00, 0x03, 0x80, - 0x02, 0xDC, 0x41, 0x00, 0x03, 0xCC, 0x01, 0xC0, 0x01, 0x49, 0x80, 0x81, 0x03, - 0xC4, 0x01, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x03, 0x86, - 0x42, 0x81, 0x00, 0xDC, 0x81, 0x00, 0x02, 0x49, 0xC0, 0x81, 0x01, 0x1E, 0x00, - 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x0E, 0x0B, 0x00, 0x00, 0x00, 0x84, - 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, 0x02, - 0x00, 0x01, 0x80, 0x02, 0x80, 0x01, 0xC0, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, - 0x02, 0x41, 0x03, 0x00, 0x00, 0x9D, 0x01, 0x00, 0x04, 0x9E, 0x01, 0x00, 0x00, - 0x1E, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, - 0x55, 0x4E, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, - 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x02, 0x00, 0x00, - 0x00, 0x49, 0x00, 0xC0, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, - 0x0A, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x0A, 0x07, 0x00, 0x00, 0x00, 0x84, - 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x46, 0x02, - 0x81, 0x00, 0x9C, 0x41, 0x00, 0x02, 0x49, 0x00, 0xC0, 0x01, 0x1E, 0x00, 0x80, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, - 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x1F, - 0x01, 0x00, 0x00, 0x02, 0x06, 0x00, 0x10, 0x2C, 0x00, 0x00, 0x00, 0xC6, 0x01, - 0x81, 0x00, 0x0C, 0x02, 0x40, 0x02, 0x40, 0x02, 0x80, 0x02, 0x81, 0x02, 0x00, - 0x00, 0x20, 0x02, 0x04, 0x80, 0x06, 0xC3, 0x82, 0x00, 0x17, 0x40, 0xC0, 0x03, - 0x16, 0x40, 0x00, 0x80, 0xC0, 0x01, 0x00, 0x06, 0x16, 0xC0, 0x02, 0x80, 0x57, - 0x40, 0x40, 0x06, 0x16, 0x40, 0x02, 0x80, 0x44, 0x03, 0x00, 0x00, 0x80, 0x03, - 0x80, 0x03, 0x5C, 0x83, 0x00, 0x01, 0x84, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, - 0x06, 0x9C, 0x83, 0x00, 0x01, 0x57, 0x80, 0x83, 0x06, 0x16, 0x40, 0x00, 0x80, - 0x82, 0x01, 0x80, 0x00, 0x16, 0x00, 0x00, 0x80, 0x1F, 0x42, 0xFB, 0x7F, 0x17, - 0x40, 0xC0, 0x03, 0x16, 0x40, 0x00, 0x80, 0xC1, 0x81, 0x00, 0x00, 0x16, 0x80, - 0x03, 0x80, 0x04, 0x02, 0x80, 0x00, 0x06, 0xC2, 0x40, 0x04, 0x0C, 0x02, 0x02, - 0x01, 0x9A, 0x41, 0x00, 0x00, 0x16, 0x40, 0x00, 0x80, 0x5B, 0x42, 0x80, 0x03, - 0x16, 0x00, 0x00, 0x80, 0x42, 0x02, 0x00, 0x00, 0x09, 0x40, 0x02, 0x04, 0x04, - 0x02, 0x00, 0x00, 0x40, 0x02, 0x80, 0x03, 0x1C, 0x82, 0x00, 0x01, 0x17, 0x00, - 0x41, 0x04, 0x16, 0x00, 0x00, 0x80, 0xC1, 0x81, 0x00, 0x00, 0x49, 0xC0, 0x81, - 0x01, 0x1E, 0x00, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x05, 0x00, 0x00, 0x00, 0x54, 0x59, 0x50, 0x45, 0x00, 0x04, 0x07, 0x00, 0x00, - 0x00, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, - 0x08, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x01, 0x80, 0x16, 0x00, 0x03, 0x80, - 0x8C, 0x01, 0x01, 0x01, 0xC6, 0x41, 0x40, 0x00, 0xC6, 0x81, 0x81, 0x03, 0xDA, - 0x41, 0x00, 0x00, 0x16, 0x40, 0x00, 0x80, 0x8D, 0x81, 0x40, 0x03, 0x16, 0x40, - 0xFE, 0x7F, 0x17, 0x80, 0x00, 0x03, 0x16, 0xC0, 0x00, 0x80, 0xC4, 0x01, 0x00, - 0x00, 0xC6, 0xC1, 0xC0, 0x03, 0xCC, 0xC1, 0x01, 0x01, 0x09, 0x00, 0xC1, 0x03, - 0x1E, 0x00, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x6C, 0x69, 0x76, 0x65, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x04, 0x08, 0x00, - 0x00, 0x00, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x4E, 0x45, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x2B, 0x01, 0x00, - 0x00, 0x01, 0x06, 0x00, 0x0A, 0x0D, 0x00, 0x00, 0x00, 0x19, 0x00, 0x01, 0x80, - 0x16, 0x40, 0x02, 0x80, 0x19, 0x40, 0x01, 0x80, 0x16, 0xC0, 0x01, 0x80, 0x84, - 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x46, 0x02, - 0x81, 0x00, 0x5A, 0x42, 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0x46, 0x42, 0x81, - 0x00, 0x9C, 0x41, 0x00, 0x02, 0x1E, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x2D, 0x01, 0x00, 0x00, 0x2F, 0x01, 0x00, 0x00, 0x01, 0x06, - 0x00, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, - 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, 0x02, 0x00, 0x01, 0x80, 0x02, 0x80, 0x01, - 0xC0, 0x02, 0x80, 0x01, 0x00, 0x03, 0x80, 0x02, 0x9D, 0x01, 0x80, 0x03, 0x9E, - 0x01, 0x00, 0x00, 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, - 0x01, 0x06, 0x00, 0x0D, 0x09, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0xC0, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, 0x02, 0x00, 0x01, 0x80, 0x02, - 0x80, 0x01, 0xCD, 0x02, 0x40, 0x02, 0x0D, 0x03, 0xC0, 0x02, 0x9C, 0x41, 0x80, - 0x03, 0x1E, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, - 0x01, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x0D, 0x09, 0x00, - 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, - 0x00, 0x40, 0x02, 0x00, 0x01, 0x80, 0x02, 0x80, 0x01, 0xCD, 0x02, 0x40, 0x02, - 0x01, 0x43, 0x00, 0x00, 0x9C, 0x41, 0x80, 0x03, 0x1E, 0x00, 0x80, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3B, 0x01, 0x00, 0x00, 0x3F, 0x01, 0x00, 0x00, 0x02, 0x06, 0x00, - 0x0B, 0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x40, 0x02, 0x16, 0x00, 0x03, 0x80, - 0x84, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, - 0x02, 0x00, 0x01, 0x80, 0x02, 0x80, 0x01, 0x9C, 0x81, 0x80, 0x02, 0x9A, 0x01, - 0x00, 0x00, 0x16, 0x00, 0x01, 0x80, 0x8D, 0x41, 0x40, 0x01, 0xC4, 0x01, 0x80, - 0x00, 0xC6, 0x81, 0xC0, 0x03, 0x8C, 0xC1, 0x01, 0x03, 0x09, 0xC0, 0x40, 0x03, - 0x1E, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, - 0x04, 0x08, 0x00, 0x00, 0x00, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x4E, 0x45, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, - 0x51, 0x01, 0x00, 0x00, 0x03, 0x06, 0x00, 0x0F, 0x37, 0x00, 0x00, 0x00, 0x84, - 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, 0x02, - 0x00, 0x01, 0x8C, 0x02, 0xC0, 0x01, 0x9C, 0xC1, 0x80, 0x02, 0x04, 0x02, 0x80, - 0x00, 0x40, 0x02, 0x80, 0x03, 0x1C, 0x82, 0x00, 0x01, 0x17, 0x40, 0x40, 0x04, - 0x16, 0xC0, 0x00, 0x80, 0x04, 0x02, 0x00, 0x01, 0x06, 0x82, 0x40, 0x04, 0x0C, - 0x02, 0x02, 0x01, 0x09, 0xC0, 0x01, 0x04, 0x06, 0xC2, 0x80, 0x00, 0x4C, 0x02, - 0xC0, 0x01, 0x46, 0x42, 0x82, 0x00, 0x84, 0x02, 0x80, 0x00, 0xC0, 0x02, 0x00, - 0x04, 0x9C, 0x82, 0x00, 0x01, 0xC4, 0x02, 0x80, 0x00, 0x00, 0x03, 0x80, 0x04, - 0xDC, 0x82, 0x00, 0x01, 0x17, 0x40, 0x40, 0x05, 0x16, 0x80, 0x00, 0x80, 0x10, - 0xC3, 0x40, 0x04, 0x17, 0x00, 0x41, 0x06, 0x16, 0x00, 0x01, 0x80, 0x17, 0x40, - 0xC0, 0x05, 0x16, 0x40, 0x01, 0x80, 0x10, 0xC3, 0xC0, 0x04, 0x57, 0x00, 0x41, - 0x06, 0x16, 0x80, 0x00, 0x80, 0x01, 0x43, 0x01, 0x00, 0x1A, 0x43, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x00, 0x4C, 0x83, 0xC1, 0x01, 0x49, - 0x00, 0x83, 0x06, 0x17, 0x40, 0x40, 0x05, 0x16, 0xC0, 0x02, 0x80, 0x17, 0x40, - 0xC0, 0x05, 0x16, 0x40, 0x02, 0x80, 0x44, 0x03, 0x80, 0x00, 0x8C, 0xC3, 0xC0, - 0x01, 0x86, 0x83, 0x83, 0x00, 0x5C, 0x83, 0x00, 0x01, 0x17, 0x40, 0xC0, 0x06, - 0x16, 0xC0, 0x00, 0x80, 0x44, 0x03, 0x00, 0x01, 0x46, 0xC3, 0xC1, 0x06, 0x4C, - 0x43, 0x03, 0x01, 0x09, 0x00, 0x83, 0x06, 0x1E, 0x00, 0x80, 0x00, 0x08, 0x00, - 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x07, - 0x00, 0x00, 0x00, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x00, 0x04, 0x0B, 0x00, - 0x00, 0x00, 0x46, 0x4F, 0x52, 0x5F, 0x53, 0x54, 0x45, 0x50, 0x5F, 0x4B, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, - 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x04, 0x05, 0x00, - 0x00, 0x00, 0x54, 0x59, 0x50, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x55, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x08, - 0x06, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0x86, 0x01, 0x40, 0x03, 0x8C, - 0x81, 0x01, 0x01, 0xC6, 0xC1, 0x80, 0x00, 0x09, 0xC0, 0x01, 0x03, 0x1E, 0x00, - 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x54, 0x59, - 0x50, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x01, 0x00, - 0x00, 0x5E, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x09, 0x0B, 0x00, 0x00, 0x00, - 0x86, 0xC1, 0x80, 0x00, 0xC4, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0xDC, - 0x81, 0x00, 0x01, 0x17, 0x00, 0xC0, 0x03, 0x16, 0xC0, 0x00, 0x80, 0xC6, 0x41, - 0x40, 0x00, 0x0C, 0x82, 0xC0, 0x01, 0x06, 0x02, 0x82, 0x00, 0xC9, 0x01, 0x02, - 0x03, 0x1E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00, - 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x74, - 0x61, 0x62, 0x6C, 0x65, 0x76, 0x61, 0x6C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x01, - 0x00, 0x00, 0x6E, 0x01, 0x00, 0x00, 0x03, 0x06, 0x00, 0x0E, 0x18, 0x00, 0x00, - 0x00, 0x84, 0x01, 0x00, 0x00, 0x49, 0x80, 0x81, 0x01, 0x86, 0x01, 0x40, 0x00, - 0x9A, 0x01, 0x00, 0x00, 0x16, 0x40, 0x04, 0x80, 0x84, 0x01, 0x80, 0x00, 0x86, - 0x41, 0x40, 0x03, 0xC6, 0x81, 0x40, 0x00, 0x00, 0x02, 0x00, 0x02, 0x9C, 0x81, - 0x80, 0x01, 0xCC, 0xC1, 0x40, 0x01, 0x0C, 0x82, 0x01, 0x01, 0x41, 0xC2, 0x00, - 0x00, 0xE0, 0xC1, 0x01, 0x80, 0xC4, 0x02, 0x00, 0x01, 0x06, 0x83, 0x40, 0x00, - 0x40, 0x03, 0x00, 0x05, 0xDC, 0x82, 0x80, 0x01, 0x17, 0x00, 0xC1, 0x05, 0x16, - 0x40, 0x00, 0x80, 0x09, 0x40, 0x41, 0x80, 0x1E, 0x00, 0x80, 0x00, 0xDF, 0x81, - 0xFD, 0x7F, 0x1E, 0x00, 0x80, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, - 0x00, 0x00, 0x6E, 0x6F, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x00, 0x04, 0x0B, 0x00, - 0x00, 0x00, 0x63, 0x6C, 0x6F, 0x73, 0x75, 0x72, 0x65, 0x6E, 0x75, 0x70, 0x00, - 0x04, 0x05, 0x00, 0x00, 0x00, 0x66, 0x75, 0x6E, 0x63, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x04, 0x05, 0x00, 0x00, 0x00, 0x4D, 0x4F, - 0x56, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, - 0x01, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0D, 0x0D, 0x00, - 0x00, 0x00, 0x86, 0x01, 0x40, 0x00, 0x86, 0x41, 0x40, 0x03, 0xC1, 0x81, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x02, 0x41, 0x82, 0x00, 0x00, 0xE0, 0x01, 0x01, 0x80, - 0xCC, 0x82, 0x82, 0x01, 0xCD, 0x82, 0xC0, 0x05, 0x0C, 0x83, 0x02, 0x03, 0x06, - 0x03, 0x03, 0x00, 0x49, 0x00, 0x83, 0x05, 0xDF, 0x41, 0xFE, 0x7F, 0x1E, 0x00, - 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x73, 0x74, - 0x61, 0x74, 0x73, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, - 0x6D, 0x73, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, 0xAC, 0x01, 0x00, - 0x00, 0x09, 0x01, 0x00, 0x16, 0x73, 0x00, 0x00, 0x00, 0x46, 0x00, 0x40, 0x00, - 0x5A, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0x1E, 0x00, 0x80, 0x00, 0x46, - 0x40, 0x40, 0x00, 0x84, 0x00, 0x00, 0x00, 0x86, 0x80, 0x40, 0x01, 0xC0, 0x00, - 0x80, 0x00, 0x9C, 0x80, 0x00, 0x01, 0x9A, 0x40, 0x00, 0x00, 0x16, 0xC0, 0x00, - 0x80, 0xC4, 0x00, 0x00, 0x00, 0xC6, 0xC0, 0xC0, 0x01, 0xC6, 0x00, 0xC1, 0x01, - 0xDE, 0x00, 0x00, 0x01, 0xC6, 0x40, 0x41, 0x01, 0x04, 0x01, 0x80, 0x00, 0x06, - 0x41, 0x41, 0x02, 0x58, 0xC0, 0x00, 0x02, 0x16, 0xC0, 0x04, 0x80, 0xC6, 0x80, - 0x41, 0x01, 0x04, 0x01, 0x80, 0x00, 0x06, 0x81, 0x41, 0x02, 0x58, 0xC0, 0x00, - 0x02, 0x16, 0x80, 0x03, 0x80, 0xC6, 0xC0, 0x41, 0x01, 0x04, 0x01, 0x80, 0x00, - 0x06, 0xC1, 0x41, 0x02, 0x58, 0xC0, 0x00, 0x02, 0x16, 0x40, 0x02, 0x80, 0xC6, - 0x00, 0x42, 0x01, 0x04, 0x01, 0x80, 0x00, 0x06, 0x01, 0x42, 0x02, 0x58, 0xC0, - 0x00, 0x02, 0x16, 0x00, 0x01, 0x80, 0xC6, 0x40, 0x42, 0x01, 0x04, 0x01, 0x80, - 0x00, 0x06, 0x41, 0x42, 0x02, 0x18, 0xC0, 0x00, 0x02, 0x16, 0xC0, 0x00, 0x80, - 0xC4, 0x00, 0x00, 0x00, 0xC6, 0xC0, 0xC0, 0x01, 0xC6, 0x80, 0xC2, 0x01, 0xDE, - 0x00, 0x00, 0x01, 0xC4, 0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x00, 0xDC, 0x80, - 0x00, 0x01, 0x09, 0x00, 0xC3, 0x85, 0x09, 0x80, 0x00, 0x81, 0x09, 0xC0, 0x80, - 0x86, 0x0A, 0x41, 0x00, 0x00, 0x46, 0xC1, 0x43, 0x01, 0x84, 0x01, 0x80, 0x01, - 0x09, 0x81, 0x81, 0x02, 0x09, 0x00, 0x01, 0x87, 0x0A, 0x01, 0x00, 0x00, 0x41, - 0x01, 0x04, 0x00, 0x86, 0xC1, 0x41, 0x01, 0xC1, 0x01, 0x04, 0x00, 0x60, 0x81, - 0x00, 0x80, 0x4D, 0x02, 0x44, 0x04, 0x86, 0x02, 0x02, 0x00, 0x09, 0x81, 0x82, - 0x04, 0x5F, 0xC1, 0xFE, 0x7F, 0x41, 0x41, 0x04, 0x00, 0x81, 0x81, 0x04, 0x00, - 0xC1, 0x41, 0x04, 0x00, 0x60, 0xC1, 0x01, 0x80, 0x44, 0x02, 0x00, 0x02, 0x80, - 0x02, 0x80, 0x00, 0xC0, 0x02, 0x00, 0x04, 0x5C, 0xC2, 0x80, 0x01, 0x9A, 0x42, - 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0x16, 0x40, 0x00, 0x80, 0x09, 0x41, 0x02, - 0x04, 0x5F, 0x81, 0xFD, 0x7F, 0x41, 0x01, 0x04, 0x00, 0x86, 0x41, 0x41, 0x01, - 0xC1, 0x01, 0x04, 0x00, 0x60, 0x41, 0x05, 0x80, 0x46, 0x02, 0x82, 0x01, 0x5A, - 0x02, 0x00, 0x00, 0x16, 0x80, 0x03, 0x80, 0x44, 0x02, 0x80, 0x02, 0x80, 0x02, - 0x80, 0x00, 0xC0, 0x02, 0x00, 0x04, 0x5C, 0x82, 0x81, 0x01, 0x84, 0x03, 0x00, - 0x03, 0x86, 0x43, 0x02, 0x07, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, - 0x40, 0x04, 0x00, 0x04, 0x80, 0x04, 0x00, 0x05, 0xC0, 0x04, 0x80, 0x05, 0x00, - 0x05, 0x00, 0x06, 0x40, 0x05, 0x80, 0x04, 0x9C, 0x43, 0x00, 0x04, 0x16, 0xC0, - 0x00, 0x80, 0x44, 0x02, 0x80, 0x03, 0x46, 0xC2, 0xC4, 0x04, 0x4C, 0x42, 0x02, - 0x04, 0x09, 0x00, 0xC5, 0x04, 0x5F, 0x01, 0xFA, 0x7F, 0x46, 0xC1, 0x42, 0x00, - 0x5A, 0x01, 0x00, 0x00, 0x16, 0x80, 0x00, 0x80, 0x44, 0x01, 0x00, 0x04, 0x46, - 0x41, 0xC5, 0x02, 0x09, 0x00, 0xC3, 0x02, 0x09, 0x80, 0xC5, 0x85, 0x09, 0x80, - 0x45, 0x81, 0x09, 0x80, 0xC5, 0x86, 0x09, 0x80, 0x45, 0x87, 0x1E, 0x00, 0x80, - 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6F, - 0x70, 0x74, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x66, 0x75, 0x6E, 0x63, 0x00, - 0x04, 0x06, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x74, 0x73, 0x00, 0x04, 0x07, - 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x00, 0x04, 0x0F, 0x00, - 0x00, 0x00, 0x43, 0x4F, 0x4D, 0x50, 0x49, 0x4C, 0x45, 0x52, 0x5F, 0x45, 0x52, - 0x52, 0x4F, 0x52, 0x00, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, - 0x63, 0x6F, 0x64, 0x65, 0x73, 0x00, 0x04, 0x0B, 0x00, 0x00, 0x00, 0x73, 0x74, - 0x61, 0x63, 0x6B, 0x73, 0x6C, 0x6F, 0x74, 0x73, 0x00, 0x04, 0x07, 0x00, 0x00, - 0x00, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, - 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x73, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x73, - 0x75, 0x62, 0x73, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x54, 0x4F, 0x4F, 0x4C, - 0x41, 0x52, 0x47, 0x45, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x6E, 0x6F, 0x63, - 0x6C, 0x6F, 0x73, 0x65, 0x00, 0x01, 0x01, 0x04, 0x05, 0x00, 0x00, 0x00, 0x6C, - 0x69, 0x76, 0x65, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x74, 0x61, 0x62, 0x6C, - 0x65, 0x76, 0x61, 0x6C, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x76, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x70, 0xC0, 0x04, 0x08, 0x00, 0x00, 0x00, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x4E, - 0x45, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x4E, 0x4F, 0x43, 0x4C, - 0x4F, 0x53, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, - 0x01, 0x00, 0x00, 0xBD, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x08, 0x1C, 0x00, - 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x19, 0x00, 0xC0, 0x00, 0x16, 0x00, 0x00, - 0x80, 0x1E, 0x00, 0x80, 0x00, 0x44, 0x00, 0x80, 0x00, 0x84, 0x00, 0x00, 0x01, - 0xC0, 0x00, 0x00, 0x00, 0x5C, 0xC0, 0x80, 0x01, 0x5A, 0x40, 0x00, 0x00, 0x16, - 0x40, 0x03, 0x80, 0xC5, 0x40, 0x00, 0x00, 0xC6, 0x80, 0xC0, 0x01, 0xCB, 0xC0, - 0xC0, 0x01, 0x41, 0x01, 0x01, 0x00, 0x80, 0x01, 0x00, 0x01, 0xC1, 0x41, 0x01, - 0x00, 0xDC, 0x40, 0x80, 0x02, 0xC4, 0x00, 0x80, 0x01, 0xC6, 0x80, 0xC1, 0x01, - 0x04, 0x01, 0x00, 0x02, 0xDC, 0x40, 0x00, 0x01, 0xC3, 0x00, 0x80, 0x01, 0xC8, - 0x00, 0x80, 0x02, 0x16, 0x80, 0x00, 0x80, 0x9A, 0x00, 0x00, 0x00, 0x16, 0x00, - 0x00, 0x80, 0x9E, 0x00, 0x00, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x07, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x00, 0x00, 0x69, 0x6F, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x73, 0x74, 0x64, - 0x65, 0x72, 0x72, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x00, 0x04, 0x1B, 0x00, 0x00, 0x00, 0x0A, 0x45, 0x52, 0x52, 0x4F, 0x52, - 0x3A, 0x20, 0x6A, 0x69, 0x74, 0x2E, 0x6F, 0x70, 0x74, 0x20, 0x64, 0x69, 0x73, - 0x61, 0x62, 0x6C, 0x65, 0x64, 0x3A, 0x20, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xCB, - 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x09, 0x26, 0x00, 0x00, 0x00, 0x45, 0x00, - 0x00, 0x00, 0x46, 0x40, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC1, 0x80, 0x00, - 0x00, 0x5C, 0xC0, 0x80, 0x01, 0x5A, 0x40, 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, - 0x40, 0x00, 0x00, 0x00, 0xC1, 0xC0, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x55, - 0x00, 0x81, 0x01, 0xC4, 0x00, 0x00, 0x00, 0x05, 0x01, 0x01, 0x00, 0x40, 0x01, - 0x80, 0x00, 0xDC, 0xC0, 0x80, 0x01, 0xDA, 0x40, 0x00, 0x00, 0x16, 0x00, 0x04, - 0x80, 0x45, 0x01, 0x00, 0x00, 0x46, 0x41, 0xC1, 0x02, 0x80, 0x01, 0x00, 0x02, - 0xC1, 0x81, 0x01, 0x00, 0x01, 0xC2, 0x01, 0x00, 0x5C, 0x81, 0x00, 0x02, 0x57, - 0x00, 0xC2, 0x02, 0x16, 0xC0, 0x00, 0x80, 0x45, 0x41, 0x02, 0x00, 0x80, 0x01, - 0x00, 0x02, 0xC1, 0x81, 0x02, 0x00, 0x5C, 0x41, 0x80, 0x01, 0x41, 0xC1, 0x02, - 0x00, 0x80, 0x01, 0x80, 0x00, 0xC1, 0x01, 0x03, 0x00, 0x55, 0xC1, 0x81, 0x02, - 0x5E, 0x01, 0x00, 0x01, 0x46, 0x41, 0x43, 0x02, 0x80, 0x01, 0x00, 0x01, 0x5C, - 0x41, 0x00, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x04, 0x07, - 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00, 0x04, 0x06, 0x00, - 0x00, 0x00, 0x6D, 0x61, 0x74, 0x63, 0x68, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x00, - 0x5E, 0x28, 0x2E, 0x2D, 0x29, 0x3D, 0x28, 0x2E, 0x2A, 0x29, 0x24, 0x00, 0x04, - 0x09, 0x00, 0x00, 0x00, 0x6A, 0x69, 0x74, 0x2E, 0x6F, 0x70, 0x74, 0x5F, 0x00, - 0x04, 0x08, 0x00, 0x00, 0x00, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x00, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x73, 0x75, 0x62, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, - 0x40, 0x04, 0x08, 0x00, 0x00, 0x00, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x20, - 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x19, 0x00, 0x00, 0x00, - 0x6F, 0x70, 0x74, 0x69, 0x6D, 0x69, 0x7A, 0x65, 0x72, 0x20, 0x61, 0x64, 0x64, - 0x2D, 0x6F, 0x6E, 0x20, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x20, 0x00, 0x04, - 0x0B, 0x00, 0x00, 0x00, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x66, 0x6F, 0x75, 0x6E, - 0x64, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x01, 0x00, 0x00, 0xEB, 0x01, - 0x00, 0x00, 0x08, 0x01, 0x00, 0x06, 0x3B, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, - 0x00, 0x5A, 0x40, 0x00, 0x00, 0x16, 0x80, 0x01, 0x80, 0x44, 0x00, 0x80, 0x00, - 0x46, 0x00, 0xC0, 0x00, 0x84, 0x00, 0x00, 0x01, 0xC4, 0x00, 0x80, 0x01, 0x5C, - 0x40, 0x80, 0x01, 0x42, 0x00, 0x80, 0x00, 0x48, 0x00, 0x00, 0x00, 0x57, 0x40, - 0x40, 0x00, 0x16, 0x40, 0x00, 0x80, 0x17, 0x80, 0x40, 0x00, 0x16, 0x80, 0x00, - 0x80, 0x44, 0x00, 0x80, 0x02, 0x48, 0x00, 0x00, 0x02, 0x16, 0x40, 0x07, 0x80, - 0x45, 0xC0, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x5C, 0x80, 0x00, 0x01, 0x5A, - 0x00, 0x00, 0x00, 0x16, 0x80, 0x02, 0x80, 0x58, 0x00, 0xC1, 0x00, 0x16, 0x80, - 0x00, 0x80, 0x90, 0x40, 0xC1, 0x00, 0x57, 0x00, 0x41, 0x01, 0x16, 0xC0, 0x00, - 0x80, 0x85, 0x80, 0x01, 0x00, 0xC1, 0xC0, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, - 0x9C, 0x40, 0x80, 0x01, 0x48, 0x00, 0x00, 0x02, 0x16, 0x40, 0x03, 0x80, 0x84, - 0x00, 0x00, 0x02, 0x17, 0x00, 0x42, 0x01, 0x16, 0x40, 0x00, 0x80, 0x84, 0x00, - 0x80, 0x02, 0x88, 0x00, 0x00, 0x02, 0x84, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, - 0x00, 0x9C, 0x80, 0x00, 0x01, 0x9A, 0x00, 0x00, 0x00, 0x16, 0xC0, 0x00, 0x80, - 0xC5, 0x80, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x41, 0x01, 0x01, 0x00, 0xDC, - 0x40, 0x80, 0x01, 0x44, 0x00, 0x80, 0x03, 0x5A, 0x40, 0x00, 0x00, 0x16, 0xC0, - 0x01, 0x80, 0x44, 0x00, 0x00, 0x02, 0x19, 0x40, 0x80, 0x84, 0x16, 0x00, 0x01, - 0x80, 0x44, 0x00, 0x00, 0x03, 0x81, 0x80, 0x02, 0x00, 0x5C, 0x40, 0x00, 0x01, - 0x42, 0x00, 0x80, 0x00, 0x48, 0x00, 0x80, 0x03, 0x1E, 0x00, 0x80, 0x00, 0x0B, - 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x61, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0x00, - 0x00, 0x74, 0x6F, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xF0, 0x3F, 0x04, 0x06, 0x00, 0x00, 0x00, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x00, - 0x04, 0x14, 0x00, 0x00, 0x00, 0x62, 0x61, 0x64, 0x20, 0x6F, 0x70, 0x74, 0x69, - 0x6D, 0x69, 0x7A, 0x65, 0x72, 0x20, 0x6C, 0x65, 0x76, 0x65, 0x6C, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBF, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x04, 0x07, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x6C, 0x69, - 0x6E, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0x01, 0x00, - 0x00, 0xF4, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0x01, 0x00, 0x00, 0xF8, 0x01, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00 -}; - -/* -** LuaJIT's opt_inline.lua compiled to Lua bytecode -*/ -static const unsigned char jit_opt_inline_lua[] = { - 0x1B, 'L' , 'u' , 'a' , 0x51, 0x00, 0x01, 0x04, 0x04, 0x04, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x1F, 0xF0, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x40, 0x00, - 0x00, 0x1C, 0x80, 0x00, 0x01, 0x45, 0x80, 0x00, 0x00, 0x86, 0xC0, 0x40, 0x00, - 0x57, 0x00, 0x41, 0x01, 0x16, 0x00, 0x00, 0x80, 0x82, 0x40, 0x00, 0x00, 0x82, - 0x00, 0x80, 0x00, 0xC1, 0x40, 0x01, 0x00, 0x5C, 0x40, 0x80, 0x01, 0x45, 0x00, - 0x00, 0x00, 0x81, 0x80, 0x01, 0x00, 0x5C, 0x80, 0x00, 0x01, 0x85, 0xC0, 0x01, - 0x00, 0xC5, 0x00, 0x02, 0x00, 0x05, 0x41, 0x02, 0x00, 0x46, 0x81, 0xC2, 0x00, - 0x86, 0xC1, 0xC2, 0x00, 0xC5, 0x01, 0x03, 0x00, 0xC6, 0x41, 0xC3, 0x03, 0x05, - 0x02, 0x03, 0x00, 0x06, 0x82, 0x43, 0x04, 0x45, 0x02, 0x03, 0x00, 0x46, 0xC2, - 0xC3, 0x04, 0x86, 0x02, 0x44, 0x00, 0xC2, 0x02, 0x80, 0x00, 0x02, 0x03, 0x80, - 0x00, 0x9C, 0x42, 0x80, 0x01, 0x8A, 0x02, 0x00, 0x00, 0xC5, 0x42, 0x04, 0x00, - 0x0A, 0x03, 0x00, 0x00, 0x64, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x83, - 0x03, 0x00, 0x08, 0x64, 0x44, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0x80, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x08, 0xA4, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, - 0x00, 0x00, 0x00, 0x08, 0xE4, 0xC4, 0x00, 0x00, 0x24, 0x05, 0x01, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x80, 0x05, 0x64, 0x45, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x83, 0x05, 0x00, - 0x0B, 0xC5, 0x85, 0x04, 0x00, 0x01, 0xC4, 0x04, 0x00, 0xC0, 0x03, 0x80, 0x0B, - 0x80, 0x03, 0x00, 0x0B, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x05, 0x05, 0x00, 0x01, - 0x46, 0x05, 0x00, 0x41, 0x86, 0x05, 0x00, 0xA4, 0x86, 0x01, 0x00, 0x00, 0x00, - 0x80, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, - 0x08, 0xC1, 0xC5, 0x05, 0x00, 0x01, 0x06, 0x06, 0x00, 0x41, 0x86, 0x05, 0x00, - 0xA4, 0xC6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x0A, 0x9C, 0x45, 0x80, 0x02, 0x03, 0x04, 0x00, 0x08, 0x80, 0x05, - 0x80, 0x08, 0xC1, 0x45, 0x02, 0x00, 0x01, 0x46, 0x06, 0x00, 0x41, 0x86, 0x06, - 0x00, 0xA4, 0x06, 0x02, 0x00, 0x00, 0x00, 0x80, 0x0A, 0x9C, 0x45, 0x80, 0x02, - 0x80, 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x01, 0x00, 0x01, 0xC6, 0x06, 0x00, 0x41, - 0x06, 0x07, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, - 0x07, 0x00, 0x01, 0x86, 0x05, 0x00, 0x41, 0x06, 0x07, 0x00, 0x9C, 0x45, 0x00, - 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x07, 0x00, 0x01, 0x06, 0x07, 0x00, - 0x41, 0xC6, 0x07, 0x00, 0x80, 0x06, 0x80, 0x09, 0x9C, 0x45, 0x80, 0x02, 0x80, - 0x05, 0x80, 0x08, 0xC1, 0x05, 0x08, 0x00, 0x01, 0x46, 0x08, 0x00, 0x41, 0x46, - 0x06, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x05, 0x02, - 0x00, 0x01, 0x06, 0x07, 0x00, 0x41, 0x86, 0x08, 0x00, 0xA4, 0x46, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x9C, 0x45, 0x80, 0x02, 0x80, - 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x08, 0x00, 0x01, 0x06, 0x07, 0x00, 0x41, 0x06, - 0x09, 0x00, 0x80, 0x06, 0x80, 0x09, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, - 0x08, 0xC1, 0x85, 0x00, 0x00, 0x01, 0x46, 0x09, 0x00, 0x41, 0x86, 0x09, 0x00, - 0xA4, 0x86, 0x02, 0x00, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, - 0xC5, 0x09, 0x00, 0x01, 0x06, 0x0A, 0x00, 0x41, 0x46, 0x0A, 0x00, 0x9C, 0x45, - 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x0A, 0x00, 0x01, 0xC6, 0x06, - 0x00, 0x41, 0x06, 0x07, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, - 0xC1, 0x05, 0x00, 0x00, 0x01, 0x86, 0x05, 0x00, 0x41, 0xC6, 0x06, 0x00, 0x9C, - 0x45, 0x00, 0x02, 0x81, 0xC5, 0x0A, 0x00, 0xC5, 0xC5, 0x0A, 0x00, 0x01, 0x04, - 0x0B, 0x00, 0xC0, 0x03, 0x80, 0x0B, 0x80, 0x03, 0x00, 0x0B, 0xDA, 0x03, 0x00, - 0x00, 0x16, 0x00, 0x04, 0x80, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x0B, 0x00, - 0x01, 0x46, 0x09, 0x00, 0x41, 0x86, 0x0B, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, - 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x0B, 0x00, 0x01, 0x46, 0x09, 0x00, 0x41, 0x06, - 0x0C, 0x00, 0xA4, 0xC6, 0x02, 0x00, 0x9C, 0x45, 0x80, 0x02, 0x03, 0x04, 0x00, - 0x08, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x0C, 0x00, 0x01, 0x86, 0x0C, 0x00, - 0x41, 0xC6, 0x0C, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x81, 0x05, 0x03, 0x00, 0xC5, - 0x05, 0x03, 0x00, 0x01, 0x04, 0x0D, 0x00, 0xC0, 0x03, 0x80, 0x0B, 0x80, 0x03, - 0x00, 0x0B, 0xDA, 0x03, 0x00, 0x00, 0x16, 0x40, 0x11, 0x80, 0x80, 0x05, 0x80, - 0x08, 0xC1, 0x45, 0x0D, 0x00, 0x01, 0x06, 0x0A, 0x00, 0x41, 0xC6, 0x06, 0x00, - 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x03, 0x00, 0x01, - 0xC6, 0x06, 0x00, 0x41, 0x86, 0x0D, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, - 0x80, 0x08, 0xC1, 0xC5, 0x0D, 0x00, 0x01, 0xC6, 0x06, 0x00, 0x41, 0x06, 0x0E, - 0x00, 0x9C, 0x45, 0x00, 0x02, 0x03, 0x04, 0x00, 0x08, 0x80, 0x05, 0x80, 0x08, - 0xC1, 0x45, 0x0E, 0x00, 0x01, 0x06, 0x0A, 0x00, 0x41, 0xC6, 0x06, 0x00, 0xA4, - 0x06, 0x03, 0x00, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, - 0x0E, 0x00, 0x01, 0xC6, 0x06, 0x00, 0x41, 0xC6, 0x0E, 0x00, 0x9C, 0x45, 0x00, - 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x05, 0x0F, 0x00, 0x01, 0xC6, 0x06, 0x00, - 0x41, 0xC6, 0x06, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, - 0x45, 0x0F, 0x00, 0x01, 0xC6, 0x06, 0x00, 0x41, 0xC6, 0x06, 0x00, 0x9C, 0x45, - 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x0F, 0x00, 0x01, 0xC6, 0x06, - 0x00, 0x41, 0xC6, 0x06, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, - 0xC1, 0xC5, 0x0F, 0x00, 0x01, 0xC6, 0x06, 0x00, 0x41, 0x06, 0x10, 0x00, 0x9C, - 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x10, 0x00, 0x01, 0x46, - 0x09, 0x00, 0x41, 0x86, 0x10, 0x00, 0xA4, 0x46, 0x03, 0x00, 0x9C, 0x45, 0x80, - 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x03, 0x00, 0x01, 0x46, 0x09, 0x00, - 0x41, 0xC6, 0x10, 0x00, 0xA4, 0x86, 0x03, 0x00, 0x9C, 0x45, 0x80, 0x02, 0x80, - 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x03, 0x00, 0x01, 0xC6, 0x0E, 0x00, 0x41, 0x06, - 0x11, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x11, - 0x00, 0x01, 0x86, 0x11, 0x00, 0x41, 0xC6, 0x11, 0x00, 0xA4, 0xC6, 0x03, 0x00, - 0x9C, 0x45, 0x80, 0x02, 0x81, 0x05, 0x12, 0x00, 0xC5, 0x05, 0x12, 0x00, 0x01, - 0x44, 0x12, 0x00, 0xC0, 0x03, 0x80, 0x0B, 0x80, 0x03, 0x00, 0x0B, 0xDA, 0x03, - 0x00, 0x00, 0x16, 0xC0, 0x05, 0x80, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x12, - 0x00, 0x01, 0xC6, 0x12, 0x00, 0x41, 0x06, 0x13, 0x00, 0x9C, 0x45, 0x00, 0x02, - 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x13, 0x00, 0x01, 0x06, 0x07, 0x00, 0x41, - 0x86, 0x05, 0x00, 0xA4, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x80, 0x01, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x13, - 0x00, 0x01, 0x06, 0x0A, 0x00, 0x41, 0x86, 0x05, 0x00, 0x9C, 0x45, 0x00, 0x02, - 0x03, 0x04, 0x00, 0x08, 0x80, 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x13, 0x00, 0x01, - 0xC6, 0x06, 0x00, 0x41, 0x06, 0x14, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x81, 0x45, - 0x14, 0x00, 0xC5, 0x45, 0x14, 0x00, 0x01, 0x84, 0x14, 0x00, 0xC0, 0x03, 0x80, - 0x0B, 0x80, 0x03, 0x00, 0x0B, 0xDA, 0x03, 0x00, 0x00, 0x16, 0x80, 0x24, 0x80, - 0x80, 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x14, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, - 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, - 0x15, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, - 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x15, 0x00, 0x01, 0x06, 0x15, 0x00, - 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, - 0xC5, 0x15, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, - 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x05, 0x16, 0x00, 0x01, 0x06, 0x15, - 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, - 0xC1, 0x45, 0x16, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, - 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x16, 0x00, 0x01, 0x06, - 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, - 0x08, 0xC1, 0xC5, 0x16, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, - 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x05, 0x17, 0x00, 0x01, - 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, - 0x80, 0x08, 0xC1, 0x45, 0x17, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, - 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x17, 0x00, - 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, - 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x17, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, - 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x05, 0x18, - 0x00, 0x01, 0x06, 0x0A, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, - 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x18, 0x00, 0x01, 0x06, 0x0A, 0x00, 0x41, - 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, - 0x18, 0x00, 0x01, 0x06, 0x07, 0x00, 0x41, 0x06, 0x15, 0x00, 0x80, 0x06, 0x80, - 0x09, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x18, 0x00, - 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, - 0x05, 0x80, 0x08, 0xC1, 0x05, 0x19, 0x00, 0x01, 0x06, 0x07, 0x00, 0x41, 0x46, - 0x19, 0x00, 0xA4, 0x46, 0x04, 0x00, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, - 0x08, 0xC1, 0x85, 0x19, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x46, 0x19, 0x00, - 0x9C, 0x45, 0x00, 0x02, 0x03, 0x04, 0x00, 0x08, 0x80, 0x05, 0x80, 0x08, 0xC1, - 0xC5, 0x19, 0x00, 0x01, 0x06, 0x07, 0x00, 0x41, 0x06, 0x1A, 0x00, 0x80, 0x06, - 0x80, 0x09, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x1A, - 0x00, 0x01, 0x06, 0x07, 0x00, 0x41, 0x06, 0x1A, 0x00, 0x80, 0x06, 0x80, 0x09, - 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x1A, 0x00, 0x01, - 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, - 0x80, 0x08, 0xC1, 0xC5, 0x1A, 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x15, - 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x05, 0x1B, 0x00, - 0x01, 0x46, 0x1B, 0x00, 0x41, 0x06, 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, - 0x05, 0x80, 0x08, 0xC1, 0x85, 0x1B, 0x00, 0x01, 0xC6, 0x1B, 0x00, 0x41, 0x06, - 0x15, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x05, 0x1C, - 0x00, 0x01, 0x06, 0x15, 0x00, 0x41, 0x46, 0x19, 0x00, 0x9C, 0x45, 0x00, 0x02, - 0x80, 0x05, 0x80, 0x08, 0xC1, 0x45, 0x1C, 0x00, 0x01, 0x06, 0x07, 0x00, 0x41, - 0xC6, 0x1B, 0x00, 0x80, 0x06, 0x80, 0x09, 0x9C, 0x45, 0x80, 0x02, 0x80, 0x05, - 0x80, 0x08, 0xC1, 0x85, 0x1C, 0x00, 0x01, 0xC6, 0x12, 0x00, 0x41, 0x06, 0x0A, - 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, 0x05, 0x80, 0x08, 0xC1, 0xC5, 0x1C, 0x00, - 0x01, 0x06, 0x15, 0x00, 0x41, 0x06, 0x1D, 0x00, 0xA4, 0x86, 0x04, 0x00, 0x9C, - 0x45, 0x80, 0x02, 0x81, 0x45, 0x1D, 0x00, 0xC5, 0x45, 0x1D, 0x00, 0x03, 0x04, - 0x00, 0x08, 0xC0, 0x03, 0x80, 0x0B, 0x80, 0x03, 0x00, 0x0B, 0xDA, 0x03, 0x00, - 0x00, 0x16, 0x40, 0x02, 0x80, 0x80, 0x05, 0x80, 0x08, 0xC1, 0x85, 0x1D, 0x00, - 0x01, 0xC6, 0x1D, 0x00, 0x41, 0x06, 0x1E, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x80, - 0x05, 0x80, 0x08, 0xC1, 0x45, 0x1E, 0x00, 0x01, 0xC6, 0x06, 0x00, 0x41, 0xC6, - 0x12, 0x00, 0x9C, 0x45, 0x00, 0x02, 0x8A, 0x05, 0x02, 0x00, 0x89, 0xC5, 0x5E, - 0xBD, 0x89, 0x45, 0x5F, 0xBE, 0x89, 0xC5, 0x5F, 0xBF, 0x89, 0x05, 0x60, 0x86, - 0x89, 0x45, 0x60, 0xA4, 0x89, 0xC5, 0x60, 0xC1, 0x89, 0x45, 0x61, 0xC2, 0x89, - 0xC5, 0x61, 0xC3, 0xCA, 0x45, 0x02, 0x00, 0xC9, 0x05, 0xE2, 0x90, 0xC9, 0x45, - 0xE2, 0x8D, 0xC9, 0x85, 0x62, 0x8B, 0xC9, 0xC5, 0xE2, 0x99, 0xC9, 0x45, 0x63, - 0xC6, 0xC9, 0xC5, 0x63, 0xC7, 0xC9, 0x05, 0x64, 0xAA, 0xC9, 0x05, 0x64, 0x94, - 0xC9, 0x85, 0xE4, 0xC8, 0x0A, 0xC6, 0x01, 0x00, 0x09, 0xC6, 0xE4, 0x90, 0x09, - 0xC6, 0xD2, 0x8D, 0x4A, 0x06, 0x00, 0x00, 0x09, 0x46, 0x06, 0x8B, 0x09, 0x06, - 0x65, 0xAA, 0x09, 0x46, 0x65, 0x94, 0x64, 0xC6, 0x04, 0x00, 0x09, 0x46, 0x06, - 0xCB, 0x45, 0x46, 0x04, 0x00, 0x09, 0x46, 0x06, 0x99, 0x64, 0x06, 0x05, 0x00, - 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x0B, 0xA4, 0x46, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, - 0x80, 0x0C, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x80, - 0x02, 0xE4, 0x86, 0x05, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0D, 0x24, 0xC7, 0x05, 0x00, 0x00, - 0x00, 0x80, 0x0D, 0x45, 0xC7, 0x25, 0x00, 0xA5, 0x07, 0x00, 0x00, 0x5C, 0x47, - 0x00, 0x00, 0x47, 0x03, 0x26, 0x00, 0x07, 0x47, 0x26, 0x00, 0x1E, 0x00, 0x80, - 0x00, 0x9A, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x6A, 0x69, 0x74, - 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x00, - 0x04, 0x0C, 0x00, 0x00, 0x00, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, - 0x6E, 0x75, 0x6D, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBC, 0xC3, 0x40, - 0x04, 0x25, 0x00, 0x00, 0x00, 0x4C, 0x75, 0x61, 0x4A, 0x49, 0x54, 0x20, 0x63, - 0x6F, 0x72, 0x65, 0x2F, 0x6C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x20, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6D, 0x69, 0x73, 0x6D, 0x61, 0x74, - 0x63, 0x68, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x6A, 0x69, 0x74, 0x2E, 0x75, - 0x74, 0x69, 0x6C, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, - 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x72, 0x61, 0x77, 0x67, 0x65, 0x74, 0x00, - 0x04, 0x05, 0x00, 0x00, 0x00, 0x6E, 0x65, 0x78, 0x74, 0x00, 0x04, 0x06, 0x00, - 0x00, 0x00, 0x68, 0x69, 0x6E, 0x74, 0x73, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, - 0x66, 0x68, 0x69, 0x6E, 0x74, 0x73, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x73, - 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x73, 0x75, - 0x62, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x74, 0x63, 0x68, 0x00, - 0x04, 0x05, 0x00, 0x00, 0x00, 0x67, 0x73, 0x75, 0x62, 0x00, 0x04, 0x04, 0x00, - 0x00, 0x00, 0x6F, 0x66, 0x66, 0x00, 0x04, 0x0F, 0x00, 0x00, 0x00, 0x63, 0x6F, - 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x67, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x00, - 0x04, 0x03, 0x00, 0x00, 0x00, 0x5F, 0x47, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x70, 0x61, 0x69, 0x72, - 0x73, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x2E, 0x2E, 0x30, 0x00, 0x04, 0x02, - 0x00, 0x00, 0x00, 0x54, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x69, 0x70, 0x61, - 0x69, 0x72, 0x73, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x2E, 0x2E, 0x49, 0x00, - 0x04, 0x03, 0x00, 0x00, 0x00, 0x2E, 0x2E, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, - 0x54, 0x2E, 0x3F, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x53, 0x00, 0x04, 0x02, - 0x00, 0x00, 0x00, 0x2E, 0x00, 0x04, 0x0D, 0x00, 0x00, 0x00, 0x67, 0x65, 0x74, - 0x6D, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x04, 0x0D, 0x00, - 0x00, 0x00, 0x73, 0x65, 0x74, 0x6D, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6C, - 0x65, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x54, 0x54, 0x3F, 0x00, 0x04, 0x09, - 0x00, 0x00, 0x00, 0x72, 0x61, 0x77, 0x65, 0x71, 0x75, 0x61, 0x6C, 0x00, 0x04, - 0x02, 0x00, 0x00, 0x00, 0x42, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x54, 0x2E, - 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x72, 0x61, 0x77, 0x73, 0x65, 0x74, 0x00, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x54, 0x2E, 0x2E, 0x00, 0x04, 0x02, 0x00, 0x00, - 0x00, 0x2A, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x2E, 0x2E, 0x2A, 0x00, 0x04, - 0x09, 0x00, 0x00, 0x00, 0x74, 0x6F, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x00, - 0x04, 0x02, 0x00, 0x00, 0x00, 0x49, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x2E, - 0x49, 0x3F, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x74, 0x6F, 0x73, 0x74, 0x72, - 0x69, 0x6E, 0x67, 0x00, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x72, 0x6F, - 0x75, 0x74, 0x69, 0x6E, 0x65, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x41, 0x04, 0x06, 0x00, 0x00, 0x00, 0x79, 0x69, 0x65, 0x6C, 0x64, 0x00, - 0x04, 0x03, 0x00, 0x00, 0x00, 0x2E, 0x2A, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, - 0x72, 0x65, 0x73, 0x75, 0x6D, 0x65, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x52, - 0x2E, 0x2A, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x77, 0x72, 0x61, 0x70, 0x00, - 0x04, 0x02, 0x00, 0x00, 0x00, 0x43, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x41, 0x04, 0x04, 0x00, - 0x00, 0x00, 0x6C, 0x65, 0x6E, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x53, 0x49, - 0x49, 0x3F, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x63, 0x68, 0x61, 0x72, 0x00, - 0x04, 0x03, 0x00, 0x00, 0x00, 0x49, 0x2A, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, - 0x62, 0x79, 0x74, 0x65, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x72, 0x65, 0x70, - 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x53, 0x49, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x00, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x00, 0x04, 0x06, 0x00, 0x00, - 0x00, 0x75, 0x70, 0x70, 0x65, 0x72, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x6C, - 0x6F, 0x77, 0x65, 0x72, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x66, 0x6F, 0x72, - 0x6D, 0x61, 0x74, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x53, 0x2E, 0x2A, 0x00, - 0x04, 0x05, 0x00, 0x00, 0x00, 0x66, 0x69, 0x6E, 0x64, 0x00, 0x04, 0x07, 0x00, - 0x00, 0x00, 0x53, 0x53, 0x49, 0x3F, 0x2E, 0x3F, 0x00, 0x04, 0x05, 0x00, 0x00, - 0x00, 0x53, 0x53, 0x49, 0x3F, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x53, 0x53, - 0x47, 0x49, 0x3F, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x67, 0x6D, 0x61, 0x74, - 0x63, 0x68, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x43, 0x30, 0x30, 0x00, 0x04, - 0x03, 0x00, 0x00, 0x00, 0x53, 0x53, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x74, - 0x61, 0x62, 0x6C, 0x65, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x41, 0x04, 0x07, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x00, - 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x54, 0x49, - 0x3F, 0x2E, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x72, 0x65, 0x6D, 0x6F, 0x76, - 0x65, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x67, 0x65, 0x74, 0x6E, 0x00, 0x04, - 0x07, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6E, 0x63, 0x61, 0x74, 0x00, 0x04, 0x08, - 0x00, 0x00, 0x00, 0x54, 0x53, 0x3F, 0x49, 0x3F, 0x49, 0x3F, 0x00, 0x04, 0x05, - 0x00, 0x00, 0x00, 0x6D, 0x61, 0x74, 0x68, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x14, 0x41, 0x04, 0x04, 0x00, 0x00, 0x00, 0x6C, 0x6F, 0x67, 0x00, - 0x04, 0x02, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x6C, - 0x6F, 0x67, 0x31, 0x30, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x65, 0x78, 0x70, - 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x73, 0x69, 0x6E, 0x68, 0x00, 0x04, 0x05, - 0x00, 0x00, 0x00, 0x63, 0x6F, 0x73, 0x68, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, - 0x74, 0x61, 0x6E, 0x68, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x61, 0x73, 0x69, - 0x6E, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x61, 0x63, 0x6F, 0x73, 0x00, 0x04, - 0x05, 0x00, 0x00, 0x00, 0x61, 0x74, 0x61, 0x6E, 0x00, 0x04, 0x04, 0x00, 0x00, - 0x00, 0x73, 0x69, 0x6E, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x73, - 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x74, 0x61, 0x6E, 0x00, 0x04, 0x05, 0x00, - 0x00, 0x00, 0x63, 0x65, 0x69, 0x6C, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x66, - 0x6C, 0x6F, 0x6F, 0x72, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x61, 0x62, 0x73, - 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x73, 0x71, 0x72, 0x74, 0x00, 0x04, 0x05, - 0x00, 0x00, 0x00, 0x66, 0x6D, 0x6F, 0x64, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, - 0x4E, 0x4E, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x61, 0x74, 0x61, 0x6E, 0x32, - 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x69, 0x6E, 0x00, 0x04, 0x04, 0x00, - 0x00, 0x00, 0x4E, 0x4E, 0x2A, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, - 0x78, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x64, 0x65, 0x67, 0x00, 0x04, 0x04, - 0x00, 0x00, 0x00, 0x72, 0x61, 0x64, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x6D, - 0x6F, 0x64, 0x66, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x00, 0x04, - 0x06, 0x00, 0x00, 0x00, 0x66, 0x72, 0x65, 0x78, 0x70, 0x00, 0x04, 0x03, 0x00, - 0x00, 0x00, 0x4E, 0x49, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x70, 0x6F, 0x77, - 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x6C, 0x64, 0x65, 0x78, 0x70, 0x00, 0x04, - 0x0B, 0x00, 0x00, 0x00, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D, 0x73, 0x65, 0x65, - 0x64, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D, - 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x49, 0x3F, 0x49, 0x3F, 0x00, 0x04, 0x03, - 0x00, 0x00, 0x00, 0x69, 0x6F, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x6C, 0x69, - 0x6E, 0x65, 0x73, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x43, 0x30, 0x30, 0x53, - 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x53, 0x3F, 0x00, 0x04, 0x05, 0x00, 0x00, - 0x00, 0x72, 0x65, 0x61, 0x64, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x6E, 0x69, - 0x6C, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x00, 0x62, 0x6F, 0x6F, 0x6C, 0x65, 0x61, 0x6E, 0x00, 0x04, 0x02, 0x00, 0x00, - 0x00, 0x62, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x6E, 0x75, 0x6D, 0x62, 0x65, - 0x72, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x04, 0x02, 0x00, 0x00, - 0x00, 0x73, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x74, 0x00, 0x04, 0x09, 0x00, - 0x00, 0x00, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x04, 0x02, - 0x00, 0x00, 0x00, 0x66, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x75, 0x73, 0x65, - 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x75, 0x00, - 0x04, 0x07, 0x00, 0x00, 0x00, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x00, 0x04, - 0x02, 0x00, 0x00, 0x00, 0x72, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x5B, 0x62, - 0x30, 0x5D, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x5B, 0x73, 0x30, 0x5D, 0x00, - 0x04, 0x05, 0x00, 0x00, 0x00, 0x5B, 0x74, 0x30, 0x5D, 0x00, 0x04, 0x05, 0x00, - 0x00, 0x00, 0x5B, 0x66, 0x30, 0x5D, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x55, - 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x5B, 0x75, 0x30, 0x5D, 0x00, 0x04, 0x02, - 0x00, 0x00, 0x00, 0x52, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x5B, 0x72, 0x30, - 0x5D, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x5B, 0x6E, 0x30, 0x5D, 0x00, 0x04, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x5B, 0x73, - 0x74, 0x66, 0x30, 0x5D, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xE0, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x04, - 0x02, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x6D, 0x6F, - 0x64, 0x75, 0x6C, 0x65, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x67, 0x65, 0x74, - 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, - 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x08, 0x18, 0x00, 0x00, - 0x00, 0x84, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x01, 0x9A, 0x00, 0x00, 0x00, - 0x16, 0xC0, 0x02, 0x80, 0xC6, 0x00, 0x40, 0x01, 0x06, 0x41, 0x40, 0x01, 0xDA, - 0x00, 0x00, 0x00, 0x16, 0x40, 0x01, 0x80, 0x40, 0x01, 0x80, 0x01, 0x81, 0x81, - 0x00, 0x00, 0xC0, 0x01, 0x00, 0x02, 0x55, 0xC1, 0x81, 0x02, 0x5E, 0x01, 0x00, - 0x01, 0x16, 0x00, 0x02, 0x80, 0x1E, 0x01, 0x00, 0x01, 0x16, 0x80, 0x01, 0x80, - 0x17, 0xC0, 0xC0, 0x00, 0x16, 0x80, 0x00, 0x80, 0xC1, 0x00, 0x01, 0x00, 0xDE, - 0x00, 0x00, 0x01, 0x16, 0x40, 0x00, 0x80, 0xC1, 0x40, 0x01, 0x00, 0xDE, 0x00, - 0x00, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, - 0x00, 0x00, 0x6C, 0x69, 0x62, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x04, 0x05, 0x00, - 0x00, 0x00, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x2E, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0A, 0x00, - 0x00, 0x00, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x00, 0x04, - 0x02, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3A, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x05, 0x04, 0x00, 0x08, 0x18, - 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x44, 0x01, 0x80, 0x00, 0x80, 0x01, - 0x00, 0x00, 0x1C, 0x81, 0x80, 0x01, 0x1A, 0x01, 0x00, 0x00, 0x16, 0x80, 0x02, - 0x80, 0x44, 0x01, 0x00, 0x01, 0x8A, 0x81, 0x01, 0x00, 0xC4, 0x01, 0x80, 0x01, - 0x89, 0xC1, 0x01, 0x80, 0x89, 0x01, 0x80, 0x80, 0xC4, 0x01, 0x00, 0x02, 0x89, - 0xC1, 0x01, 0x81, 0x89, 0x41, 0x80, 0x81, 0x89, 0x81, 0x00, 0x82, 0x89, 0xC1, - 0x80, 0x82, 0x49, 0x81, 0x01, 0x02, 0x44, 0x01, 0x00, 0x02, 0x5A, 0x01, 0x00, - 0x00, 0x16, 0x80, 0x00, 0x80, 0x44, 0x01, 0x00, 0x02, 0x4C, 0x81, 0xC1, 0x02, - 0x48, 0x01, 0x00, 0x02, 0x1E, 0x00, 0x80, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, - 0x08, 0x00, 0x00, 0x00, 0x6C, 0x69, 0x62, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x04, - 0x05, 0x00, 0x00, 0x00, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x04, 0x04, 0x00, 0x00, - 0x00, 0x69, 0x64, 0x78, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x72, 0x65, 0x73, - 0x75, 0x6C, 0x74, 0x73, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x61, 0x72, 0x67, - 0x73, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, - 0x72, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, - 0x03, 0x05, 0x00, 0x08, 0x12, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x8A, - 0x81, 0x01, 0x00, 0xC4, 0x01, 0x80, 0x00, 0x89, 0xC1, 0x01, 0x80, 0x89, 0x01, - 0x80, 0x80, 0xC4, 0x01, 0x00, 0x01, 0x89, 0xC1, 0x01, 0x81, 0x89, 0x81, 0x80, - 0x81, 0x89, 0xC1, 0x00, 0x82, 0x89, 0x01, 0x81, 0x82, 0x49, 0x81, 0x81, 0x00, - 0x44, 0x01, 0x00, 0x01, 0x5A, 0x01, 0x00, 0x00, 0x16, 0x80, 0x00, 0x80, 0x44, - 0x01, 0x00, 0x01, 0x4C, 0x81, 0xC1, 0x02, 0x48, 0x01, 0x00, 0x01, 0x1E, 0x00, - 0x80, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x6C, 0x69, - 0x62, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x6E, 0x61, - 0x6D, 0x65, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x69, 0x64, 0x78, 0x00, 0x04, - 0x08, 0x00, 0x00, 0x00, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x73, 0x00, 0x04, - 0x05, 0x00, 0x00, 0x00, 0x61, 0x72, 0x67, 0x73, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x00, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, - 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x04, 0x00, - 0x00, 0x00, 0x8C, 0x01, 0xC0, 0x01, 0x86, 0x81, 0x81, 0x00, 0x49, 0x80, 0x81, - 0x01, 0x1E, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, - 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x03, 0x05, 0x00, 0x13, 0x2A, 0x00, - 0x00, 0x00, 0x1A, 0x01, 0x00, 0x00, 0x16, 0x80, 0x08, 0x80, 0x44, 0x01, 0x00, - 0x00, 0x46, 0x01, 0xC0, 0x02, 0x86, 0x41, 0x40, 0x00, 0xC0, 0x01, 0x80, 0x02, - 0x00, 0x02, 0x00, 0x03, 0x4C, 0x82, 0x40, 0x01, 0xDC, 0x01, 0x81, 0x01, 0x17, - 0xC0, 0xC0, 0x03, 0x16, 0x40, 0x06, 0x80, 0x8C, 0x02, 0x41, 0x01, 0x8C, 0x42, - 0x02, 0x05, 0xC0, 0x02, 0x80, 0x02, 0x00, 0x03, 0x00, 0x03, 0x40, 0x03, 0x00, - 0x05, 0xDC, 0x42, 0x81, 0x01, 0x17, 0x40, 0xC1, 0x05, 0x16, 0x40, 0x04, 0x80, - 0x17, 0xC0, 0x00, 0x06, 0x16, 0xC0, 0x03, 0x80, 0x19, 0x00, 0x41, 0x07, 0x16, - 0x40, 0x03, 0x80, 0xC0, 0x03, 0x80, 0x02, 0x00, 0x04, 0x00, 0x03, 0x4C, 0x84, - 0x40, 0x05, 0xDC, 0x03, 0x81, 0x01, 0x17, 0xC0, 0xC0, 0x07, 0x16, 0xC0, 0x01, - 0x80, 0x8C, 0x44, 0x84, 0x04, 0x17, 0x80, 0x41, 0x09, 0x16, 0x00, 0x01, 0x80, - 0x84, 0x04, 0x80, 0x00, 0x86, 0xC4, 0x41, 0x09, 0x8C, 0x84, 0x04, 0x05, 0x09, - 0x00, 0x01, 0x09, 0x1E, 0x00, 0x80, 0x00, 0x44, 0x01, 0x00, 0x01, 0x49, 0x40, - 0x81, 0x01, 0x42, 0x01, 0x80, 0x00, 0x5E, 0x01, 0x00, 0x01, 0x1E, 0x00, 0x80, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, - 0x65, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x66, 0x75, - 0x6E, 0x63, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x04, - 0x04, 0x00, 0x00, 0x00, 0x4A, 0x4D, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x04, 0x09, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4F, 0x52, - 0x4C, 0x4F, 0x4F, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x04, 0x07, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x4C, 0x49, 0x4E, 0x45, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x7E, 0x00, - 0x00, 0x00, 0x02, 0x04, 0x00, 0x09, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x40, - 0x01, 0x06, 0x01, 0x81, 0x00, 0x43, 0x01, 0x00, 0x03, 0xC4, 0x01, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x02, 0xDC, 0x81, 0x00, 0x01, 0x17, 0x40, 0xC0, 0x03, 0x16, - 0x00, 0x02, 0x80, 0xC4, 0x01, 0x80, 0x00, 0x00, 0x02, 0x00, 0x02, 0xDC, 0xC1, - 0x00, 0x01, 0x80, 0x01, 0x00, 0x04, 0x40, 0x01, 0x80, 0x03, 0x17, 0x80, 0x40, - 0x03, 0x16, 0x40, 0x00, 0x80, 0xC6, 0xC1, 0x40, 0x00, 0x86, 0x01, 0x81, 0x03, - 0xDB, 0x41, 0x80, 0x02, 0x16, 0x00, 0x00, 0x80, 0xC1, 0x01, 0x01, 0x00, 0x49, - 0xC0, 0x81, 0x01, 0xCC, 0x01, 0xC0, 0x01, 0x49, 0x80, 0x81, 0x03, 0x1E, 0x00, - 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xF0, 0x3F, 0x04, 0x06, 0x00, 0x00, 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, - 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x76, 0x61, - 0x6C, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x02, 0x07, 0x00, - 0x0D, 0x0F, 0x00, 0x00, 0x00, 0xC4, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x40, 0x02, 0x80, 0x00, 0x80, 0x02, 0x80, 0x01, 0xCC, 0x02, 0xC0, 0x01, 0xDC, - 0x41, 0x80, 0x02, 0xC4, 0x01, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, - 0x80, 0x00, 0x80, 0x02, 0x00, 0x01, 0xC0, 0x02, 0x80, 0x01, 0x00, 0x03, 0x00, - 0x03, 0xDD, 0x01, 0x00, 0x03, 0xDE, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x80, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x99, 0x00, - 0x00, 0x00, 0x03, 0x07, 0x00, 0x0F, 0x1E, 0x00, 0x00, 0x00, 0xCC, 0x01, 0xC0, - 0x01, 0xC6, 0xC1, 0x81, 0x00, 0x0C, 0x42, 0xC0, 0x01, 0x49, 0x00, 0x40, 0x04, - 0x03, 0x02, 0x00, 0x04, 0x44, 0x02, 0x00, 0x00, 0x80, 0x02, 0x80, 0x03, 0x5C, - 0x82, 0x00, 0x01, 0x17, 0x80, 0xC0, 0x04, 0x16, 0x00, 0x02, 0x80, 0x44, 0x02, - 0x80, 0x00, 0x80, 0x02, 0x80, 0x03, 0xC1, 0x02, 0x00, 0x00, 0x5C, 0x82, 0x80, - 0x01, 0x00, 0x02, 0x80, 0x04, 0x17, 0xC0, 0x40, 0x04, 0x16, 0x40, 0x00, 0x80, - 0x46, 0x02, 0x41, 0x00, 0x06, 0xC2, 0x81, 0x04, 0x4C, 0x42, 0xC1, 0x01, 0x49, - 0x00, 0x82, 0x04, 0x44, 0x02, 0x00, 0x01, 0x80, 0x02, 0x00, 0x00, 0xC0, 0x02, - 0x80, 0x00, 0x00, 0x03, 0x00, 0x01, 0x40, 0x03, 0x80, 0x01, 0x80, 0x03, 0x00, - 0x03, 0x5D, 0x02, 0x00, 0x03, 0x5E, 0x02, 0x00, 0x00, 0x1E, 0x00, 0x80, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x04, 0x06, 0x00, 0x00, - 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, - 0x74, 0x61, 0x62, 0x6C, 0x65, 0x76, 0x61, 0x6C, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, - 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x0B, 0x07, 0x00, - 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, - 0x00, 0x40, 0x02, 0x80, 0x01, 0x80, 0x02, 0x80, 0x01, 0x9C, 0x41, 0x80, 0x02, - 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, - 0x0A, 0x11, 0x00, 0x00, 0x00, 0x8C, 0x01, 0xC0, 0x01, 0x86, 0x81, 0x81, 0x00, - 0xC4, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0xDC, 0x81, 0x00, 0x01, 0x17, - 0x40, 0xC0, 0x03, 0x16, 0x80, 0x01, 0x80, 0xC4, 0x01, 0x80, 0x00, 0x00, 0x02, - 0x00, 0x03, 0x4C, 0x82, 0xC0, 0x01, 0x46, 0x42, 0x82, 0x00, 0xDC, 0x81, 0x80, - 0x01, 0xDA, 0x41, 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0xC1, 0xC1, 0x00, 0x00, - 0x49, 0xC0, 0x81, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x04, 0x06, 0x00, 0x00, 0x00, - 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, - 0x0C, 0x10, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x80, 0x02, - 0x01, 0x02, 0x00, 0x00, 0xA0, 0x41, 0x02, 0x80, 0x8C, 0x42, 0x82, 0x01, 0x8D, - 0x02, 0x40, 0x05, 0x19, 0x00, 0x81, 0x04, 0x16, 0xC0, 0x00, 0x80, 0xCC, 0x42, - 0x82, 0x01, 0xC6, 0xC2, 0x82, 0x00, 0xDA, 0x42, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x80, 0xC3, 0x02, 0x80, 0x05, 0x49, 0xC0, 0x02, 0x05, 0x9F, 0x01, 0xFD, 0x7F, - 0x1E, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7, 0x00, - 0x00, 0x00, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0B, 0x09, 0x00, 0x00, - 0x00, 0x49, 0x00, 0xC0, 0x01, 0x81, 0x41, 0x00, 0x00, 0xCD, 0x41, 0xC0, 0x02, - 0x01, 0x42, 0x00, 0x00, 0xA0, 0x41, 0x00, 0x80, 0x8C, 0x42, 0x82, 0x01, 0x49, - 0x80, 0x40, 0x05, 0x9F, 0x01, 0xFF, 0x7F, 0x1E, 0x00, 0x80, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x00, 0x00, 0x00, 0xCB, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0B, 0x08, 0x00, 0x00, 0x00, 0x81, 0x01, - 0x00, 0x00, 0xCD, 0x41, 0xC0, 0x02, 0x01, 0x42, 0x00, 0x00, 0xA0, 0x41, 0x00, - 0x80, 0x8C, 0x42, 0x82, 0x01, 0x49, 0x40, 0x40, 0x05, 0x9F, 0x01, 0xFF, 0x7F, - 0x1E, 0x00, 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x00, 0x00, 0x00, 0xD7, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x00, 0x0B, 0x0B, 0x00, 0x00, 0x00, 0x49, 0x00, 0xC0, - 0x01, 0x8C, 0x01, 0xC0, 0x01, 0x49, 0x00, 0x40, 0x03, 0x81, 0x41, 0x00, 0x00, - 0xCD, 0x01, 0xC0, 0x02, 0x01, 0x02, 0x00, 0x00, 0xA0, 0x41, 0x00, 0x80, 0x8C, - 0x42, 0x82, 0x01, 0x49, 0x80, 0x40, 0x05, 0x9F, 0x01, 0xFF, 0x7F, 0x1E, 0x00, - 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xF0, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x00, - 0x00, 0x00, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0B, 0x08, 0x00, 0x00, - 0x00, 0x81, 0x01, 0x00, 0x00, 0xCD, 0x41, 0xC0, 0x02, 0x01, 0x42, 0x00, 0x00, - 0xA0, 0x41, 0x00, 0x80, 0x8C, 0x42, 0x82, 0x01, 0x49, 0x80, 0x40, 0x05, 0x9F, - 0x01, 0xFF, 0x7F, 0x1E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xF0, 0x3F, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xDE, 0x00, 0x00, 0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x06, - 0x00, 0x0A, 0x09, 0x00, 0x00, 0x00, 0x8C, 0x01, 0xC0, 0x01, 0xC6, 0x41, 0x40, - 0x00, 0xC6, 0x81, 0xC0, 0x03, 0xCD, 0xC1, 0xC0, 0x03, 0x01, 0xC2, 0x00, 0x00, - 0xA0, 0x01, 0x00, 0x80, 0x49, 0x00, 0xC1, 0x04, 0x9F, 0x41, 0xFF, 0x7F, 0x1E, - 0x00, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x74, 0x73, - 0x00, 0x04, 0x0B, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x63, 0x6B, 0x73, 0x6C, - 0x6F, 0x74, 0x73, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, - 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x00, 0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x0A, 0x12, - 0x00, 0x00, 0x00, 0x19, 0x40, 0x01, 0x80, 0x16, 0x80, 0x03, 0x80, 0x8C, 0x01, - 0xC0, 0x01, 0x86, 0x81, 0x81, 0x00, 0xC4, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x03, 0xDC, 0x81, 0x00, 0x01, 0x17, 0x40, 0xC0, 0x03, 0x16, 0x40, 0x01, 0x80, - 0xC4, 0x01, 0x80, 0x00, 0x00, 0x02, 0x00, 0x03, 0x41, 0x02, 0x00, 0x00, 0xDC, - 0x81, 0x80, 0x01, 0xDA, 0x41, 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0xC1, 0x81, - 0x00, 0x00, 0x49, 0xC0, 0x81, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x04, 0x06, 0x00, - 0x00, 0x00, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x01, 0x00, 0x00, 0x0F, - 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x8C, 0x01, - 0xC0, 0x01, 0x86, 0x81, 0x81, 0x00, 0x9A, 0x41, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x80, 0x81, 0x41, 0x00, 0x00, 0x49, 0x80, 0x81, 0x01, 0x1E, 0x00, 0x80, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x00, 0x06, - 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x80, 0x16, 0x00, 0x00, - 0x80, 0x49, 0x40, 0xC0, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, - 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, - 0x00, 0x00, 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x4D, 0x01, 0x00, 0x00, 0x02, - 0x01, 0x00, 0x06, 0x0B, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x84, 0x00, - 0x00, 0x00, 0xC6, 0x40, 0x40, 0x00, 0x01, 0x81, 0x00, 0x00, 0x44, 0x01, 0x80, - 0x00, 0x9C, 0x80, 0x00, 0x02, 0xC1, 0xC0, 0x00, 0x00, 0x55, 0xC0, 0x80, 0x00, - 0x09, 0x40, 0x00, 0x82, 0x5E, 0x00, 0x00, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x05, - 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x04, 0x05, 0x00, - 0x00, 0x00, 0x61, 0x72, 0x67, 0x73, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x2E, - 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x30, 0x2A, 0x24, 0x00, 0x04, 0x09, 0x00, - 0x00, 0x00, 0x61, 0x72, 0x67, 0x6D, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x69, 0x01, 0x00, 0x00, - 0x07, 0x07, 0x00, 0x12, 0x4F, 0x00, 0x00, 0x00, 0xC6, 0x01, 0x40, 0x00, 0xDA, - 0x01, 0x00, 0x00, 0x16, 0xC0, 0x06, 0x80, 0x57, 0x40, 0xC0, 0x02, 0x16, 0x40, - 0x06, 0x80, 0x01, 0x82, 0x00, 0x00, 0x41, 0xC2, 0x00, 0x00, 0x80, 0x02, 0x80, - 0x02, 0xC1, 0xC2, 0x00, 0x00, 0x60, 0xC2, 0x01, 0x80, 0x40, 0x03, 0x00, 0x04, - 0x84, 0x03, 0x00, 0x00, 0xC4, 0x03, 0x80, 0x00, 0x0C, 0x04, 0x03, 0x02, 0x06, - 0x04, 0x04, 0x01, 0xDC, 0x83, 0x00, 0x01, 0x86, 0xC3, 0x03, 0x07, 0x15, 0x82, - 0x83, 0x06, 0x5F, 0x82, 0xFD, 0x7F, 0x44, 0x02, 0x00, 0x01, 0x80, 0x02, 0x00, - 0x04, 0xC6, 0x02, 0x41, 0x00, 0xDA, 0x42, 0x00, 0x00, 0x16, 0x80, 0x00, 0x80, - 0xC4, 0x02, 0x80, 0x01, 0x00, 0x03, 0x00, 0x00, 0xDC, 0x82, 0x00, 0x01, 0x5C, - 0x82, 0x80, 0x01, 0x5A, 0x42, 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0xC3, 0x01, - 0x80, 0x03, 0x06, 0x42, 0x41, 0x00, 0x57, 0x80, 0x41, 0x04, 0x16, 0x80, 0x05, - 0x80, 0x57, 0x40, 0x40, 0x03, 0x16, 0x00, 0x05, 0x80, 0x54, 0x02, 0x00, 0x04, - 0x18, 0x80, 0x81, 0x04, 0x16, 0x00, 0x00, 0x80, 0xC3, 0x01, 0x80, 0x03, 0x41, - 0xC2, 0x00, 0x00, 0x94, 0x02, 0x00, 0x04, 0xC1, 0xC2, 0x00, 0x00, 0x60, 0xC2, - 0x02, 0x80, 0x44, 0x03, 0x00, 0x02, 0x80, 0x03, 0x00, 0x04, 0xC0, 0x03, 0x00, - 0x06, 0x00, 0x04, 0x00, 0x06, 0x5C, 0x83, 0x00, 0x02, 0x57, 0xC0, 0xC1, 0x06, - 0x16, 0x00, 0x01, 0x80, 0x8C, 0x03, 0x03, 0x02, 0x8D, 0xC3, 0x40, 0x07, 0xC4, - 0x03, 0x80, 0x02, 0xC6, 0x43, 0x83, 0x07, 0x89, 0xC0, 0x03, 0x07, 0x5F, 0x82, - 0xFC, 0x7F, 0x46, 0x02, 0x42, 0x00, 0x5A, 0x02, 0x00, 0x00, 0x16, 0xC0, 0x02, - 0x80, 0x80, 0x02, 0x80, 0x04, 0xC0, 0x02, 0x80, 0x00, 0x00, 0x03, 0x00, 0x01, - 0x40, 0x03, 0x80, 0x01, 0x80, 0x03, 0x00, 0x02, 0xC0, 0x03, 0x80, 0x02, 0x00, - 0x04, 0x00, 0x03, 0x40, 0x04, 0x80, 0x03, 0x9C, 0x82, 0x00, 0x04, 0x9A, 0x02, - 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0xC3, 0x01, 0x80, 0x03, 0xDA, 0x01, 0x00, - 0x00, 0x16, 0xC0, 0x00, 0x80, 0x84, 0x02, 0x00, 0x03, 0x86, 0x42, 0x42, 0x05, - 0x8C, 0x82, 0x82, 0x01, 0x49, 0xC0, 0x01, 0x05, 0x1E, 0x00, 0x80, 0x00, 0x0A, - 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x69, 0x64, 0x78, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBF, 0x04, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x04, 0x09, 0x00, - 0x00, 0x00, 0x61, 0x72, 0x67, 0x6D, 0x61, 0x74, 0x63, 0x68, 0x00, 0x04, 0x08, - 0x00, 0x00, 0x00, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x73, 0x00, 0x04, 0x02, - 0x00, 0x00, 0x00, 0x2A, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x04, - 0x08, 0x00, 0x00, 0x00, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00, 0x04, - 0x07, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x4C, 0x49, 0x4E, 0x45, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x01, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00, - 0x04, 0x06, 0x00, 0x10, 0x31, 0x00, 0x00, 0x00, 0x86, 0xC1, 0x80, 0x00, 0xC4, - 0x01, 0x00, 0x00, 0xC6, 0x01, 0xC0, 0x03, 0xCC, 0xC1, 0x01, 0x01, 0x09, 0x80, - 0x81, 0x03, 0xC4, 0x01, 0x80, 0x00, 0x00, 0x02, 0x00, 0x03, 0xDC, 0x81, 0x00, - 0x01, 0x17, 0x40, 0xC0, 0x03, 0x16, 0x80, 0x07, 0x80, 0xC4, 0x01, 0x00, 0x01, - 0xC6, 0x81, 0x81, 0x03, 0xDA, 0x01, 0x00, 0x00, 0x16, 0x40, 0x02, 0x80, 0x04, - 0x02, 0x80, 0x01, 0x40, 0x02, 0x80, 0x03, 0x80, 0x02, 0x00, 0x00, 0xC0, 0x02, - 0x80, 0x00, 0x00, 0x03, 0x00, 0x01, 0x40, 0x03, 0x80, 0x01, 0x80, 0x03, 0x00, - 0x02, 0xC0, 0x03, 0x80, 0x02, 0x1C, 0x42, 0x00, 0x04, 0x1E, 0x00, 0x80, 0x00, - 0x06, 0x82, 0x40, 0x00, 0x17, 0x00, 0x02, 0x03, 0x16, 0x40, 0x03, 0x80, 0x06, - 0xC2, 0x40, 0x00, 0x06, 0x02, 0x41, 0x04, 0x1A, 0x42, 0x00, 0x00, 0x16, 0x40, - 0x02, 0x80, 0x57, 0x40, 0x41, 0x02, 0x16, 0xC0, 0x00, 0x80, 0x06, 0xC2, 0x40, - 0x00, 0x06, 0x82, 0x41, 0x04, 0x17, 0x00, 0x02, 0x02, 0x16, 0xC0, 0x00, 0x80, - 0x04, 0x02, 0x00, 0x00, 0x06, 0xC2, 0x41, 0x04, 0x0C, 0x02, 0x02, 0x01, 0x09, - 0x00, 0x42, 0x04, 0xC0, 0x01, 0x80, 0x01, 0x0C, 0x42, 0x81, 0x01, 0x0D, 0x42, - 0x42, 0x04, 0x41, 0x42, 0x02, 0x00, 0xE0, 0x01, 0x00, 0x80, 0x49, 0x80, 0x42, - 0x05, 0xDF, 0x41, 0xFF, 0x7F, 0x1E, 0x00, 0x80, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x04, 0x05, 0x00, 0x00, 0x00, 0x54, 0x59, 0x50, 0x45, 0x00, 0x04, 0x09, 0x00, - 0x00, 0x00, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x04, 0x05, - 0x00, 0x00, 0x00, 0x66, 0x75, 0x6E, 0x63, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, - 0x73, 0x74, 0x61, 0x74, 0x73, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00, 0x69, 0x73, - 0x76, 0x61, 0x72, 0x61, 0x72, 0x67, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xF0, 0xBF, 0x04, 0x07, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6D, - 0x73, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x4C, 0x49, 0x4E, 0x45, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x01, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, - 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x40, 0x00, 0x00, 0x1C, - 0x80, 0x00, 0x01, 0x46, 0x80, 0x40, 0x00, 0x84, 0x00, 0x00, 0x00, 0x5C, 0x40, - 0x00, 0x01, 0x1E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, - 0x00, 0x00, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x00, 0x04, 0x08, 0x00, - 0x00, 0x00, 0x6A, 0x69, 0x74, 0x2E, 0x6F, 0x70, 0x74, 0x00, 0x04, 0x10, 0x00, - 0x00, 0x00, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5F, 0x63, 0x61, 0x6C, 0x6C, - 0x68, 0x69, 0x6E, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; diff -Nru corsix-th-0.30/CorsixTH/Src/lua.hpp corsix-th-0.62/CorsixTH/Src/lua.hpp --- corsix-th-0.30/CorsixTH/Src/lua.hpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/lua.hpp 2018-07-21 11:13:17.000000000 +0000 @@ -34,41 +34,42 @@ // These definitions will already have been made if Lua 5.2 was compiled // with LUA_COMPAT_ALL defined, but we have no control over this. -#ifdef LUA_RIDX_CPCALL -// NB: Lua 5.2 isn't officially released yet, and only "work" versions are -// available. Until 5.2 is officially released, this makes 5.2 a moving target -// and it only makes sense to target the most recent version. -// LUA_RIDX_CPCALL was defined in 5.2-work1 and 5.2-work2, but is not present -// in 5.2-work3 (there were many other changes, but this is the easiest to -// detect at compile-time) -#error Please update to the latest version of Lua 5.2 -#endif - #ifndef lua_objlen -#define lua_objlen(L, i) lua_rawlen(L, (i)) -#endif - -#ifndef luaL_typerror -#define luaL_typerror luaL_typeerror +inline size_t lua_objlen(lua_State *L, int idx) +{ + return lua_rawlen(L, idx); +} #endif #ifndef lua_equal -#define lua_equal(L, idx1, idx2) lua_compare(L, (idx1), (idx2), LUA_OPEQ) +inline int lua_equal(lua_State *L, int idx1, int idx2) +{ + return lua_compare(L, idx1, idx2, LUA_OPEQ); +} #endif #ifndef lua_lessthan -#define lua_lessthan(L, idx1, idx2) lua_compare(L, (idx1), (idx1), LUA_OPLT) +inline int lua_lessthan(lua_State *L, int idx1, int idx2) +{ + return lua_compare(L, idx1, idx2, LUA_OPLT); +} #endif // Use our own replacements for lua_[sg]etfenv #ifndef lua_setfenv -#define lua_setfenv luaT_setfenv52 int luaT_setfenv52(lua_State*, int); +inline int lua_setfenv(lua_State *L, int n) +{ + return luaT_setfenv52(L, n); +} #endif #ifndef lua_getfenv -#define lua_getfenv luaT_getfenv52 void luaT_getfenv52(lua_State*, int); +inline void lua_getfenv(lua_State *L, int n) +{ + luaT_getfenv52(L, n); +} #endif #endif // LUA_VERSION_NUM >= 502 diff -Nru corsix-th-0.30/CorsixTH/Src/lua_rnc.cpp corsix-th-0.62/CorsixTH/Src/lua_rnc.cpp --- corsix-th-0.30/CorsixTH/Src/lua_rnc.cpp 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/lua_rnc.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,75 @@ +#include "lua_rnc.h" +#include "../../common/rnc.h" +#include "th_lua.h" + +//! Provides lua function to decompress RNC data +/*! + @param L Lua state where the function is called from. In lua a call + to this function has one parameter which is the RNC compressed data. + The return value is the decompressed data. +*/ +static int l_decompress(lua_State *L) +{ + size_t inlen; + const uint8_t* in = reinterpret_cast(luaL_checklstring(L, 1, &inlen)); + + // Verify that the data contains an RNC signature, and that the input + // size matches the size specified in the data header. + if(inlen < rnc_header_size || inlen != rnc_input_size(in)) + { + lua_pushnil(L); + lua_pushliteral(L, "Input is not RNC compressed data"); + return 2; + } + uint32_t outlen = rnc_output_size(in); + + // Allocate scratch area as Lua userdata so that if something horrible + // happens, it'll be cleaned up by Lua's GC. Remember that most Lua API + // calls can throw errors, so they all have to be wrapped with code to + // detect errors and free the buffer if said buffer was not managed by Lua. + void* outbuf = lua_newuserdata(L, outlen); + + lua_pushnil(L); + switch(rnc_unpack(in, (uint8_t*)outbuf)) + { + case rnc_status::ok: + lua_pushlstring(L, (const char*)outbuf, outlen); + return 1; + + case rnc_status::file_is_not_rnc: + lua_pushliteral(L, "Input is not RNC compressed data"); + break; + + case rnc_status::huf_decode_error: + lua_pushliteral(L, "Invalid Huffman coding"); + break; + + case rnc_status::file_size_mismatch: + lua_pushliteral(L, "Size mismatch"); + break; + + case rnc_status::packed_crc_error: + lua_pushliteral(L, "Incorrect packed CRC"); + break; + + case rnc_status::unpacked_crc_error: + lua_pushliteral(L, "Incorrect unpacked CRC"); + break; + + default: + lua_pushliteral(L, "Unknown error decompressing RNC data"); + break; + } + return 2; +} + +static const std::vector rnclib = { + {"decompress", l_decompress}, + {nullptr, nullptr} +}; + +int luaopen_rnc(lua_State *L) +{ + luaT_register(L, "rnc", rnclib); + return 1; +} diff -Nru corsix-th-0.30/CorsixTH/Src/lua_rnc.h corsix-th-0.62/CorsixTH/Src/lua_rnc.h --- corsix-th-0.30/CorsixTH/Src/lua_rnc.h 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/lua_rnc.h 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,8 @@ +#ifndef CORSIX_TH_LUA_RNC +#define CORSIX_TH_LUA_RNC + +#include "th_lua.h" + +int luaopen_rnc(lua_State *L); + +#endif diff -Nru corsix-th-0.30/CorsixTH/Src/lua_sdl.h corsix-th-0.62/CorsixTH/Src/lua_sdl.h --- corsix-th-0.30/CorsixTH/Src/lua_sdl.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/lua_sdl.h 2018-07-21 11:13:17.000000000 +0000 @@ -32,11 +32,15 @@ #define SDL_USEREVENT_TICK (SDL_USEREVENT + 0) // SDL_USEREVENT_MUSIC_OVER - informs script of SDL_Mixer music finishing #define SDL_USEREVENT_MUSIC_OVER (SDL_USEREVENT + 1) -// SDL_USEREVENT_CPCALL - calls lua_cpcall with SDL_Event user.data1 and data2 -#define SDL_USEREVENT_CPCALL (SDL_USEREVENT + 2) +// SDL_USEREVENT_MUSIC_LOADED - informs script that async music is loaded +#define SDL_USEREVENT_MUSIC_LOADED (SDL_USEREVENT + 2) // SDL USEREVENT_MOVIE_OVER - informs script of THMovie movie finishing #define SDL_USEREVENT_MOVIE_OVER (SDL_USEREVENT + 3) +// SDL_USEREVENT_SOUND_OVER - informs script of a played sound finishing. +#define SDL_USEREVENT_SOUND_OVER (SDL_USEREVENT + 4) int luaopen_sdl(lua_State *L); +int l_load_music_async_callback(lua_State *L); + #endif // CORSIX_TH_LUA_SDL_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/main.cpp corsix-th-0.62/CorsixTH/Src/main.cpp --- corsix-th-0.30/CorsixTH/Src/main.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/main.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -23,16 +23,15 @@ #include "config.h" #include "lua.hpp" extern "C" { -#include "../../LFS/lfs.h" -int luaopen_lpeg(lua_State *L); int luaopen_random(lua_State *L); } -#include "rnc.h" #include "th_lua.h" +#include "lua_rnc.h" #include "lua_sdl.h" -#include "jit_opt.h" #include "persist_lua.h" #include "iso_fs.h" +#include +#include // Config file checking #ifndef CORSIX_TH_USE_PACK_PRAGMAS @@ -40,13 +39,13 @@ #endif // End of config file checking -int CorsixTH_lua_main_no_eval(lua_State *L) +int lua_main_no_eval(lua_State *L) { // assert(_VERSION == LUA_VERSION) size_t iLength; lua_getglobal(L, "_VERSION"); const char* sVersion = lua_tolstring(L, -1, &iLength); - if(iLength != strlen(LUA_VERSION) || strcmp(sVersion, LUA_VERSION) != 0) + if(iLength != std::strlen(LUA_VERSION) || std::strcmp(sVersion, LUA_VERSION) != 0) { lua_pushliteral(L, "Linked against a version of Lua different to the " "one used when compiling.\nPlease recompile CorsixTH against the " @@ -55,64 +54,13 @@ } lua_pop(L, 1); - // registry._CLEANUP = {} - lua_newtable(L); - lua_setfield(L, LUA_REGISTRYINDEX, "_CLEANUP"); - // math.random* = Mersenne twister variant - luaT_cpcall(L, luaopen_random, NULL); - - // package.preload["jit.opt"] = load(jit_opt_lua) - // package.preload["jit.opt_inline"] = load(jit_opt_inline_lua) - lua_getglobal(L, "package"); - lua_getfield(L, -1, "preload"); - luaL_loadbuffer(L, (const char*)jit_opt_lua, sizeof(jit_opt_lua), - "jit/opt.luac"); - lua_setfield(L, -2, "jit.opt"); - luaL_loadbuffer(L, (const char*)jit_opt_inline_lua, - sizeof(jit_opt_inline_lua), "jit/opt_inline.luac"); - lua_setfield(L, -2, "jit.opt_inline"); - lua_pop(L, 2); - - // if registry._LOADED.jit then - // require"jit.opt".start() - // else - // print "Notice: ..." - // end - // (this could be done in Lua rather than here, but ideally the optimiser - // should be turned on before any Lua code is loaded) - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, -1, "jit"); - if(lua_type(L, -1) == LUA_TNIL) - { - lua_pop(L, 2); - lua_getglobal(L, "print"); - lua_pushliteral(L, "Notice: LuaJIT not being used.\nConsider replacing" - " Lua with LuaJIT to improve performance."); -#ifdef CORSIX_TH_64BIT - lua_pushliteral(L, " Note that there is not currently a 64 bit version" - " of LuaJIT."); - lua_concat(L, 2); -#endif - lua_call(L, 1, 0); - } - else - { - lua_pop(L, 2); - lua_getglobal(L, "require"); - lua_pushliteral(L, "jit.opt"); - lua_call(L, 1, 1); - lua_getfield(L, -1, "start"); - lua_call(L, 0, 0); - lua_pop(L, 1); - } + luaT_cpcall(L, luaopen_random, nullptr); // Fill in package.preload table so that calls to require("X") from Lua // will call the appropriate luaopen_X function in C. #define PRELOAD(name, fn) \ luaT_execute(L, "package.preload." name " = ...", fn) - PRELOAD("lfs", luaopen_lfs_ext); - PRELOAD("lpeg", luaopen_lpeg); PRELOAD("rnc", luaopen_rnc); PRELOAD("TH", luaopen_th); PRELOAD("ISO_FS", luaopen_iso_fs); @@ -132,7 +80,7 @@ { size_t iLen; const char* sCmd = lua_tolstring(L, i, &iLen); - if(iLen > 14 && memcmp(sCmd, "--interpreter=", 14) == 0) + if(iLen > 14 && std::memcmp(sCmd, "--interpreter=", 14) == 0) { lua_getglobal(L, "assert"); lua_getglobal(L, "loadfile"); @@ -143,62 +91,27 @@ } } - // Code to try several variations on finding CorsixTH.lua: - // CorsixTH.lua - // CorsixTH/CorsixTH.lua - // ../CorsixTH.lua - // ../CorsixTH/CorsixTH.lua - // ../../CorsixTH.lua - // ../../CorsixTH/CorsixTH.lua - // ../../../CorsixTH.lua - // ../../../CorsixTH/CorsixTH.lua - // It is simpler to write this in Lua than in C. - const char sLuaCorsixTHLua[] = - "local name, sep, code = \"CorsixTH.lua\", package.config:sub(1, 1)\n" - "local root = (... or \"\"):match(\"^(.*[\"..sep..\"])\") or \"\"\n" -#ifdef __APPLE__ // Darrell: Search inside the bundle first. - // There's probably a better way of doing this. -#if defined(IS_CORSIXTH_APP) - "code = loadfile(\"CorsixTH.app/Contents/Resources/\"..name)\n" - "if code then return code end\n" -#elif defined(IS_MAPEDIT_APP) - "code = loadfile(\"MapEdit.app/Contents/Resources/\"..name)\n" - "if code then return code end\n" -#endif -#endif - "for num_dotdot = 0, 3 do\n" - " for num_dir = 0, 1 do\n" - " code = loadfile(root..(\"..\"..sep):rep(num_dotdot)..\n" - " (\"CorsixTH\"..sep):rep(num_dir)..name)\n" - " if code then return code end \n" - " end \n" - "end \n" - "return loadfile(name)"; - - // return assert(loadfile"CorsixTH.lua")(...) if(!bGotScriptFile) { lua_getglobal(L, "assert"); - luaL_loadbuffer(L, sLuaCorsixTHLua, strlen(sLuaCorsixTHLua), - "@main.cpp (l_main bootstrap)"); - if(lua_gettop(L) == 2) - lua_pushnil(L); - else - lua_pushvalue(L, 1); + lua_getglobal(L, "loadfile"); + lua_pushstring(L, CORSIX_TH_INTERPRETER_PATH); + bGotScriptFile = true; } + lua_call(L, 1, 2); lua_call(L, 2, 1); lua_insert(L, 1); return lua_gettop(L); } -int CorsixTH_lua_main(lua_State *L) +int lua_main(lua_State *L) { - lua_call(L, CorsixTH_lua_main_no_eval(L) - 1, LUA_MULTRET); + lua_call(L, lua_main_no_eval(L) - 1, LUA_MULTRET); return lua_gettop(L); } -int CorsixTH_lua_stacktrace(lua_State *L) +int lua_stacktrace(lua_State *L) { // err = tostring(err) lua_settop(L, 1); @@ -207,7 +120,7 @@ lua_call(L, 1, 1); // err = .. err - lua_pushliteral(L, "An error has occured in CorsixTH:\n"); + lua_pushliteral(L, "An error has occurred in CorsixTH:\n"); lua_insert(L, 1); lua_concat(L, 2); @@ -221,17 +134,17 @@ return 1; } -int CorsixTH_lua_panic(lua_State *L) +int lua_panic(lua_State *L) { - fprintf(stderr, "A Lua error has occured in CorsixTH outside of protected " + std::fprintf(stderr, "A Lua error has occurred in CorsixTH outside of protected " "mode!!\n"); - fflush(stderr); + std::fflush(stderr); if(lua_type(L, -1) == LUA_TSTRING) - fprintf(stderr, "%s\n", lua_tostring(L, -1)); + std::fprintf(stderr, "%s\n", lua_tostring(L, -1)); else - fprintf(stderr, "%p\n", lua_topointer(L, -1)); - fflush(stderr); + std::fprintf(stderr, "%p\n", lua_topointer(L, -1)); + std::fflush(stderr); // A stack trace would be nice, but they cannot be done in a panic. diff -Nru corsix-th-0.30/CorsixTH/Src/main.h corsix-th-0.62/CorsixTH/Src/main.h --- corsix-th-0.30/CorsixTH/Src/main.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/main.h 2018-07-21 11:13:17.000000000 +0000 @@ -23,6 +23,9 @@ #ifndef CORSIX_TH_MAIN_H_ #define CORSIX_TH_MAIN_H_ #include "lua.hpp" +#ifdef CORSIX_TH_USE_VLD +#include +#endif //! Lua mode entry point /*! @@ -30,14 +33,14 @@ transfers control to CorsixTH.lua as soon as possible (so that as little as possible behaviour is hardcoded into C rather than Lua). */ -int CorsixTH_lua_main(lua_State *L); +int lua_main(lua_State *L); //! Alternative lua mode entry point /*! Behaves like CorsixTH_lua_main, except that it doesn't transfer control over to Lua scripts - it just prepares everything for them and loads them. */ -int CorsixTH_lua_main_no_eval(lua_State *L); +int lua_main_no_eval(lua_State *L); //! Process a caught error before returning it to the caller /*! @@ -46,7 +49,7 @@ processing the error, the caller receives LUA_ERRERR rather than panicking while processing it itself. */ -int CorsixTH_lua_stacktrace(lua_State *L); +int lua_stacktrace(lua_State *L); //! Process an uncaught Lua error before aborting /*! @@ -54,6 +57,6 @@ which can be done when they do, but at least the user should be informed, and the error message printed. */ -int CorsixTH_lua_panic(lua_State *L); +int lua_panic(lua_State *L); #endif // CORSIX_TH_MAIN_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/persist_lua.cpp corsix-th-0.62/CorsixTH/Src/persist_lua.cpp --- corsix-th-0.30/CorsixTH/Src/persist_lua.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/persist_lua.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -21,14 +21,18 @@ */ #include "persist_lua.h" -#include +#include #include -#include +#include +#include +#include +#include +#include #ifdef _MSC_VER -#pragma warning(disable: 4996) // Disable "strcpy unsafe" warnings under MSVC +#pragma warning(disable: 4996) // Disable "std::strcpy unsafe" warnings under MSVC #endif -enum PersistTypes +enum persist_type { // LUA_TNIL = 0, // LUA_TBOOLEAN, // Used for false @@ -49,9 +53,6 @@ PERSIST_TCOUNT, // must equal 16 (for compatibility) }; -LuaPersistWriter::~LuaPersistWriter() {} -LuaPersistReader::~LuaPersistReader() {} - static int l_writer_mt_index(lua_State *L); template static int l_crude_gc(lua_State *L) @@ -69,27 +70,28 @@ can be more efficient to use this structure, which can load them without concatenating them. Sample usage is: - LoadMultiBuffer_t ls; + load_multi_buffer ls; ls.s[0] = lua_tolstring(L, -2, &ls.i[0]); ls.s[1] = lua_tolstring(L, -1, &ls.i[1]); lua_load(L, LoadMultiBuffer_t::load_fn, &ls, "chunk name"); */ -struct LoadMultiBuffer_t +class load_multi_buffer { +public: const char *s[3]; size_t i[3]; int n; - LoadMultiBuffer_t() + load_multi_buffer() { - s[0] = s[1] = s[2] = NULL; + s[0] = s[1] = s[2] = nullptr; i[0] = i[1] = i[2] = 0; n = 0; } static const char* load_fn(lua_State *L, void *ud, size_t *size) { - LoadMultiBuffer_t *pThis = reinterpret_cast(ud); + load_multi_buffer *pThis = reinterpret_cast(ud); for( ; pThis->n < 3; ++pThis->n) { @@ -101,15 +103,15 @@ } *size = 0; - return NULL; + return nullptr; } }; //! Basic implementation of persistance interface /*! - self - Instance of LuaPersistBasicWriter allocated as a Lua userdata + self - Instance of lua_persist_basic_writer allocated as a Lua userdata self metatable: - __gc - ~LuaPersistBasicWriter (via l_crude_gc) + __gc - ~lua_persist_basic_writer (via l_crude_gc) ":" - [1] - pre-populated prototype persistance names ":" - "" @@ -122,76 +124,69 @@ upvalue 1 - permanents table upvalue 2 - self */ -class LuaPersistBasicWriter : public LuaPersistWriter +class lua_persist_basic_writer : public lua_persist_writer { public: - LuaPersistBasicWriter(lua_State *L) - : m_L(L) - { - m_iDataBufferLength = 1024; - m_pData = (uint8_t*)malloc(m_iDataBufferLength); - } + lua_persist_basic_writer(lua_State *L) + : L(L), + data() + { } - ~LuaPersistBasicWriter() - { - free(m_pData); - } + ~lua_persist_basic_writer() + { } - virtual lua_State* getStack() + lua_State* get_stack() override { - return m_L; + return L; } void init() { - lua_State *L = m_L; lua_createtable(L, 1, 8); // Environment lua_pushvalue(L, 2); // Permanent objects lua_rawseti(L, -2, 1); lua_createtable(L, 1, 0); // Environment metatable lua_pushvalue(L, 2); // Permanent objects lua_pushvalue(L, 1); // self - lua_pushcclosure(L, l_writer_mt_index, 2); + luaT_pushcclosure(L, l_writer_mt_index, 2); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); lua_setfenv(L, 1); lua_createtable(L, 1, 4); // Metatable - lua_pushcclosure(L, l_crude_gc, 0); + luaT_pushcclosure(L, l_crude_gc, 0); lua_setfield(L, -2, "__gc"); lua_pushvalue(L, luaT_upvalueindex(1)); // Prototype persistance names lua_rawseti(L, -2, 1); lua_setmetatable(L, 1); - m_iNextIndex = 1; - m_iDataLength = 0; - m_bHadError = false; + next_index = 1; + data_size = 0; + had_error = false; } int finish() { - if(getError() != NULL) + if(get_error() != nullptr) { - lua_pushnil(m_L); - lua_pushstring(m_L, getError()); - lua_getmetatable(m_L, 1); - lua_getfield(m_L, -1, "err"); - lua_replace(m_L, -2); + lua_pushnil(L); + lua_pushstring(L, get_error()); + lua_getmetatable(L, 1); + lua_getfield(L, -1, "err"); + lua_replace(L, -2); return 3; } else { - lua_pushlstring(m_L, (const char*)m_pData, m_iDataLength); + lua_pushlstring(L, data.c_str(), data.length()); return 1; } } - virtual void fastWriteStackObject(int iIndex) + void fast_write_stack_object(int iIndex) override { - lua_State *L = m_L; - if(lua_type(L, iIndex) != LUA_TUSERDATA) { - writeStackObject(iIndex); + write_stack_object(iIndex); return; } @@ -210,25 +205,25 @@ if(!lua_isnil(L, -1) || !lua_isnil(L, -2)) { lua_pop(L, 3); - writeStackObject(iIndex); + write_stack_object(iIndex); return; } lua_pop(L, 2); // Save the index to the cache lua_pushvalue(L, iIndex); - lua_pushnumber(L, (lua_Number)(m_iNextIndex++)); + lua_pushnumber(L, (lua_Number)(next_index++)); lua_settable(L, -3); - if(!_checkThatUserdataCanBeDepersisted(iIndex)) + if(!check_that_userdata_can_be_depersisted(iIndex)) return; // Write type, metatable, and then environment uint8_t iType = LUA_TUSERDATA; - writeByteStream(&iType, 1); - writeStackObject(-1); + write_byte_stream(&iType, 1); + write_stack_object(-1); lua_getfenv(L, iIndex); - writeStackObject(-1); + write_stack_object(-1); lua_pop(L, 1); // Write the raw data @@ -246,14 +241,12 @@ lua_pop(L, 2); } } - writeVUInt((uint64_t)0x42); // sync marker + write_uint((uint64_t)0x42); // sync marker lua_pop(L, 1); } - virtual void writeStackObject(int iIndex) + void write_stack_object(int iIndex) override { - lua_State *L = m_L; - // Convert index from relative to absolute if(iIndex < 0 && iIndex > LUA_REGISTRYINDEX) iIndex = lua_gettop(L) + 1 + iIndex; @@ -263,7 +256,7 @@ if(iType == LUA_TNIL || iType == LUA_TNONE) { uint8_t iByte = LUA_TNIL; - writeByteStream(&iByte, 1); + write_byte_stream(&iByte, 1); } else if(iType == LUA_TBOOLEAN) { @@ -272,7 +265,7 @@ iByte = PERSIST_TTRUE; else iByte = LUA_TBOOLEAN; - writeByteStream(&iByte, 1); + write_byte_stream(&iByte, 1); } else if(iType == LUA_TNUMBER) { @@ -283,16 +276,16 @@ // NB: 16383 = 2^14-1, which is the maximum value which // can fit into two bytes of VUInt. uint8_t iByte = PERSIST_TINTEGER; - writeByteStream(&iByte, 1); + write_byte_stream(&iByte, 1); uint16_t iValue = (uint16_t)fValue; - writeVUInt(iValue); + write_uint(iValue); } else { // Other numbers are written as an 8 byte double uint8_t iByte = LUA_TNUMBER; - writeByteStream(&iByte, 1); - writeByteStream(reinterpret_cast(&fValue), sizeof(double)); + write_byte_stream(&iByte, 1); + write_byte_stream(reinterpret_cast(&fValue), sizeof(double)); } } else @@ -310,19 +303,18 @@ // would have been called, and the appropriate data written, and 0 // would be returned. Otherwise, the index would be returned, which // we offset by the number of types, and then write. - writeVUInt(iValue + PERSIST_TCOUNT - 1); + write_uint(iValue + PERSIST_TCOUNT - 1); } } } - int writeObjectRaw() + int write_object_raw() { - lua_State *L = m_L; uint8_t iType; // Save the index to the cache lua_pushvalue(L, 2); - lua_pushnumber(L, (lua_Number)(m_iNextIndex++)); + lua_pushnumber(L, (lua_Number)(next_index++)); lua_settable(L, 1); // Lookup the object in the permanents table @@ -333,14 +325,14 @@ // Object is in the permanents table. uint8_t iType = PERSIST_TPERMANENT; - writeByteStream(&iType, 1); + write_byte_stream(&iType, 1); // Replace self's environment with self (for call to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Write the key corresponding to the permanent object - writeStackObject(-1); + write_stack_object(-1); } else { @@ -355,12 +347,12 @@ case LUA_TSTRING: { iType = LUA_TSTRING; - writeByteStream(&iType, 1); + write_byte_stream(&iType, 1); // Strings are simple: length and then bytes (not null terminated) size_t iLength; const char *sString = lua_tolstring(L, 2, &iLength); - writeVUInt(iLength); - writeByteStream(reinterpret_cast(sString), iLength); + write_uint(iLength); + write_byte_stream(reinterpret_cast(sString), iLength); break; } case LUA_TTABLE: { @@ -378,24 +370,24 @@ if(lua_getmetatable(L, iTable)) { iType = PERSIST_TTABLE_WITH_META; - writeByteStream(&iType, 1); - writeStackObject(-1); + write_byte_stream(&iType, 1); + write_stack_object(-1); lua_pop(L, 1); } else { iType = LUA_TTABLE; - writeByteStream(&iType, 1); + write_byte_stream(&iType, 1); } // Write the children as key, value pairs lua_pushnil(L); while(lua_next(L, iTable)) { - writeStackObject(-2); + write_stack_object(-2); // The naive thing to do now would be writeStackObject(-1) // but this can easily lead to Lua's C call stack limit - // being hit. To reduce the likelyhood of this happening, + // being hit. To reduce the likelihood of this happening, // we check to see if about to write another table. if(lua_type(L, -1) == LUA_TTABLE) { @@ -409,7 +401,7 @@ lua_checkstack(L, 10); iTable += 2; lua_pushvalue(L, iTable); - lua_pushnumber(L, (lua_Number)(m_iNextIndex++)); + lua_pushnumber(L, (lua_Number)(next_index++)); lua_settable(L, 2); goto table_reentry; table_resume: iTable -= 2; @@ -417,18 +409,18 @@ else { lua_pop(L, 2); - writeStackObject(-1); + write_stack_object(-1); } } else - writeStackObject(-1); + write_stack_object(-1); lua_pop(L, 1); } // Write a nil to mark the end of the children (as nil is the // only value which cannot be used as a key in a table). iType = LUA_TNIL; - writeByteStream(&iType, 1); + write_byte_stream(&iType, 1); if(iTable != 3) goto table_resume; break; } @@ -436,13 +428,13 @@ case LUA_TFUNCTION: if(lua_iscfunction(L, 2)) { - setErrorObject(2); - setError("Cannot persist C functions"); + set_error_object(2); + set_error("Cannot persist C functions"); } else { iType = LUA_TFUNCTION; - writeByteStream(&iType, 1); + write_byte_stream(&iType, 1); // Replace self's environment with self (for calls to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); @@ -453,37 +445,37 @@ lua_Debug proto_info; lua_pushvalue(L, 2); lua_getinfo(L, ">Su", &proto_info); - writePrototype(&proto_info, 2); + write_prototype(&proto_info, 2); // Write the values of the upvalues // If available, also write the upvalue IDs (so that in // the future, we could hypothetically rejoin shared // upvalues). An ID is just an opaque sequence of bytes. - writeVUInt(proto_info.nups); + write_uint(proto_info.nups); #if LUA_VERSION_NUM >= 502 - writeVUInt(sizeof(void*)); + write_uint(sizeof(void*)); #else - writeVUInt(0); + write_uint(0); #endif for(int i = 1; i <= proto_info.nups; ++i) { lua_getupvalue(L, 2, i); - writeStackObject(-1); + write_stack_object(-1); #if LUA_VERSION_NUM >= 502 void *pUpvalueID = lua_upvalueid(L, 2, i); - writeByteStream((uint8_t*)&pUpvalueID, sizeof(void*)); + write_byte_stream((uint8_t*)&pUpvalueID, sizeof(void*)); #endif } // Write the environment table lua_getfenv(L, 2); - writeStackObject(-1); + write_stack_object(-1); lua_pop(L, 1); } break; case LUA_TUSERDATA: - if(!_checkThatUserdataCanBeDepersisted(2)) + if(!check_that_userdata_can_be_depersisted(2)) break; // Replace self's environment with self (for calls to writeStackObject) @@ -492,10 +484,10 @@ // Write type, metatable, and then environment iType = LUA_TUSERDATA; - writeByteStream(&iType, 1); - writeStackObject(-1); + write_byte_stream(&iType, 1); + write_stack_object(-1); lua_getfenv(L, 2); - writeStackObject(-1); + write_stack_object(-1); lua_pop(L, 1); // Write the raw data @@ -511,11 +503,11 @@ lua_call(L, 2, 0); } } - writeVUInt((uint64_t)0x42); // sync marker + write_uint((uint64_t)0x42); // sync marker break; default: - setError(lua_pushfstring(L, "Cannot persist %s values", luaL_typename(L, 2))); + set_error(lua_pushfstring(L, "Cannot persist %s values", luaL_typename(L, 2))); break; } } @@ -523,10 +515,8 @@ return 1; } - bool _checkThatUserdataCanBeDepersisted(int iIndex) + bool check_that_userdata_can_be_depersisted(int iIndex) { - lua_State *L = m_L; - if(lua_getmetatable(L, iIndex)) { lua_getfield(L, -1, "__depersist_size"); @@ -535,7 +525,7 @@ if(static_cast(lua_tointeger(L, -1)) != static_cast(lua_objlen(L, iIndex))) { - setError(lua_pushfstring(L, "__depersist_size is " + set_error(lua_pushfstring(L, "__depersist_size is " "incorrect (%d vs. %d)", (int)lua_objlen(L, iIndex), (int)lua_tointeger(L, -1))); return false; @@ -546,7 +536,7 @@ lua_getfield(L, -3, "__depersist"); if(lua_isnil(L, -1) || lua_isnil(L, -2)) { - setError("Can only persist non-empty userdata" + set_error("Can only persist non-empty userdata" " if they have __persist and __depersist " "metamethods"); return false; @@ -558,7 +548,7 @@ { if(lua_objlen(L, iIndex) != 0) { - setError("Can only persist non-empty userdata if " + set_error("Can only persist non-empty userdata if " "they have a __depersist_size metafield"); return false; } @@ -569,7 +559,7 @@ { if(lua_objlen(L, iIndex) != 0) { - setError("Can only persist userdata without a metatable" + set_error("Can only persist userdata without a metatable" " if their size is zero"); return false; } @@ -578,26 +568,24 @@ return true; } - void writePrototype(lua_Debug *pProtoInfo, int iInstanceIndex) + void write_prototype(lua_Debug *pProtoInfo, int iInstanceIndex) { - lua_State *L = m_L; - // Sanity checks if(pProtoInfo->source[0] != '@') { // @ denotes that the source was a file // (http://www.lua.org/manual/5.1/manual.html#lua_Debug) - setError("Can only persist Lua functions defined in source files"); + set_error("Can only persist Lua functions defined in source files"); return; } - if(strcmp(pProtoInfo->what, "Lua") != 0) + if(std::strcmp(pProtoInfo->what, "Lua") != 0) { // what == "C" should have been caught by writeObjectRaw(). // what == "tail" should be impossible. // Hence "Lua" and "main" should be the only values seen. // NB: Chunks are not functions defined *in* source files, because // chunks *are* source files. - setError(lua_pushfstring(L, "Cannot persist entire Lua chunks (%s)", pProtoInfo->source + 1)); + set_error(lua_pushfstring(L, "Cannot persist entire Lua chunks (%s)", pProtoInfo->source + 1)); lua_pop(L, 1); return; } @@ -612,23 +600,23 @@ { uint64_t iValue = (uint64_t)lua_tonumber(L, -1); lua_pop(L, 3); - writeVUInt(iValue + PERSIST_TCOUNT - 1); + write_uint(iValue + PERSIST_TCOUNT - 1); return; } lua_pop(L, 1); lua_pushvalue(L, -1); - lua_pushnumber(L, (lua_Number)m_iNextIndex++); + lua_pushnumber(L, (lua_Number)next_index++); lua_rawset(L, -4); uint8_t iType = PERSIST_TPROTOTYPE; - writeByteStream(&iType, 1); + write_byte_stream(&iType, 1); // Write upvalue names - writeVUInt(pProtoInfo->nups); + write_uint(pProtoInfo->nups); for(int i = 1; i <= pProtoInfo->nups; ++i) { lua_pushstring(L, lua_getupvalue(L, iInstanceIndex, i)); - writeStackObject(-1); + write_stack_object(-1); lua_pop(L, 2); } @@ -638,53 +626,44 @@ lua_rawget(L, -2); if(lua_isnil(L, -1)) { - setError(lua_pushfstring(L, "Lua functions must be given a unique " + set_error(lua_pushfstring(L, "Lua functions must be given a unique " "persistable name in order to be persisted (attempt to persist" " %s:%d)", pProtoInfo->source + 1, pProtoInfo->linedefined)); lua_pop(L, 2); return; } - writeStackObject(-1); + write_stack_object(-1); lua_pop(L, 2); } - virtual void writeByteStream(const uint8_t *pBytes, size_t iCount) + void write_byte_stream(const uint8_t *pBytes, size_t iCount) override { - if(m_bHadError) + if(had_error) { - // If an error occured, then silently fail to write any + // If an error occurred, then silently fail to write any // data. return; } - while(m_iDataLength + iCount > m_iDataBufferLength) - { - m_iDataBufferLength *= 2; - m_pData = (uint8_t*)realloc(m_pData, m_iDataBufferLength); - } - memcpy(m_pData + m_iDataLength, pBytes, iCount); - m_iDataLength += iCount; + data.append(reinterpret_cast(pBytes), iCount); } - virtual void setError(const char *sError) + void set_error(const char *sError) override { // If multiple errors occur, only record the first. - if(m_bHadError) + if (had_error) { return; - m_bHadError = true; + } + had_error = true; // Use the written data buffer to store the error message - m_iDataLength = strlen(sError) + 1; - if(m_iDataBufferLength < m_iDataLength) - m_pData = (uint8_t*)realloc(m_pData, m_iDataBufferLength); - strcpy((char*)m_pData, sError); + data.assign(sError); } - void setErrorObject(int iStackObject) + void set_error_object(int iStackObject) { - if(m_bHadError) + if(had_error) return; - lua_State *L = m_L; lua_pushvalue(L, iStackObject); lua_getmetatable(L, luaT_upvalueindex(2)); @@ -693,32 +672,31 @@ lua_pop(L, 1); } - const char* getError() + const char* get_error() { - if(m_bHadError) - return reinterpret_cast(m_pData); + if(had_error) + return data.c_str(); else - return NULL; + return nullptr; } -protected: - lua_State *m_L; - uint64_t m_iNextIndex; - uint8_t* m_pData; - size_t m_iDataLength; - size_t m_iDataBufferLength; - bool m_bHadError; +private: + lua_State *L; + uint64_t next_index; + std::string data; + size_t data_size; + bool had_error; }; static int l_writer_mt_index(lua_State *L) { - return reinterpret_cast( - lua_touserdata(L, luaT_upvalueindex(2)))->writeObjectRaw(); + return reinterpret_cast( + lua_touserdata(L, luaT_upvalueindex(2)))->write_object_raw(); } //! Basic implementation of depersistance interface /*! - self - Instance of LuaPersistBasicReader allocated as a Lua userdata + self - Instance of lua_persist_basic_reader allocated as a Lua userdata self environment: [-3] - self [-2] - pre-populated prototype persistance code @@ -728,48 +706,37 @@ [ 0] - permanents table - self metatable: - __gc - ~LuaPersistBasicReader (via l_crude_gc) + __gc - ~lua_persist_basic_reader (via l_crude_gc) - */ -class LuaPersistBasicReader : public LuaPersistReader +class lua_persist_basic_reader : public lua_persist_reader { public: - LuaPersistBasicReader(lua_State *L) - : m_L(L) - { - m_iStringBufferLength = 32; - m_sStringBuffer = (char*)malloc(m_iStringBufferLength); - } + lua_persist_basic_reader(lua_State *L) + : L(L), + string_buffer() + { } - ~LuaPersistBasicReader() - { - free(m_sStringBuffer); - } + ~lua_persist_basic_reader() + { } - virtual lua_State* getStack() + lua_State* get_stack() override { - return m_L; + return L; } - virtual void setError(const char *sError) + void set_error(const char *sError) override { - m_bHadError = true; - size_t iErrLength = strlen(sError) + 1; - if(iErrLength > m_iStringBufferLength) - { - m_sStringBuffer = (char*)realloc(m_sStringBuffer, iErrLength); - m_iStringBufferLength = iErrLength; - } - strcpy(m_sStringBuffer, sError); + had_error = true; + string_buffer.assign(sError); } void init(const uint8_t *pData, size_t iLength) { - lua_State *L = m_L; - m_pData = pData; - m_iDataBufferLength = iLength; - m_iNextIndex = 1; - m_bHadError = false; + data = pData; + data_buffer_size = iLength; + next_index = 1; + had_error = false; lua_createtable(L, 32, 0); // Environment lua_pushvalue(L, 2); lua_rawseti(L, -2, 0); @@ -781,20 +748,19 @@ lua_rawseti(L, -2, -3); lua_setfenv(L, 1); lua_createtable(L, 0, 1); // Metatable - lua_pushcclosure(L, l_crude_gc, 0); + luaT_pushcclosure(L, l_crude_gc, 0); lua_setfield(L, -2, "__gc"); lua_setmetatable(L, 1); } - virtual bool readStackObject() + bool read_stack_object() override { uint64_t iIndex; - if(!readVUInt(iIndex)) + if(!read_uint(iIndex)) { - setError("Expected stack object"); + set_error("Expected stack object"); return false; } - lua_State *L = m_L; if(lua_type(L, 1) != LUA_TTABLE) { // Ensure that index #1 is self environment @@ -813,7 +779,7 @@ } if(lua_isnil(L, -1)) { - setError("Cycle while depersisting permanent object key or userdata metatable"); + set_error("Cycle while depersisting permanent object key or userdata metatable"); return false; } } @@ -826,18 +792,18 @@ lua_pushnil(L); break; case PERSIST_TPERMANENT: { - uint64_t iOldIndex = m_iNextIndex; - ++m_iNextIndex; // Temporary marker + uint64_t iOldIndex = next_index; + ++next_index; // Temporary marker lua_rawgeti(L, 1, 0); // Permanents table - if(!readStackObject()) + if(!read_stack_object()) return false; lua_gettable(L, -2); lua_replace(L, -2); // Replace marker with actual object - uint64_t iNewIndex = m_iNextIndex; - m_iNextIndex = iOldIndex; - saveStackObject(); - m_iNextIndex = iNewIndex; + uint64_t iNewIndex = next_index; + next_index = iOldIndex; + save_stack_object(); + next_index = iNewIndex; break; } case LUA_TBOOLEAN: lua_pushboolean(L, 0); @@ -847,86 +813,82 @@ break; case LUA_TSTRING: { size_t iLength; - if(!readVUInt(iLength)) + if(!read_uint(iLength)) return false; - while(iLength > m_iStringBufferLength) - { - m_iStringBufferLength *= 2; - m_sStringBuffer = (char*)realloc(m_sStringBuffer, m_iStringBufferLength); - } - if(!readByteStream((uint8_t*)m_sStringBuffer, iLength)) + if(!read_byte_stream(string_buffer, iLength)) return false; - lua_pushlstring(L, m_sStringBuffer, iLength); - saveStackObject(); + lua_pushlstring(L, string_buffer.c_str(), string_buffer.length()); + save_stack_object(); break; } case LUA_TTABLE: lua_newtable(L); - saveStackObject(); + save_stack_object(); if(!lua_checkstack(L, 8)) return false; - if(!readTableContents()) + if(!read_table_contents()) return false; break; case PERSIST_TTABLE_WITH_META: lua_newtable(L); - saveStackObject(); + save_stack_object(); if(!lua_checkstack(L, 8)) return false; - if(!readStackObject()) + if(!read_stack_object()) return false; lua_setmetatable(L, -2); - if(!readTableContents()) + if(!read_table_contents()) return false; break; case LUA_TNUMBER: { double fValue; - if(!readByteStream(reinterpret_cast(&fValue), sizeof(double))) + if(!read_byte_stream(reinterpret_cast(&fValue), sizeof(double))) return false; lua_pushnumber(L, fValue); break; } case LUA_TFUNCTION: { if(!lua_checkstack(L, 8)) return false; - uint64_t iOldIndex = m_iNextIndex; - ++m_iNextIndex; // Temporary marker - if(!readStackObject()) + uint64_t iOldIndex = next_index; + ++next_index; // Temporary marker + if(!read_stack_object()) return false; lua_call(L, 0, 2); // Replace marker with closure - uint64_t iNewIndex = m_iNextIndex; - m_iNextIndex = iOldIndex; - saveStackObject(); - m_iNextIndex = iNewIndex; + uint64_t iNewIndex = next_index; + next_index = iOldIndex; + save_stack_object(); + next_index = iNewIndex; // Set upvalues lua_insert(L, -2); int iNups, i; - if(!readVUInt(iNups)) + if(!read_uint(iNups)) return false; size_t iIDSize; - if(!readVUInt(iIDSize)) + if(!read_uint(iIDSize)) return false; for(i = 0; i < iNups; ++i) { - if(!readStackObject()) + if(!read_stack_object()) return false; // For now, just skip over the upvalue IDs. In the future, // the ID may be used to rejoin shared upvalues. - if(!readByteStream(NULL, iIDSize)) + if(!read_byte_stream(nullptr, iIDSize)) return false; } lua_call(L, iNups, 0); // Read environment - if(!readStackObject()) + if(!read_stack_object()) return false; lua_setfenv(L, -2); break; } case PERSIST_TPROTOTYPE: { if(!lua_checkstack(L, 8)) return false; - uint64_t iOldIndex = m_iNextIndex; - ++m_iNextIndex; // Temporary marker + + uint64_t iOldIndex = next_index; + ++next_index; // Temporary marker int iNups; - if(!readVUInt(iNups)) + if(!read_uint(iNups)) return false; if(iNups == 0) lua_pushliteral(L, "return function() end,"); @@ -938,11 +900,11 @@ { if(i != 0) lua_pushliteral(L, ","); - if(!readStackObject()) + if(!read_stack_object()) return false; if(lua_type(L, -1) != LUA_TSTRING) { - setError("Upvalue name not a string"); + set_error("Upvalue name not a string"); return false; } } @@ -953,30 +915,33 @@ lua_concat(L, 5); } // Fetch name and then lookup filename and code - if(!readStackObject()) + if(!read_stack_object()) return false; lua_pushliteral(L, "@"); + lua_rawgeti(L, 1, -1); lua_pushvalue(L, -3); lua_gettable(L, -2); lua_replace(L, -2); + if(lua_isnil(L, -1)) { - setError(lua_pushfstring(L, "Unable to depersist prototype" + set_error(lua_pushfstring(L, "Unable to depersist prototype" " \'%s\'", lua_tostring(L, -3))); return false; } lua_concat(L, 2); // Prepend the @ to the filename lua_rawgeti(L, 1, -2); lua_pushvalue(L, -3); + lua_gettable(L, -2); lua_replace(L, -2); lua_remove(L, -3); // Construct the closure factory - LoadMultiBuffer_t ls; + load_multi_buffer ls; ls.s[0] = lua_tolstring(L, -3, &ls.i[0]); ls.s[1] = lua_tolstring(L, -1, &ls.i[1]); - if(lua_load(L, LoadMultiBuffer_t::load_fn, &ls, lua_tostring(L, -2)) != 0) + if(luaT_load(L, load_multi_buffer::load_fn, &ls, lua_tostring(L, -2), "bt") != 0) { // Should never happen lua_error(L); @@ -985,31 +950,31 @@ lua_replace(L, -4); lua_pop(L, 2); // Replace marker with closure factory - uint64_t iNewIndex = m_iNextIndex; - m_iNextIndex = iOldIndex; - saveStackObject(); - m_iNextIndex = iNewIndex; + uint64_t iNewIndex = next_index; + next_index = iOldIndex; + save_stack_object(); + next_index = iNewIndex; break; } case LUA_TUSERDATA: { bool bHasSetMetatable = false; - uint64_t iOldIndex = m_iNextIndex; - ++m_iNextIndex; // Temporary marker + uint64_t iOldIndex = next_index; + ++next_index; // Temporary marker // Read metatable - if(!readStackObject()) + if(!read_stack_object()) return false; lua_getfield(L, -1, "__depersist_size"); if(!lua_isnumber(L, -1)) { - setError("Userdata missing __depersist_size metafield"); + set_error("Userdata missing __depersist_size metafield"); return false; } lua_newuserdata(L, (size_t)lua_tonumber(L, -1)); lua_replace(L, -2); // Replace marker with userdata - uint64_t iNewIndex = m_iNextIndex; - m_iNextIndex = iOldIndex; - saveStackObject(); - m_iNextIndex = iNewIndex; + uint64_t iNewIndex = next_index; + next_index = iOldIndex; + save_stack_object(); + next_index = iNewIndex; // Perform immediate initialisation lua_getfield(L, -2, "__pre_depersist"); if(lua_isnil(L, -1)) @@ -1029,7 +994,7 @@ lua_call(L, 1, 0); } // Read environment - if(!readStackObject()) + if(!read_stack_object()) return false; lua_setfenv(L, -2); // Set metatable and read the raw data @@ -1059,17 +1024,17 @@ } lua_replace(L, -2); uint64_t iSyncMarker; - if(!readVUInt(iSyncMarker)) + if(!read_uint(iSyncMarker)) return false; if(iSyncMarker != 0x42) { - setError("sync fail"); + set_error("sync fail"); return false; } break; } case PERSIST_TINTEGER: { uint16_t iValue; - if(!readVUInt(iValue)) + if(!read_uint(iValue)) return false; lua_pushinteger(L, iValue); break; } @@ -1099,7 +1064,7 @@ } lua_pushliteral(L, "\'"); lua_concat(L, 3); - setError(lua_tostring(L, -1)); + set_error(lua_tostring(L, -1)); lua_pop(L, 1); return false; } @@ -1107,36 +1072,34 @@ return true; } - void saveStackObject() + void save_stack_object() { - lua_State *L = m_L; - if(m_iNextIndex < (uint64_t)INT_MAX) + if(next_index < (uint64_t)INT_MAX) { lua_pushvalue(L, -1); - lua_rawseti(L, 1, (int)m_iNextIndex); + lua_rawseti(L, 1, (int)next_index); } else { - lua_pushnumber(L, (lua_Number)m_iNextIndex); + lua_pushnumber(L, (lua_Number)next_index); lua_pushvalue(L, -2); lua_rawset(L, 1); } - ++m_iNextIndex; + ++next_index; } - bool readTableContents() + bool read_table_contents() { - lua_State *L = m_L; while(true) { - if(!readStackObject()) + if(!read_stack_object()) return false; if(lua_type(L, -1) == LUA_TNIL) { lua_pop(L, 1); return true; } - if(!readStackObject()) + if(!read_stack_object()) return false; // NB: lua_rawset used rather than lua_settable to avoid invoking // any metamethods, as they may not have been designed to be called @@ -1147,12 +1110,11 @@ bool finish() { - lua_State *L = m_L; // Ensure that all data has been read - if(m_iDataBufferLength != 0) + if(data_buffer_size != 0) { - setError(lua_pushfstring(L, "%d bytes of data remain unpersisted", (int)m_iDataBufferLength)); + set_error(lua_pushfstring(L, "%d bytes of data remain unpersisted", (int)data_buffer_size)); return false; } @@ -1180,42 +1142,60 @@ return true; } - virtual bool readByteStream(uint8_t *pBytes, size_t iCount) + bool read_byte_stream(uint8_t *pBytes, size_t iCount) override { - if(iCount > m_iDataBufferLength) + if(iCount > data_buffer_size) { - setError(lua_pushfstring(m_L, + set_error(lua_pushfstring(L, + "End of input reached while attempting to read %d byte%s", + (int)iCount, iCount == 1 ? "" : "s")); + lua_pop(L, 1); + return false; + } + + if(pBytes != nullptr) + std::memcpy(pBytes, data, iCount); + + data += iCount; + data_buffer_size -= iCount; + return true; + } + + bool read_byte_stream(std::string& bytes, size_t iCount) + { + if(iCount > data_buffer_size) { + set_error(lua_pushfstring(L, "End of input reached while attempting to read %d byte%s", (int)iCount, iCount == 1 ? "" : "s")); - lua_pop(m_L, 1); + lua_pop(L, 1); return false; } - if(pBytes != NULL) - memcpy(pBytes, m_pData, iCount); - m_pData += iCount; - m_iDataBufferLength -= iCount; + + bytes.assign(reinterpret_cast(data), iCount); + + data += iCount; + data_buffer_size -= iCount; return true; } - const uint8_t* getPointer() {return m_pData;} - uint64_t getObjectCount() {return m_iNextIndex;} + const uint8_t* get_pointer() {return data;} + uint64_t get_object_count() {return next_index;} - const char* getError() + const char* get_error() { - if(m_bHadError) - return m_sStringBuffer; + if(had_error) + return string_buffer.c_str(); else - return NULL; + return nullptr; } -protected: - lua_State *m_L; - uint64_t m_iNextIndex; - const uint8_t* m_pData; - char* m_sStringBuffer; - size_t m_iDataBufferLength; - size_t m_iStringBufferLength; - bool m_bHadError; +private: + lua_State *L; + uint64_t next_index; + const uint8_t* data; + size_t data_buffer_size; + std::string string_buffer; + bool had_error; }; static int l_dump_toplevel(lua_State *L) @@ -1223,30 +1203,30 @@ luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); lua_pushvalue(L, 1); - LuaPersistBasicWriter *pWriter = new (lua_newuserdata(L, sizeof(LuaPersistBasicWriter))) LuaPersistBasicWriter(L); + lua_persist_basic_writer *pWriter = new (lua_newuserdata(L, sizeof(lua_persist_basic_writer))) lua_persist_basic_writer(L); lua_replace(L, 1); pWriter->init(); - pWriter->writeStackObject(3); + pWriter->write_stack_object(3); return pWriter->finish(); } static int l_load_toplevel(lua_State *L) { size_t iDataLength; - const unsigned char *pData = luaT_checkfile(L, 1, &iDataLength); + const uint8_t *pData = luaT_checkfile(L, 1, &iDataLength); luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); lua_pushvalue(L, 1); - LuaPersistBasicReader *pReader = new (lua_newuserdata(L, sizeof(LuaPersistBasicReader))) LuaPersistBasicReader(L); + lua_persist_basic_reader *pReader = new (lua_newuserdata(L, sizeof(lua_persist_basic_reader))) lua_persist_basic_reader(L); lua_replace(L, 1); pReader->init(pData, iDataLength); - if(!pReader->readStackObject() || !pReader->finish()) + if(!pReader->read_stack_object() || !pReader->finish()) { - int iNumObjects = (int)pReader->getObjectCount(); - int iNumBytes = (int)(pReader->getPointer() - pData); + int iNumObjects = (int)pReader->get_object_count(); + int iNumBytes = (int)(pReader->get_pointer() - pData); lua_pushnil(L); lua_pushfstring(L, "%s after %d objects (%d bytes)", - pReader->getError() ? pReader->getError() : "Error while depersisting", + pReader->get_error() ? pReader->get_error() : "Error while depersisting", iNumObjects, iNumBytes); return 2; } @@ -1256,7 +1236,7 @@ } } -static int CalculateLineNumber(const char *sStart, const char *sPosition) +static int calculate_line_number(const char *sStart, const char *sPosition) { int iLine = 1; for(; sStart != sPosition; ++sStart) @@ -1280,21 +1260,21 @@ return iLine; } -const char* FindFunctionEnd(lua_State *L, const char* sStart) +static const char* find_function_end(lua_State *L, const char* sStart) { const char* sEnd = sStart; while(sEnd) { - sEnd = strstr(sEnd, "end"); + sEnd = std::strstr(sEnd, "end"); if(sEnd) { sEnd += 3; - LoadMultiBuffer_t ls; + load_multi_buffer ls; ls.s[0] = "return function"; ls.i[0] = sizeof("return function") - 1; ls.s[1] = sStart; ls.i[1] = sEnd - sStart; - if(lua_load(L, LoadMultiBuffer_t::load_fn, &ls, "") == 0) + if(luaT_load(L, load_multi_buffer::load_fn, &ls, "", "bt") == 0) { lua_pop(L, 1); return sEnd; @@ -1302,7 +1282,7 @@ lua_pop(L, 1); } } - return NULL; + return nullptr; } static int l_persist_dofile(lua_State *L) @@ -1311,37 +1291,37 @@ lua_settop(L, 1); // Read entire file into memory - FILE *fFile = fopen(sFilename, "r"); - if(fFile == NULL) + FILE *fFile = std::fopen(sFilename, "r"); + if(fFile == nullptr) { - const char *sError = strerror(errno); + const char *sError =std::strerror(errno); return luaL_error(L, "cannot open %s: %s", sFilename, sError); } - size_t iBufferSize = lua_objlen(L, lua_upvalueindex(1)); + size_t iBufferSize = lua_objlen(L, luaT_upvalueindex(1)); size_t iBufferUsed = 0; - while(!feof(fFile)) + while(!std::feof(fFile)) { - iBufferUsed += fread(reinterpret_cast(lua_touserdata(L, - lua_upvalueindex(1))) + iBufferUsed, 1, iBufferSize - iBufferUsed, fFile); + iBufferUsed += std::fread(reinterpret_cast(lua_touserdata(L, + luaT_upvalueindex(1))) + iBufferUsed, 1, iBufferSize - iBufferUsed, fFile); if(iBufferUsed == iBufferSize) { iBufferSize *= 2; - memcpy(lua_newuserdata(L, iBufferSize), lua_touserdata(L, lua_upvalueindex(1)), iBufferUsed); - lua_replace(L, lua_upvalueindex(1)); + std::memcpy(lua_newuserdata(L, iBufferSize), lua_touserdata(L, luaT_upvalueindex(1)), iBufferUsed); + lua_replace(L, luaT_upvalueindex(1)); } else break; } - int iStatus = ferror(fFile); - fclose(fFile); + int iStatus = std::ferror(fFile); + std::fclose(fFile); if(iStatus) { - const char *sError = strerror(errno); + const char *sError =std::strerror(errno); return luaL_error(L, "cannot read %s: %s", sFilename, sError); } // Check file - char *sFile = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); + char *sFile = reinterpret_cast(lua_touserdata(L, luaT_upvalueindex(1))); sFile[iBufferUsed] = 0; if(sFile[0] == '#') { @@ -1364,32 +1344,32 @@ return lua_error(L); lua_remove(L, -2); int iBufferCopyIndex = lua_gettop(L); - memcpy(lua_newuserdata(L, iBufferUsed + 1), sFile, iBufferUsed + 1); + std::memcpy(lua_newuserdata(L, iBufferUsed + 1), sFile, iBufferUsed + 1); lua_insert(L, -2); lua_call(L, 0, LUA_MULTRET); - sFile = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); - memcpy(sFile, lua_touserdata(L, iBufferCopyIndex), iBufferUsed + 1); + sFile = reinterpret_cast(lua_touserdata(L, luaT_upvalueindex(1))); + std::memcpy(sFile, lua_touserdata(L, iBufferCopyIndex), iBufferUsed + 1); lua_remove(L, iBufferCopyIndex); // Extract persistable functions const char *sPosition = sFile; while(true) { - sPosition = strstr(sPosition, "--[[persistable:"); + sPosition = std::strstr(sPosition, "--[[persistable:"); if(!sPosition) break; sPosition += 16; - const char *sNameEnd = strstr(sPosition, "]]"); + const char *sNameEnd = std::strstr(sPosition, "]]"); if(sNameEnd) { - int iLineNumber = CalculateLineNumber(sFile, sNameEnd); - const char *sFunctionArgs = strchr(sNameEnd + 2, '('); - const char *sFunctionEnd = FindFunctionEnd(L, sFunctionArgs); + int iLineNumber = calculate_line_number(sFile, sNameEnd); + const char *sFunctionArgs = std::strchr(sNameEnd + 2, '('); + const char *sFunctionEnd = find_function_end(L, sFunctionArgs); if((sNameEnd - sPosition) == 1 && *sPosition == ':') { // --[[persistable::]] means take the existing name of the function - sPosition = strstr(sNameEnd, "function") + 8; - sPosition += strspn(sPosition, " \t"); + sPosition = std::strstr(sNameEnd, "function") + 8; + sPosition += std::strspn(sPosition, " \t"); sNameEnd = sFunctionArgs; while(sNameEnd[-1] == ' ') --sNameEnd; @@ -1399,12 +1379,12 @@ // Save : => lua_pushfstring(L, "%s:%d", sFilename, iLineNumber); lua_pushvalue(L, -1); - lua_gettable(L, lua_upvalueindex(2)); + lua_gettable(L, luaT_upvalueindex(2)); if(lua_isnil(L, -1)) { lua_pop(L, 1); lua_pushlstring(L, sPosition, sNameEnd - sPosition); - lua_settable(L, lua_upvalueindex(2)); + lua_settable(L, luaT_upvalueindex(2)); } else { @@ -1415,12 +1395,12 @@ // Save => lua_pushlstring(L, sPosition, sNameEnd - sPosition); lua_pushvalue(L, -1); - lua_gettable(L, lua_upvalueindex(3)); + lua_gettable(L, luaT_upvalueindex(3)); if(lua_isnil(L, -1)) { lua_pop(L, 1); lua_pushvalue(L, 1); - lua_settable(L, lua_upvalueindex(3)); + lua_settable(L, luaT_upvalueindex(3)); } else { @@ -1439,7 +1419,7 @@ lua_pushliteral(L, "function"); lua_pushlstring(L, sFunctionArgs, sFunctionEnd - sFunctionArgs); lua_concat(L, 3); - lua_settable(L, lua_upvalueindex(4)); + lua_settable(L, luaT_upvalueindex(4)); } } } @@ -1456,28 +1436,28 @@ return 1; } -static const struct luaL_reg persist_lib[] = { +static const std::vector persist_lib = { // Due to the various required upvalues, functions are registered // manually, but we still need a dummy to pass to luaL_register. {"errcatch", l_errcatch}, - {NULL, NULL} + {nullptr, nullptr} }; int luaopen_persist(lua_State *L) { - luaL_register(L, "persist", persist_lib); + luaT_register(L, "persist", persist_lib); lua_newuserdata(L, 512); // buffer for dofile lua_newtable(L); lua_newtable(L); lua_newtable(L); lua_pushvalue(L, -3); - lua_pushcclosure(L, l_dump_toplevel, 1); + luaT_pushcclosure(L, l_dump_toplevel, 1); lua_setfield(L, -6, "dump"); lua_pushvalue(L, -2); lua_pushvalue(L, -2); - lua_pushcclosure(L, l_load_toplevel, 2); + luaT_pushcclosure(L, l_load_toplevel, 2); lua_setfield(L, -6, "load"); - lua_pushcclosure(L, l_persist_dofile, 4); + luaT_pushcclosure(L, l_persist_dofile, 4); lua_setfield(L, -2, "dofile"); return 1; } diff -Nru corsix-th-0.30/CorsixTH/Src/persist_lua.h corsix-th-0.62/CorsixTH/Src/persist_lua.h --- corsix-th-0.30/CorsixTH/Src/persist_lua.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/persist_lua.h 2018-07-21 11:13:17.000000000 +0000 @@ -22,44 +22,39 @@ #ifndef CORSIX_TH_PERSIST_LUA_H_ #define CORSIX_TH_PERSIST_LUA_H_ -#include "th_lua.h" #include "config.h" -#include -#ifdef CORSIX_TH_HAS_MALLOC_H -#include // for alloca -#endif -#ifdef CORSIX_TH_HAS_ALLOCA_H -#include -#endif +#include "th_lua.h" +#include +#include -template struct LuaPersistVInt {}; -template <> struct LuaPersistVInt {typedef unsigned int T;}; +template struct lua_persist_int {}; +template <> struct lua_persist_int {typedef unsigned int T;}; //! Interface used for persisting Lua objects /*! When userdata are persisted, they get an instance of this interface for writing binary data and other Lua objects. */ -class LuaPersistWriter +class lua_persist_writer { public: - virtual ~LuaPersistWriter(); + virtual ~lua_persist_writer() = default; - virtual lua_State* getStack() = 0; - virtual void writeStackObject(int iIndex) = 0; - virtual void writeByteStream(const uint8_t *pBytes, size_t iCount) = 0; - virtual void setError(const char *sError) = 0; + virtual lua_State* get_stack() = 0; + virtual void write_stack_object(int iIndex) = 0; + virtual void write_byte_stream(const uint8_t *pBytes, size_t iCount) = 0; + virtual void set_error(const char *sError) = 0; - // writeStackObject for userdata without growing the Lua call stack + // write_stack_object for userdata without growing the Lua call stack // The given index should be a userdata whose __persist metamethod supports // fast persistance (being called with extra arguments and the wrong // environment / upvalues). - virtual void fastWriteStackObject(int iIndex) = 0; + virtual void fast_write_stack_object(int iIndex) = 0; // Writes an unsigned integer as a variable number of bytes // Endian independant and underlying type size independant template - void writeVUInt(T tValue) + void write_uint(T tValue) { T tTemp(tValue); int iNumBytes; @@ -68,43 +63,43 @@ if(iNumBytes == 1) { uint8_t iByte = (uint8_t)tValue; - writeByteStream(&iByte, 1); + write_byte_stream(&iByte, 1); } else { - uint8_t *pBytes = (uint8_t*)alloca(iNumBytes); - pBytes[iNumBytes - 1] = 0x7F & (uint8_t)(tValue); + std::vector bytes(iNumBytes); + bytes[iNumBytes - 1] = 0x7F & (uint8_t)(tValue); for(int i = 1; i < iNumBytes; ++i) { tValue /= (T)0x80; - pBytes[iNumBytes - 1 - i] = 0x80 | (0x7F & (uint8_t)tValue); + bytes[iNumBytes - 1 - i] = 0x80 | (0x7F & (uint8_t)tValue); } - writeByteStream(pBytes, iNumBytes); + write_byte_stream(bytes.data(), iNumBytes); } } template - void writeVInt(T tValue) + void write_int(T tValue) { - typename LuaPersistVInt::T tValueToWrite; + typename lua_persist_int::T tValueToWrite; if(tValue >= 0) { - tValueToWrite = (typename LuaPersistVInt::T)tValue; + tValueToWrite = (typename lua_persist_int::T)tValue; tValueToWrite <<= 1; } else { - tValueToWrite = (typename LuaPersistVInt::T)(-(tValue + 1)); + tValueToWrite = (typename lua_persist_int::T)(-(tValue + 1)); tValueToWrite <<= 1; tValueToWrite |= 1; } - writeVUInt(tValueToWrite); + write_uint(tValueToWrite); } template - void writeVFloat(T fValue) + void write_float(T fValue) { - writeByteStream(reinterpret_cast(&fValue), sizeof(T)); + write_byte_stream(reinterpret_cast(&fValue), sizeof(T)); } }; @@ -113,35 +108,35 @@ When userdata are depersisted, they get an instance of this interface for reading binary data and other Lua objects. */ -class LuaPersistReader +class lua_persist_reader { public: - virtual ~LuaPersistReader(); + virtual ~lua_persist_reader() = default; - virtual lua_State* getStack() = 0; - virtual bool readStackObject() = 0; - virtual bool readByteStream(uint8_t *pBytes, size_t iCount) = 0; - virtual void setError(const char *sError) = 0; + virtual lua_State* get_stack() = 0; + virtual bool read_stack_object() = 0; + virtual bool read_byte_stream(uint8_t *pBytes, size_t iCount) = 0; + virtual void set_error(const char *sError) = 0; - // Reads an integer previously written by LuaPersistWriter::writeVUInt() + // Reads an integer previously written by lua_persist_writer::write_uint() template - bool readVUInt(T& tValue) + bool read_uint(T& tValue) { T tTemp(0); uint8_t iByte; while(true) { - if(!readByteStream(&iByte, 1)) + if(!read_byte_stream(&iByte, 1)) return false; if(iByte & 0x80) { - tTemp |= (iByte & 0x7F); - tTemp <<= 7; + tTemp = static_cast(tTemp | (iByte & 0x7F)); + tTemp = static_cast(tTemp << 7); } else { - tTemp |= iByte; + tTemp = static_cast(tTemp | iByte); break; } } @@ -151,22 +146,22 @@ } template - bool readVInt(T& tValue) + bool read_int(T& tValue) { - typename LuaPersistVInt::T tWrittenValue; - if(!readVUInt(tWrittenValue)) + typename lua_persist_int::T tWrittenValue; + if(!read_uint(tWrittenValue)) return false; if(tWrittenValue & 1) tValue = (-(T)(tWrittenValue >> 1)) - 1; else - tValue = (T)(tWrittenValue >> 1); + tValue = static_cast(tWrittenValue >> 1); return true; } template - bool readVFloat(T& fValue) + bool read_float(T& fValue) { - if(!readByteStream(reinterpret_cast(&fValue), sizeof(T))) + if(!read_byte_stream(reinterpret_cast(&fValue), sizeof(T))) return false; return true; } diff -Nru corsix-th-0.30/CorsixTH/Src/random.c corsix-th-0.62/CorsixTH/Src/random.c --- corsix-th-0.30/CorsixTH/Src/random.c 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/random.c 2018-07-21 11:13:17.000000000 +0000 @@ -61,7 +61,7 @@ uint16_t mti=N+1; /* mti==N+1 means mt[N] is not initialized */ /* initializes mt[N] with a seed */ -void init_genrand(uint32_t s) +static void init_genrand(uint32_t s) { mt[0]= s; for (mti=1; mti>5, b=genrand_int32()>>6; return(a*67108864.0+b)*(1.0/9007199254740992.0); diff -Nru corsix-th-0.30/CorsixTH/Src/rnc.cpp corsix-th-0.62/CorsixTH/Src/rnc.cpp --- corsix-th-0.30/CorsixTH/Src/rnc.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/rnc.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,554 +0,0 @@ -/* -Copyright (c) 1997 Simon Tatham - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - Original code was from http://www.yoda.arachsys.com/dk/utils.html. While - that site and the original code do not state copyright or license, email - communication releaved the original author, and they agreed to releasing it - under the MIT license (above). - - Modifications made to the original code include: - * Const correctness - * Prebuilt CRC table - * Lua interface - * Indentation and code style - * Bit stream pointers to data - * Fix bit operations near end of stream - * Style changes to conform to CorsixTH -*/ - -#include "config.h" -#include "rnc.h" - -#define RNC_OK 0 -#define RNC_FILE_IS_NOT_RNC -1 -#define RNC_HUF_DECODE_ERROR -2 -#define RNC_FILE_SIZE_MISMATCH -3 -#define RNC_PACKED_CRC_ERROR -4 -#define RNC_UNPACKED_CRC_ERROR -5 -#define RNC_SIGNATURE 0x524E4301 /* "RNC\001" */ - -static const unsigned short rnc_crc_table[256] = { - 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, - 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, - 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, - 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, - 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, - 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, - 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, - 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, - 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, - 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, - 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, - 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, - 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, - 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, - 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, - 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, - 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, - 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, - 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, - 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, - 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, - 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, - 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, - 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, - 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, - 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, - 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, - 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, - 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, - 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, - 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, - 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, -}; - -struct bit_stream -{ - unsigned long bitbuf; // holds between 16 and 32 bits - int bitcount; // how many bits does bitbuf hold? - const unsigned char* endpos; // final position that can be read - const unsigned char* p; // pointer in data that stream is reading -}; - -struct huf_table -{ - int num; // number of nodes in the tree - struct - { - unsigned long code; - int codelen; - int value; - } table[32]; -}; - -//! Calculate a CRC, the RNC way. -/*! - @param data data for which to calculate the CRC - @param len length of the data in bytes -*/ -static unsigned long rnc_crc(const unsigned char* data, long len) -{ - unsigned short val = 0; - - while(len--) - { - val ^= *data++; - val = (val >> 8) ^ rnc_crc_table[val & 0xFF]; - } - - return val; -} - - -//! Return the big-endian 32 bit word at p. -/*! - @param p Pointer to data containing the word -*/ -static unsigned long blong (const unsigned char *p) -{ - unsigned long n; - n = p[0]; - n = (n << 8) + p[1]; - n = (n << 8) + p[2]; - n = (n << 8) + p[3]; - return n; -} - -//! Return the big-endian 16 bit word at p. -/*! - @param p Pointer to data containing the word -*/ -static unsigned long bword (const unsigned char *p) -{ - unsigned long n; - n = p[0]; - n = (n << 8) + p[1]; - return n; -} - -//! Return the little-endian 16 bit word at p. -/*! - @param p Pointer to data containing the word - */ -static unsigned long lword (const unsigned char *p) -{ - unsigned long n; - n = p[1]; - n = (n << 8) + p[0]; - return n; -} - -//! Mirror the bottom n bits of x. -/*! - @param x - @param n -*/ -static unsigned long mirror (unsigned long x, int n) -{ - unsigned long top = 1 << (n-1), bottom = 1; - while (top > bottom) - { - unsigned long mask = top | bottom; - unsigned long masked = x & mask; - if (masked != 0 && masked != mask) - { - x ^= mask; - } - top >>= 1; - bottom <<= 1; - } - return x; -} - - -//! Initialises a bit stream with the first two bytes of the packed -//! data. -/*! - @param bs Bit stream to be initialized - @param p Pointer to start of memory block the bitstream is to - traverse - @param endpos Pointer to end of memory block the bitstream is - to traverse -*/ -static void bitread_init (bit_stream *bs, const unsigned char *p, const unsigned char* endpos) -{ - bs->bitbuf = lword (p); - bs->bitcount = 16; - bs->p = p; - bs->endpos = endpos; -} - -//! Fixes up a bit stream after literals have been read out of the -//! data stream and the pointer has been moved. -/*! - @param bs Bit stream to correct -*/ -static void bitread_fix (bit_stream *bs) -{ - // Remove the top 16 bits - bs->bitcount -= 16; - bs->bitbuf &= (1<bitcount)-1; - - // Replace with what is in the new current location - // in the bit stream - if(bs->p < bs->endpos) - { - bs->bitbuf |= (lword(bs->p)<bitcount); - bs->bitcount += 16; - } - else if(bs->p == bs->endpos) - { - bs->bitbuf |= (*(bs->p)<bitcount); - bs->bitcount += 8; - } -} - -//! Return a word consisting of the specified bits without advancing -//! the bit stream. -/*! - @param bs Bit stream from which to peek - @param mask A 32 bit bit mask specifying which bits to peek -*/ -static unsigned long bit_peek (bit_stream *bs, const unsigned long mask) -{ - return bs->bitbuf & mask; -} - -//! Advances the bit stream. -/*! - @param bs Bit stream to advance - @param n Number of bits to advance the stream. Must be - between 0 and 16 -*/ -static void bit_advance (bit_stream *bs, int n) -{ - bs->bitbuf >>= n; - bs->bitcount -= n; - - if (bs->bitcount < 16) - { - // At this point it is possible for bs->p to advance past - // the end of the data. In that case we simply do not read - // anything more into the buffer. If we are on the last - // byte the lword matches what is in that byte. - bs->p += 2; - - if(bs->p < bs->endpos) - { - bs->bitbuf |= (lword(bs->p)<bitcount); - bs->bitcount += 16; - } - else if (bs->p == bs->endpos) - { - bs->bitbuf |= (*(bs->p)<bitcount); - bs->bitcount += 8; - } - } -} - -//! Returns bits from the bit stream matching the mask and advances it -//! n places. -/*! - @param bs Bit stream to read - @param mask A 32 bit bit mask specifiying which bits to read - @param n Number of bits to advance the stream. Must be - between 0 and 16 -*/ -static unsigned long bit_read (bit_stream *bs, unsigned long mask, int n) -{ - unsigned long result = bit_peek(bs, mask); - bit_advance(bs, n); - return result; -} - -//! Read a Huffman table out of the bit stream given. -/*! - @param h huf_table structure to populate - @param bs Bit stream pointing to the start of the Huffman table - description -*/ -static void read_huftable(huf_table *h, bit_stream *bs) -{ - int i, j, k, num; - int leaflen[32]; - int leafmax; - unsigned long codeb; /* big-endian form of code */ - - num = bit_read(bs, 0x1F, 5); - - if(num == 0) - { - return; - } - - leafmax = 1; - for(i = 0; i < num; i++) - { - leaflen[i] = bit_read(bs, 0x0F, 4); - if (leafmax < leaflen[i]) - { - leafmax = leaflen[i]; - } - } - - codeb = 0L; - k = 0; - for(i = 1; i <= leafmax; i++) - { - for(j = 0; j < num; j++) - { - if(leaflen[j] == i) - { - h->table[k].code = mirror(codeb, i); - h->table[k].codelen = i; - h->table[k].value = j; - codeb++; - k++; - } - } - codeb <<= 1; - } - h->num = k; -} - -//! Read a value out of the bit stream using the given Huffman table. -/*! - @param h Huffman table to transcribe from - @param bs bit stream - @param p input data - @return The value from the table with the matching bits, or -1 if none found. -*/ -static unsigned long huf_read(huf_table *h, bit_stream *bs, const unsigned char **p) -{ - int i; - unsigned long val; - unsigned long mask; - - // Find the current bits in the table - for (i = 0; i < h->num; i++) - { - mask = (1 << h->table[i].codelen) - 1; - if(bit_peek(bs, mask) == h->table[i].code) - { - break; - } - } - - // No match found in table (error) - if(i == h->num) - { - return -1; - } - - bit_advance(bs, h->table[i].codelen); - - val = h->table[i].value; - if (val >= 2) - { - val = 1 << (val-1); - val |= bit_read(bs, val-1, h->table[i].value - 1); - } - return val; -} - -//! Decompresses RNC data -/*! - @param input Pointer to compressed RNC data - @param output Pointer to allocated memory region to hold uncompressed - data. The size of output must match the value specified in the - 4 byte segment of the input header starting at the 4th byte - in Big-endian. -*/ -static int rnc_unpack(const unsigned char* input, unsigned char* output) -{ - const unsigned char *inputend; - unsigned char *outputend; - bit_stream input_bs; - huf_table raw = {0}, dist = {0}, len = {0}; - unsigned long ch_count; - unsigned long ret_len; - unsigned long out_crc; - if(blong(input) != RNC_SIGNATURE) - { - return RNC_FILE_IS_NOT_RNC; - } - ret_len = blong(input + 4); - outputend = output + ret_len; - inputend = input + 18 + blong(input + 8); - - //skip header - input += 18; - - // Check the packed-data CRC. Also save the unpacked-data CRC - // for later. - if(rnc_crc(input, static_cast(inputend-input)) != bword(input - 4)) - { - return RNC_PACKED_CRC_ERROR; - } - out_crc = bword(input - 6); - - //initialize the bitstream to the input and advance past the - //first two bytes as they don't have any understood use. - bitread_init(&input_bs, input, inputend); - bit_advance(&input_bs, 2); - - //process chunks - while (output < outputend) - { - read_huftable(&raw, &input_bs); //raw byte length table - read_huftable(&dist, &input_bs); //distance prior to copy table - read_huftable(&len, &input_bs); //length bytes to copy table - ch_count = bit_read(&input_bs, 0xFFFF, 16); - - while(true) - { - long length, posn; - - // Copy bit pattern to output based on lookup - // of bytes from input. - length = huf_read(&raw, &input_bs, &input); - if(length == -1) - { - return RNC_HUF_DECODE_ERROR; - } - if(length) - { - while(length--) - { - *output++ = *(input_bs.p++); - } - bitread_fix(&input_bs); - } - if(--ch_count <= 0) - { - break; - } - - // Read position to copy output to - posn = huf_read(&dist, &input_bs, &input); - if(posn == -1) - { - return RNC_HUF_DECODE_ERROR; - } - posn += 1; - - // Read length of output to copy back - length = huf_read(&len, &input_bs, &input); - if(length == -1) - { - return RNC_HUF_DECODE_ERROR; - } - length += 2; - - // Copy length bytes from output back posn - while(length--) - { - *output = output[-posn]; - output++; - } - } - } - - if(outputend != output) - { - return RNC_FILE_SIZE_MISMATCH; - } - - // Check the unpacked-data CRC. - if(rnc_crc(outputend - ret_len, ret_len) != out_crc) - { - return RNC_UNPACKED_CRC_ERROR; - } - - return RNC_OK; -} - -//! Provides lua function to decompress RNC data -/*! - @param L Lua state where the function is called from. In lua a call - to this function has one parameter which is the RNC compressed data. - The return value is the decompressed data. -*/ -static int l_decompress(lua_State *L) -{ - size_t inlen; - const unsigned char* in = (const unsigned char*)luaL_checklstring(L, 1, &inlen); - - // Verify that the data contains an RNC signature, and that the input - // size matches the size specified in the data header. - if(inlen < 18 || blong(in) != RNC_SIGNATURE || blong(in + 8) != (inlen - 18)) - { - lua_pushnil(L); - lua_pushliteral(L, "Input is not RNC compressed data"); - return 2; - } - unsigned long outlen = blong(in + 4); - - // Allocate scratch area as Lua userdata so that if something horrible - // happens, it'll be cleaned up by Lua's GC. Remember that most Lua API - // calls can throw errors, so they all have to be wrapped with code to - // detect errors and free the buffer if said buffer was not managed by Lua. - void* outbuf = lua_newuserdata(L, outlen); - - lua_pushnil(L); - switch(rnc_unpack(in, (unsigned char*)outbuf)) - { - case RNC_OK: - lua_pushlstring(L, (const char*)outbuf, outlen); - return 1; - - case RNC_FILE_IS_NOT_RNC: - lua_pushliteral(L, "Input is not RNC compressed data"); - break; - - case RNC_HUF_DECODE_ERROR: - lua_pushliteral(L, "Invalid Huffman coding"); - break; - - case RNC_FILE_SIZE_MISMATCH: - lua_pushliteral(L, "Size mismatch"); - break; - - case RNC_PACKED_CRC_ERROR: - lua_pushliteral(L, "Incorrect packed CRC"); - break; - - case RNC_UNPACKED_CRC_ERROR: - lua_pushliteral(L, "Incorrect unpacked CRC"); - break; - - default: - lua_pushliteral(L, "Unknown error decompressing RNC data"); - break; - } - return 2; -} - -static const struct luaL_reg rnclib[] = { - {"decompress", l_decompress}, - {NULL, NULL} -}; - -int luaopen_rnc(lua_State *L) -{ - luaL_register(L, "rnc", rnclib); - return 1; -} diff -Nru corsix-th-0.30/CorsixTH/Src/rnc.h corsix-th-0.62/CorsixTH/Src/rnc.h --- corsix-th-0.30/CorsixTH/Src/rnc.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/rnc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* -Copyright (c) 2009 Peter "Corsix" Cawley - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef CORSIX_TH_RNC_H_ -#define CORSIX_TH_RNC_H_ -#include "lua.hpp" - -int luaopen_rnc(lua_State *L); - -#endif // CORSIX_TH_RNC_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/run_length_encoder.cpp corsix-th-0.62/CorsixTH/Src/run_length_encoder.cpp --- corsix-th-0.30/CorsixTH/Src/run_length_encoder.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/run_length_encoder.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -25,79 +25,79 @@ #include #include -IntegerRunLengthEncoder::IntegerRunLengthEncoder() +integer_run_length_encoder::integer_run_length_encoder() { - m_pBuffer = NULL; - m_pOutput = NULL; - _clean(); + buffer = nullptr; + output = nullptr; + clean(); } -IntegerRunLengthEncoder::~IntegerRunLengthEncoder() +integer_run_length_encoder::~integer_run_length_encoder() { - _clean(); + clean(); } -void IntegerRunLengthEncoder::_clean() +void integer_run_length_encoder::clean() { - delete[] m_pBuffer; - delete[] m_pOutput; - m_pBuffer = NULL; - m_pOutput = NULL; - m_iRecordSize = 0; - m_iBufferSize = 0; - m_iBufferSizeUsed = 0; - m_iBufferOffset = 0; - m_iOutputSize = 0; - m_iOutputSizeUsed = 0; - m_iObjectSize = 0; - m_iObjectCount = 0; + delete[] buffer; + delete[] output; + buffer = nullptr; + output = nullptr; + record_size = 0; + buffer_capacity = 0; + buffer_size = 0; + buffer_offset = 0; + output_capacity = 0; + output_size = 0; + object_size = 0; + object_copies = 0; } -bool IntegerRunLengthEncoder::initialise(size_t iRecordSize) +bool integer_run_length_encoder::initialise(size_t iRecordSize) { - _clean(); - m_iRecordSize = iRecordSize; + clean(); + record_size = iRecordSize; // Buffer must hold at least 7 + 2 * 8 records, as the maximum object size // is 8 records, 2 of which are needed to detect a repeat, and 7 for the // offset at which the objects are found. - m_iBufferSize = iRecordSize * 8 * 4; - m_iBufferSizeUsed = 0; - m_iBufferOffset = 0; - m_pBuffer = new (std::nothrow) uint32_t[m_iBufferSize]; - if(!m_pBuffer) + buffer_capacity = iRecordSize * 8 * 4; + buffer_size = 0; + buffer_offset = 0; + buffer = new (std::nothrow) uint32_t[buffer_capacity]; + if(!buffer) return false; - m_iOutputSize = iRecordSize * 32; - m_iOutputSizeUsed = 0; - m_pOutput = new (std::nothrow) uint32_t[m_iOutputSize]; - if(!m_pOutput) + output_capacity = iRecordSize * 32; + output_size = 0; + output = new (std::nothrow) uint32_t[output_capacity]; + if(!output) return false; - m_iObjectSize = 0; - m_iObjectCount = 0; + object_size = 0; + object_copies = 0; return true; } -void IntegerRunLengthEncoder::write(uint32_t iValue) +void integer_run_length_encoder::write(uint32_t iValue) { - m_pBuffer[(m_iBufferOffset + m_iBufferSizeUsed) % m_iBufferSize] = iValue; - if(++m_iBufferSizeUsed == m_iBufferSize) - _flush(false); + buffer[(buffer_offset + buffer_size) % buffer_capacity] = iValue; + if(++buffer_size == buffer_capacity) + flush(false); } -void IntegerRunLengthEncoder::finish() +void integer_run_length_encoder::finish() { - if(m_iBufferSizeUsed != 0) - _flush(true); + if(buffer_size != 0) + flush(true); } -void IntegerRunLengthEncoder::_flush(bool bAll) +void integer_run_length_encoder::flush(bool bAll) { do { - if(m_iObjectSize == 0) + if(object_size == 0) { // Decide on the size of the next object // Want the object size which gives most object repeats, then for @@ -110,9 +110,9 @@ for(size_t iOffset = 0; iOffset < iNumRecords; ++iOffset) { size_t iNumRepeats = 0; - size_t iObjSize = iNumRecords * m_iRecordSize; - while(iObjSize * (iOffset + iNumRepeats + 1) <= m_iBufferSizeUsed - && _areRangesEqual(0, iNumRepeats, iOffset, iObjSize)) + size_t iObjSize = iNumRecords * record_size; + while(iObjSize * (iOffset + iNumRepeats + 1) <= buffer_size + && are_ranges_equal(0, iNumRepeats, iOffset, iObjSize)) { ++iNumRepeats; } @@ -129,52 +129,52 @@ { // No repeats were found, so the best we can do is output // a large non-repeating blob. - _output(std::min(m_iBufferSizeUsed, 8 * m_iRecordSize), 1); + move_object_to_output(std::min(buffer_size, 8 * record_size), 1); } else { if(iBestOffset != 0) - _output(iBestOffset * m_iRecordSize, 1); + move_object_to_output(iBestOffset * record_size, 1); // Mark the object as the current one, and remove all but the // last instance of it from the buffer. On the next flush, the // new data might continue the same object, hence why the // object isn't output just yet. - m_iObjectSize = iBestSize; - m_iObjectCount = iBestRepeats - 1; - m_iBufferOffset = (m_iBufferOffset + m_iObjectSize * m_iObjectCount) % m_iBufferSize; - m_iBufferSizeUsed -= m_iObjectSize * m_iObjectCount; + object_size = iBestSize; + object_copies = iBestRepeats - 1; + buffer_offset = (buffer_offset + object_size * object_copies) % buffer_capacity; + buffer_size -= object_size * object_copies; } } else { // Try to match more of the current object - while(m_iObjectSize * 2 <= m_iBufferSizeUsed && - _areRangesEqual(0, 1, 0, m_iObjectSize)) + while(object_size * 2 <= buffer_size && + are_ranges_equal(0, 1, 0, object_size)) { - ++m_iObjectCount; - m_iBufferOffset = (m_iBufferOffset + m_iObjectSize) % m_iBufferSize; - m_iBufferSizeUsed -= m_iObjectSize; + ++object_copies; + buffer_offset = (buffer_offset + object_size) % buffer_capacity; + buffer_size -= object_size; } // Write data - if(m_iObjectSize * 2 <= m_iBufferSizeUsed || bAll) + if(object_size * 2 <= buffer_size || bAll) { - _output(m_iObjectSize, m_iObjectCount + 1); - m_iObjectSize = 0; - m_iObjectCount = 0; + move_object_to_output(object_size, object_copies + 1); + object_size = 0; + object_copies = 0; } } - } while(bAll && m_iBufferSizeUsed != 0); + } while(bAll && buffer_size != 0); } -bool IntegerRunLengthEncoder::_areRangesEqual(size_t iObjIdx1, size_t iObjIdx2, +bool integer_run_length_encoder::are_ranges_equal(size_t iObjIdx1, size_t iObjIdx2, size_t iOffset, size_t iObjSize) const { - iObjIdx1 = m_iBufferOffset + iOffset * m_iRecordSize + iObjIdx1 * iObjSize; - iObjIdx2 = m_iBufferOffset + iOffset * m_iRecordSize + iObjIdx2 * iObjSize; + iObjIdx1 = buffer_offset + iOffset * record_size + iObjIdx1 * iObjSize; + iObjIdx2 = buffer_offset + iOffset * record_size + iObjIdx2 * iObjSize; for(size_t i = 0; i < iObjSize; ++i) { - if(m_pBuffer[(iObjIdx1 + i) % m_iBufferSize] - != m_pBuffer[(iObjIdx2 + i) % m_iBufferSize]) + if(buffer[(iObjIdx1 + i) % buffer_capacity] + != buffer[(iObjIdx2 + i) % buffer_capacity]) { return false; } @@ -182,146 +182,146 @@ return true; } -bool IntegerRunLengthEncoder::_output(size_t iObjSize, size_t iObjCount) +bool integer_run_length_encoder::move_object_to_output(size_t iObjSize, size_t iObjCount) { // Grow the output array if needed - if(m_iOutputSize - m_iOutputSizeUsed <= iObjSize) + if(output_capacity - output_size <= iObjSize) { - size_t iNewSize = (m_iOutputSize + iObjSize) * 2; + size_t iNewSize = (output_capacity + iObjSize) * 2; uint32_t *pNewOutput = new (std::nothrow) uint32_t[iNewSize]; if(!pNewOutput) return false; #ifdef _MSC_VER #pragma warning(disable: 4996) #endif - std::copy(m_pOutput, m_pOutput + m_iOutputSizeUsed, pNewOutput); + std::copy(output, output + output_size, pNewOutput); #ifdef _MSC_VER #pragma warning(default: 4996) #endif - delete[] m_pOutput; - m_pOutput = pNewOutput; - m_iOutputSize = iNewSize; + delete[] output; + output = pNewOutput; + output_capacity = iNewSize; } - size_t iHeader = (iObjSize / m_iRecordSize - 1) + 8 * (iObjCount - 1); - m_pOutput[m_iOutputSizeUsed++] = static_cast(iHeader); + size_t iHeader = (iObjSize / record_size - 1) + 8 * (iObjCount - 1); + output[output_size++] = static_cast(iHeader); // Move the object from the buffer to the output for(size_t i = 0; i < iObjSize; ++i) { - m_pOutput[m_iOutputSizeUsed++] = m_pBuffer[m_iBufferOffset]; - m_iBufferOffset = (m_iBufferOffset + 1) % m_iBufferSize; + output[output_size++] = buffer[buffer_offset]; + buffer_offset = (buffer_offset + 1) % buffer_capacity; } - m_iBufferSizeUsed -= iObjSize; + buffer_size -= iObjSize; return true; } -uint32_t* IntegerRunLengthEncoder::getOutput(size_t *pCount) const +uint32_t* integer_run_length_encoder::get_output(size_t *pCount) const { if(pCount) - *pCount = m_iOutputSizeUsed; - return m_pOutput; + *pCount = output_size; + return output; } -void IntegerRunLengthEncoder::pumpOutput(LuaPersistWriter *pWriter) const +void integer_run_length_encoder::pump_output(lua_persist_writer *pWriter) const { - pWriter->writeVUInt(m_iOutputSizeUsed); - for(size_t i = 0; i < m_iOutputSizeUsed; ++i) + pWriter->write_uint(output_size); + for(size_t i = 0; i < output_size; ++i) { - pWriter->writeVUInt(m_pOutput[i]); + pWriter->write_uint(output[i]); } } -IntegerRunLengthDecoder::IntegerRunLengthDecoder() +integer_run_length_decoder::integer_run_length_decoder() { - m_pBuffer = NULL; - _clean(); + buffer = nullptr; + clean(); } -IntegerRunLengthDecoder::~IntegerRunLengthDecoder() +integer_run_length_decoder::~integer_run_length_decoder() { - _clean(); + clean(); } -void IntegerRunLengthDecoder::_clean() +void integer_run_length_decoder::clean() { - delete[] m_pBuffer; - m_pBuffer = NULL; - m_pReader = NULL; - m_pInput = NULL; - m_pInputEnd = NULL; - m_iNumReadsRemaining = 0; - m_iRepeatCount = 0; - m_iRecordSize = 0; - m_iObjectIndex = 0; - m_iObjectSize = 0; + delete[] buffer; + buffer = nullptr; + reader = nullptr; + input = nullptr; + input_end = nullptr; + reads_remaining = 0; + object_copies = 0; + record_size = 0; + object_index = 0; + object_size = 0; } -bool IntegerRunLengthDecoder::initialise(size_t iRecordSize, LuaPersistReader *pReader) +bool integer_run_length_decoder::initialise(size_t iRecordSize, lua_persist_reader *pReader) { - _clean(); + clean(); - m_pBuffer = new (std::nothrow) uint32_t[9 * iRecordSize]; - if(!m_pBuffer) + buffer = new (std::nothrow) uint32_t[9 * iRecordSize]; + if(!buffer) return false; - m_pReader = pReader; - m_iRecordSize = iRecordSize; - return pReader->readVUInt(m_iNumReadsRemaining); + reader = pReader; + record_size = iRecordSize; + return pReader->read_uint(reads_remaining); } -bool IntegerRunLengthDecoder::initialise(size_t iRecordSize, const uint32_t *pInput, size_t iCount) +bool integer_run_length_decoder::initialise(size_t iRecordSize, const uint32_t *pInput, size_t iCount) { - _clean(); + clean(); - m_pBuffer = new (std::nothrow) uint32_t[9 * iRecordSize]; - if(!m_pBuffer) + buffer = new (std::nothrow) uint32_t[9 * iRecordSize]; + if(!buffer) return false; - m_pInput = pInput; - m_pInputEnd = pInput + iCount; - m_iRecordSize = iRecordSize; + input = pInput; + input_end = pInput + iCount; + record_size = iRecordSize; return true; } -uint32_t IntegerRunLengthDecoder::read() +uint32_t integer_run_length_decoder::read() { - if(m_iRepeatCount == 0) + if(object_copies == 0) { uint32_t iHeader = 0; - if(m_pReader) + if(reader) { - m_pReader->readVUInt(iHeader); - --m_iNumReadsRemaining; + reader->read_uint(iHeader); + --reads_remaining; } else - iHeader = *(m_pInput++); - m_iObjectSize = m_iRecordSize * (1 + (iHeader & 7)); - m_iRepeatCount = (iHeader / 8) + 1; - if(m_pReader) + iHeader = *(input++); + object_size = record_size * (1 + (iHeader & 7)); + object_copies = (iHeader / 8) + 1; + if(reader) { - for(size_t i = 0; i < m_iObjectSize; ++i) + for(size_t i = 0; i < object_size; ++i) { - m_pReader->readVUInt(m_pBuffer[i]); - --m_iNumReadsRemaining; + reader->read_uint(buffer[i]); + --reads_remaining; } } else { - for(size_t i = 0; i < m_iObjectSize; ++i) - m_pBuffer[i] = *(m_pInput++); + for(size_t i = 0; i < object_size; ++i) + buffer[i] = *(input++); } } - uint32_t iValue = m_pBuffer[m_iObjectIndex]; - if(++m_iObjectIndex == m_iObjectSize) + uint32_t iValue = buffer[object_index]; + if(++object_index == object_size) { - m_iObjectIndex = 0; - --m_iRepeatCount; + object_index = 0; + --object_copies; } return iValue; } -bool IntegerRunLengthDecoder::isFinished() const +bool integer_run_length_decoder::is_finished() const { - if(m_pReader) - return m_iNumReadsRemaining == 0 && m_iRepeatCount == 0; + if(reader) + return reads_remaining == 0 && object_copies == 0; else - return m_pInput == m_pInputEnd && m_iRepeatCount == 0; + return input == input_end && object_copies == 0; } diff -Nru corsix-th-0.30/CorsixTH/Src/run_length_encoder.h corsix-th-0.62/CorsixTH/Src/run_length_encoder.h --- corsix-th-0.30/CorsixTH/Src/run_length_encoder.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/run_length_encoder.h 2018-07-21 11:13:17.000000000 +0000 @@ -24,8 +24,8 @@ #define CORSIX_TH_RLE_H_ #include "config.h" -class LuaPersistReader; -class LuaPersistWriter; +class lua_persist_reader; +class lua_persist_writer; //! Encoder for reducing the amount of space to store a sequence of integers /*! @@ -39,11 +39,11 @@ * Object - One or more records. Each object has an associated repeat count. */ -class IntegerRunLengthEncoder +class integer_run_length_encoder { public: - IntegerRunLengthEncoder(); - ~IntegerRunLengthEncoder(); + integer_run_length_encoder(); + ~integer_run_length_encoder(); //! (Re-)initialise the encoder /*! @@ -63,72 +63,72 @@ */ void finish(); - uint32_t* getOutput(size_t *pCount) const; - void pumpOutput(LuaPersistWriter *pWriter) const; + uint32_t* get_output(size_t *pCount) const; + void pump_output(lua_persist_writer *pWriter) const; -protected: - void _clean(); +private: + void clean(); //! Reduce the amount of data in the buffer /*! - \param bAll If true, will reduce m_iBufferSizeUsed to zero. - If false, will reduce m_iBufferSizeUsed by some amount. + \param bAll If true, will reduce buffer_size to zero. + If false, will reduce buffer_size by some amount. */ - void _flush(bool bAll); + void flush(bool bAll); - bool _areRangesEqual(size_t iObjIdx1, size_t iObjIdx2, size_t iOffset, size_t iObjSize) const; - bool _output(size_t iObjSize, size_t iObjCount); + bool are_ranges_equal(size_t iObjIdx1, size_t iObjIdx2, size_t iOffset, size_t iObjSize) const; + bool move_object_to_output(size_t iObjSize, size_t iObjCount); //! A circular fixed-size buffer holding the most recent input - uint32_t* m_pBuffer; + uint32_t* buffer; //! A variable-length array holding the output sequence - uint32_t* m_pOutput; + uint32_t* output; //! The number of integers in a record - size_t m_iRecordSize; + size_t record_size; //! The maximum number of integers stored in the buffer - size_t m_iBufferSize; + size_t buffer_capacity; //! The current number of integers stored in the buffer - size_t m_iBufferSizeUsed; - //! The index into m_pBuffer of the 1st integer - size_t m_iBufferOffset; + size_t buffer_size; + //! The index into buffer of the 1st integer + size_t buffer_offset; //! The maximum number of integers storable in the output (before the //! output array has to be resized). - size_t m_iOutputSize; + size_t output_capacity; //! The current number of integers stored in the output - size_t m_iOutputSizeUsed; + size_t output_size; //! The number of integers in the current object (multiple of record size) - size_t m_iObjectSize; + size_t object_size; //! The number of copies of the current object already seen and removed //! from the buffer. - size_t m_iObjectCount; + size_t object_copies; }; -class IntegerRunLengthDecoder +class integer_run_length_decoder { public: - IntegerRunLengthDecoder(); - ~IntegerRunLengthDecoder(); + integer_run_length_decoder(); + ~integer_run_length_decoder(); - bool initialise(size_t iRecordSize, LuaPersistReader *pReader); + bool initialise(size_t iRecordSize, lua_persist_reader *pReader); bool initialise(size_t iRecordSize, const uint32_t *pInput, size_t iCount); uint32_t read(); - bool isFinished() const; + bool is_finished() const; -protected: - void _clean(); +private: + void clean(); - uint32_t* m_pBuffer; - LuaPersistReader* m_pReader; - const uint32_t* m_pInput; + uint32_t* buffer; + lua_persist_reader* reader; + const uint32_t* input; union { - const uint32_t* m_pInputEnd; - size_t m_iNumReadsRemaining; + const uint32_t* input_end; + size_t reads_remaining; }; - size_t m_iRepeatCount; - size_t m_iRecordSize; - size_t m_iObjectIndex; - size_t m_iObjectSize; + size_t object_copies; + size_t record_size; + size_t object_index; + size_t object_size; }; #endif // CORSIX_TH_RLE_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/sdl_audio.cpp corsix-th-0.62/CorsixTH/Src/sdl_audio.cpp --- corsix-th-0.30/CorsixTH/Src/sdl_audio.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/sdl_audio.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -27,36 +27,26 @@ #include "xmi2mid.h" #include #ifdef _MSC_VER -#pragma comment(lib, "SDL_mixer") -#pragma warning(disable: 4996) // CRT deprecation +#pragma comment(lib, "SDL2_mixer") #endif +#include -struct music_t +class music { +public: Mix_Music* pMusic; - SDL_RWops* pRWop; - music_t() + music() { - pMusic = NULL; - pRWop = NULL; + pMusic = nullptr; } - ~music_t() + ~music() { if(pMusic) { Mix_FreeMusic(pMusic); - pMusic = NULL; - } - if(pRWop) - { - // Some SDL_Mixer backends will free this for you, and some will - // not. As we do not know what the backend will do, we have to do - // the same in every case, and a minor memory leak is less serious - // (see http://code.google.com/p/corsix-th/issues/detail?id=3). - //SDL_FreeRW(pRWop); - pRWop = NULL; + pMusic = nullptr; } } }; @@ -70,10 +60,10 @@ static int l_init(lua_State *L) { - if(Mix_OpenAudio(luaL_optint(L, 1, MIX_DEFAULT_FREQUENCY), + if(Mix_OpenAudio(static_cast(luaL_optinteger(L, 1, MIX_DEFAULT_FREQUENCY)), MIX_DEFAULT_FORMAT, - luaL_optint(L, 2, MIX_DEFAULT_CHANNELS), - luaL_optint(L, 3, 2048) /* chunk size */) != 0) + static_cast(luaL_optinteger(L, 2, MIX_DEFAULT_CHANNELS)), + static_cast(luaL_optinteger(L, 3, 2048)) /* chunk size */) != 0) { lua_pushboolean(L, 0); lua_pushstring(L, Mix_GetError()); @@ -82,23 +72,26 @@ else { lua_pushboolean(L, 1); - luaT_addcleanup(L, Mix_CloseAudio); Mix_HookMusicFinished(audio_music_over_callback); return 1; } } -struct load_music_async_t +struct load_music_async_data { lua_State* L; Mix_Music* music; SDL_RWops* rwop; char* err; + SDL_Thread* thread; }; -static int l_load_music_async_callback(lua_State *L) +int l_load_music_async_callback(lua_State *L) { - load_music_async_t *async = (load_music_async_t*)lua_touserdata(L, 1); + load_music_async_data *async = (load_music_async_data*)lua_touserdata(L, 1); + + // Frees resources allocated to the thread + SDL_WaitThread(async->thread, nullptr); // Replace light UD with full UD lua_pushvalue(L, 1); @@ -107,27 +100,21 @@ lua_pushnil(L); lua_settable(L, LUA_REGISTRYINDEX); - // Get CB state and function + // Get CB function lua_pushvalue(L, 1); lua_gettable(L, LUA_REGISTRYINDEX); lua_rawgeti(L, -1, 1); - lua_State *cbL = lua_tothread(L, -1); - // NB: cbL may equal L, or it may not - lua_pop(L, 1); - lua_rawgeti(L, -1, 2); - if(L != cbL) - lua_xmove(L, cbL, 1); - // Push CB arg + // Push CB arguments int nargs = 1; - if(async->music == NULL) + if(async->music == nullptr) { - lua_pushnil(cbL); + lua_pushnil(L); if(async->err) { if(*async->err) { - lua_pushstring(cbL, async->err); + lua_pushstring(L, async->err); nargs = 2; } free(async->err); @@ -135,50 +122,38 @@ } else { - lua_rawgeti(L, 2, 3); - if(L != cbL) - lua_xmove(L, cbL, 1); - music_t* pLMusic = (music_t*)lua_touserdata(cbL, -1); + lua_rawgeti(L, 2, 2); + music* pLMusic = (music*)lua_touserdata(L, -1); pLMusic->pMusic = async->music; - pLMusic->pRWop = async->rwop; - async->music = NULL; - async->rwop = NULL; + async->music = nullptr; } // Finish cleanup - if(async->rwop) - SDL_FreeRW(async->rwop); lua_pushvalue(L, 1); lua_pushnil(L); lua_settable(L, LUA_REGISTRYINDEX); // Callback - if(cbL == L) - { - lua_call(cbL, nargs, 0); - return 0; - } - if(lua_pcall(cbL, nargs, 0, 0) != 0) - { - lua_pushliteral(L, "Error in async music load callback: "); - lua_xmove(cbL, L, 1); - lua_tostring(L, -1); - lua_concat(L, 2); - lua_error(L); - } + lua_call(L, nargs, 0); + return 0; } static int load_music_async_thread(void* arg) { - load_music_async_t *async = (load_music_async_t*)arg; - async->music = Mix_LoadMUS_RW(async->rwop); - if(async->music == NULL) - async->err = strdup(Mix_GetError()); + load_music_async_data *async = (load_music_async_data*)arg; + + async->music = Mix_LoadMUS_RW(async->rwop, 1); + async->rwop = nullptr; + if(async->music == nullptr) + { + size_t iLen = std::strlen(Mix_GetError()) + 1; + async->err = (char*)malloc(iLen); + std::memcpy(async->err, Mix_GetError(), iLen); + } SDL_Event e; - e.type = SDL_USEREVENT_CPCALL; - e.user.data1 = (void*)l_load_music_async_callback; - e.user.data2 = arg; + e.type = SDL_USEREVENT_MUSIC_LOADED; + e.user.data1 = arg; SDL_PushEvent(&e); return 0; } @@ -186,62 +161,59 @@ static int l_load_music_async(lua_State *L) { size_t iLength; - const unsigned char *pData = luaT_checkfile(L, 1, &iLength); + const uint8_t *pData = luaT_checkfile(L, 1, &iLength); luaL_checktype(L, 2, LUA_TFUNCTION); SDL_RWops* rwop = SDL_RWFromConstMem(pData, (int)iLength); lua_settop(L, 2); - load_music_async_t *async = luaT_new(L, load_music_async_t); + load_music_async_data *async = luaT_new(L, load_music_async_data); lua_pushlightuserdata(L, async); lua_pushvalue(L, -2); lua_settable(L, LUA_REGISTRYINDEX); async->L = L; - async->music = NULL; + async->music = nullptr; async->rwop = rwop; - async->err = NULL; + async->err = nullptr; lua_createtable(L, 2, 0); - lua_pushthread(L); - lua_rawseti(L, -2, 1); lua_pushvalue(L, 2); - lua_rawseti(L, -2, 2); - luaT_stdnew(L, luaT_environindex, true); + lua_rawseti(L, -2, 1); + luaT_stdnew(L, luaT_environindex, true); lua_pushvalue(L, 1); luaT_setenvfield(L, -2, "data"); - lua_rawseti(L, -2, 3); + lua_rawseti(L, -2, 2); lua_settable(L, LUA_REGISTRYINDEX); /* In registry: [light userdata async] -> [full userdata async] [full userdata async] -> { - [1] = callback_thread, - [2] = callback_function, - [3] = empty music_t userdata, + [1] = callback_function, + [2] = empty music_t userdata, } New thread will load music, and inform the main loop, which will then call the callback and remove the new entries from the registry. */ - SDL_CreateThread(load_music_async_thread, async); + async->thread = SDL_CreateThread(load_music_async_thread, "music_thread", async); + return 0; } static int l_load_music(lua_State *L) { size_t iLength; - const unsigned char *pData = luaT_checkfile(L, 1, &iLength); + const uint8_t *pData = luaT_checkfile(L, 1, &iLength); SDL_RWops* rwop = SDL_RWFromConstMem(pData, (int)iLength); - Mix_Music* pMusic = Mix_LoadMUS_RW(rwop); - if(pMusic == NULL) + Mix_Music* pMusic = Mix_LoadMUS_RW(rwop, 1); + if(pMusic == nullptr) { lua_pushnil(L); lua_pushstring(L, Mix_GetError()); return 2; } - music_t* pLMusic = luaT_stdnew(L, luaT_environindex, true); + music* pLMusic = luaT_stdnew(L, luaT_environindex, true); pLMusic->pMusic = pMusic; - pLMusic->pRWop = rwop; lua_pushvalue(L, 1); luaT_setenvfield(L, -2, "data"); return 1; @@ -262,8 +234,8 @@ static int l_play_music(lua_State *L) { - music_t* pLMusic = luaT_testuserdata(L); - if(Mix_PlayMusic(pLMusic->pMusic, luaL_optint(L, 2, 1)) != 0) + music* pLMusic = luaT_testuserdata(L, -1); + if(Mix_PlayMusic(pLMusic->pMusic, static_cast(luaL_optinteger(L, 2, 1))) != 0) { lua_pushnil(L); lua_pushstring(L, Mix_GetError()); @@ -296,10 +268,10 @@ static int l_transcode_xmi(lua_State *L) { size_t iLength, iMidLength; - const unsigned char *pData = luaT_checkfile(L, 1, &iLength); + const uint8_t *pData = luaT_checkfile(L, 1, &iLength); - unsigned char *pMidData = TranscodeXmiToMid(pData, iLength, &iMidLength); - if(pMidData == NULL) + uint8_t *pMidData = transcode_xmi_to_midi(pData, iLength, &iMidLength); + if(pMidData == nullptr) { lua_pushnil(L); lua_pushliteral(L, "Unable to transcode XMI to MIDI"); @@ -311,13 +283,13 @@ return 1; } -static const struct luaL_reg sdl_audiolib[] = { +static const struct luaL_Reg sdl_audiolib[] = { {"init", l_init}, {"transcodeXmiToMid", l_transcode_xmi}, - {NULL, NULL} + {nullptr, nullptr} }; -static const struct luaL_reg sdl_musiclib[] = { +static const struct luaL_Reg sdl_musiclib[] = { {"loadMusic", l_load_music}, {"loadMusicAsync", l_load_music_async}, {"playMusic", l_play_music}, @@ -325,13 +297,13 @@ {"pauseMusic", l_pause_music}, {"resumeMusic", l_resume_music}, {"setMusicVolume", l_music_volume}, - {NULL, NULL} + {nullptr, nullptr} }; int luaopen_sdl_audio(lua_State *L) { lua_newtable(L); - luaL_register(L, NULL, sdl_audiolib); + luaT_setfuncs(L, sdl_audiolib); lua_pushboolean(L, 1); lua_setfield(L, -2, "loaded"); @@ -339,12 +311,12 @@ lua_pushvalue(L, -1); lua_replace(L, luaT_environindex); lua_pushvalue(L, luaT_environindex); - lua_pushcclosure(L, luaT_stdgc, 1); + luaT_pushcclosure(L, luaT_stdgc, 1); lua_setfield(L, -2, "__gc"); lua_pushvalue(L, 1); lua_setfield(L, -2, "__index"); lua_pop(L, 1); - luaT_register(L, NULL, sdl_musiclib); + luaT_setfuncs(L, sdl_musiclib); return 1; } @@ -360,4 +332,9 @@ return 1; } +int l_load_music_async_callback(lua_State *L) +{ + return 0; +} + #endif // CORSIX_TH_USE_SDL_MIXER diff -Nru corsix-th-0.30/CorsixTH/Src/sdl_core.cpp corsix-th-0.62/CorsixTH/Src/sdl_core.cpp --- corsix-th-0.30/CorsixTH/Src/sdl_core.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/sdl_core.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -23,12 +23,9 @@ #include "config.h" #include "lua_sdl.h" #include "th_lua.h" -#include -#ifndef _MSC_VER -#define stricmp strcasecmp -#else -#pragma warning (disable: 4996) // CRT deprecation -#endif +#include +#include +#include static int l_init(lua_State *L) { @@ -38,24 +35,24 @@ for(i = 1; i <= argc; ++i) { const char* s = luaL_checkstring(L, i); - if(stricmp(s, "video") == 0) + if(std::strcmp(s, "video") == 0) flags |= SDL_INIT_VIDEO; - else if(stricmp(s, "audio") == 0) + else if(std::strcmp(s, "audio") == 0) flags |= SDL_INIT_AUDIO; - else if(stricmp(s, "timer") == 0) + else if(std::strcmp(s, "timer") == 0) flags |= SDL_INIT_TIMER; - else if(stricmp(s, "*") == 0) + else if(std::strcmp(s, "*") == 0) flags |= SDL_INIT_EVERYTHING; else luaL_argerror(L, i, "Expected SDL part name"); } if(SDL_Init(flags) != 0) { + std::fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); lua_pushboolean(L, 0); return 1; } - SDL_EnableUNICODE(1); - luaT_addcleanup(L, SDL_Quit); + lua_pushboolean(L, 1); return 1; } @@ -91,9 +88,9 @@ { Uint32 now = SDL_GetTicks(); frame_time[q_front] = now; - q_front = (q_front + 1) % (sizeof(frame_time) / sizeof(*frame_time)); + q_front = (q_front + 1) % static_cast((sizeof(frame_time) / sizeof(*frame_time))); if(q_front == q_back) - q_back = (q_back + 1) % (sizeof(frame_time) / sizeof(*frame_time)); + q_back = (q_back + 1) % static_cast((sizeof(frame_time) / sizeof(*frame_time))); else ++frame_count; if(now < 1000) @@ -103,39 +100,40 @@ while(frame_time[q_back] < now) { --frame_count; - q_back = (q_back + 1) % (sizeof(frame_time) / sizeof(*frame_time)); + q_back = (q_back + 1) % static_cast((sizeof(frame_time) / sizeof(*frame_time))); } } }; -static void l_push_utf8(lua_State *L, uint32_t iCodePoint) +static void l_push_modifiers_table(lua_State *L, Uint16 mod) { - uint8_t aBytes[4]; - size_t iNBytes = 1; - if(iCodePoint <= 0x7F) - aBytes[0] = static_cast(iCodePoint); - else if(iCodePoint <= 0x7FF) - { - aBytes[0] = 0xC0 | static_cast(iCodePoint >> 6); - aBytes[1] = 0x80 | static_cast(iCodePoint & 0x3F); - iNBytes = 2; - } - else if(iCodePoint <= 0xFFFF) - { - aBytes[0] = 0xE0 | static_cast(iCodePoint >> 12); - aBytes[1] = 0x80 | static_cast((iCodePoint >> 6) & 0x3F); - aBytes[2] = 0x80 | static_cast(iCodePoint & 0x3F); - iNBytes = 3; + lua_newtable(L); + if ((mod & KMOD_SHIFT) != 0) + { + luaT_pushtablebool(L, "shift", true); } - else + if ((mod & KMOD_ALT) != 0) + { + luaT_pushtablebool(L, "alt", true); + } + if ((mod & KMOD_CTRL) != 0) + { + luaT_pushtablebool(L, "ctrl", true); + } + if ((mod & KMOD_GUI) != 0) + { + luaT_pushtablebool(L, "gui", true); + } + if ((mod & KMOD_NUM) != 0) { - aBytes[0] = 0xF0 | static_cast(iCodePoint >> 18); - aBytes[1] = 0x80 | static_cast((iCodePoint >> 12) & 0x3F); - aBytes[2] = 0x80 | static_cast((iCodePoint >> 6) & 0x3F); - aBytes[3] = 0x80 | static_cast(iCodePoint & 0x3F); - iNBytes = 4; + luaT_pushtablebool(L, "numlockactive", true); } - lua_pushlstring(L, reinterpret_cast(aBytes), iNBytes); +} + +static int l_get_key_modifiers(lua_State *L) +{ + l_push_modifiers_table(L, SDL_GetModState()); + return 1; } static int l_mainloop(lua_State *L) @@ -143,8 +141,8 @@ luaL_checktype(L, 1, LUA_TTHREAD); lua_State *dispatcher = lua_tothread(L, 1); - fps_ctrl *fps_control = (fps_ctrl*)lua_touserdata(L, lua_upvalueindex(1)); - SDL_TimerID timer = SDL_AddTimer(30, timer_frame_callback, NULL); + fps_ctrl *fps_control = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1)); + SDL_TimerID timer = SDL_AddTimer(30, timer_frame_callback, nullptr); SDL_Event e; while(SDL_WaitEvent(&e) != 0) @@ -160,16 +158,28 @@ goto leave_loop; case SDL_KEYDOWN: lua_pushliteral(dispatcher, "keydown"); - lua_pushinteger(dispatcher, e.key.keysym.sym); - l_push_utf8(dispatcher, e.key.keysym.unicode); - nargs = 3; + lua_pushstring(dispatcher, SDL_GetKeyName(e.key.keysym.sym)); + l_push_modifiers_table(dispatcher, e.key.keysym.mod); + lua_pushboolean(dispatcher, e.key.repeat != 0); + nargs = 4; break; case SDL_KEYUP: lua_pushliteral(dispatcher, "keyup"); - lua_pushinteger(dispatcher, e.key.keysym.sym); - // NB: No unicode translation done by SDL for keyup + lua_pushstring(dispatcher, SDL_GetKeyName(e.key.keysym.sym)); + nargs = 2; + break; + case SDL_TEXTINPUT: + lua_pushliteral(dispatcher, "textinput"); + lua_pushstring(dispatcher, e.text.text); nargs = 2; break; + case SDL_TEXTEDITING: + lua_pushliteral(dispatcher, "textediting"); + lua_pushstring(dispatcher, e.edit.text); + lua_pushinteger(dispatcher, e.edit.start); + lua_pushinteger(dispatcher, e.edit.length); + nargs = 4; + break; case SDL_MOUSEBUTTONDOWN: lua_pushliteral(dispatcher, "buttondown"); lua_pushinteger(dispatcher, e.button.button); @@ -184,6 +194,12 @@ lua_pushinteger(dispatcher, e.button.y); nargs = 4; break; + case SDL_MOUSEWHEEL: + lua_pushliteral(dispatcher, "mousewheel"); + lua_pushinteger(dispatcher, e.wheel.x); + lua_pushinteger(dispatcher, e.wheel.y); + nargs = 3; + break; case SDL_MOUSEMOTION: lua_pushliteral(dispatcher, "motion"); lua_pushinteger(dispatcher, e.motion.x); @@ -192,17 +208,44 @@ lua_pushinteger(dispatcher, e.motion.yrel); nargs = 5; break; - case SDL_ACTIVEEVENT: - lua_pushliteral(dispatcher, "active"); - lua_pushinteger(dispatcher, e.active.gain); - nargs = 2; + case SDL_MULTIGESTURE: + lua_pushliteral(dispatcher, "multigesture"); + lua_pushinteger(dispatcher, e.mgesture.numFingers); + lua_pushnumber(dispatcher, e.mgesture.dTheta); + lua_pushnumber(dispatcher, e.mgesture.dDist); + lua_pushnumber(dispatcher, e.mgesture.x); + lua_pushnumber(dispatcher, e.mgesture.y); + nargs = 6; + break; + case SDL_WINDOWEVENT: + switch (e.window.event) { + case SDL_WINDOWEVENT_FOCUS_GAINED: + lua_pushliteral(dispatcher, "active"); + lua_pushinteger(dispatcher, 1); + nargs = 2; + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + lua_pushliteral(dispatcher, "active"); + lua_pushinteger(dispatcher, 0); + nargs = 2; + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + lua_pushliteral(dispatcher, "window_resize"); + lua_pushinteger(dispatcher, e.window.data1); + lua_pushinteger(dispatcher, e.window.data2); + nargs = 3; + break; + default: + nargs = 0; + break; + } break; case SDL_USEREVENT_MUSIC_OVER: lua_pushliteral(dispatcher, "music_over"); nargs = 1; break; - case SDL_USEREVENT_CPCALL: - if(luaT_cpcall(L, (lua_CFunction)e.user.data1, e.user.data2)) + case SDL_USEREVENT_MUSIC_LOADED: + if(luaT_cpcall(L, (lua_CFunction)l_load_music_async_callback, e.user.data1)) { SDL_RemoveTimer(timer); lua_pushliteral(L, "callback"); @@ -218,13 +261,18 @@ lua_pushliteral(dispatcher, "movie_over"); nargs = 1; break; + case SDL_USEREVENT_SOUND_OVER: + lua_pushliteral(dispatcher, "sound_over"); + lua_pushinteger(dispatcher, *(static_cast(e.user.data1))); + nargs = 2; + break; default: nargs = 0; break; } if(nargs != 0) { - if(lua_resume(dispatcher, nargs) != LUA_YIELD) + if(luaT_resume(dispatcher, dispatcher, nargs) != LUA_YIELD) { goto leave_loop; } @@ -235,7 +283,7 @@ if(do_timer) { lua_pushliteral(dispatcher, "timer"); - if(lua_resume(dispatcher, 1) != LUA_YIELD) + if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD) { break; } @@ -251,12 +299,12 @@ fps_control->count_frame(); } lua_pushliteral(dispatcher, "frame"); - if(lua_resume(dispatcher, 1) != LUA_YIELD) + if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD) { goto leave_loop; } lua_settop(dispatcher, 0); - } while(fps_control->limit_fps == false && SDL_PollEvent(NULL) == 0); + } while(fps_control->limit_fps == false && SDL_PollEvent(nullptr) == 0); } // No events pending - a good time to do a bit of garbage collection @@ -277,21 +325,21 @@ static int l_track_fps(lua_State *L) { - fps_ctrl *ctrl = (fps_ctrl*)lua_touserdata(L, lua_upvalueindex(1)); + fps_ctrl *ctrl = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1)); ctrl->track_fps = lua_isnone(L, 1) ? true : (lua_toboolean(L, 1) != 0); return 0; } static int l_limit_fps(lua_State *L) { - fps_ctrl *ctrl = (fps_ctrl*)lua_touserdata(L, lua_upvalueindex(1)); + fps_ctrl *ctrl = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1)); ctrl->limit_fps = lua_isnone(L, 1) ? true : (lua_toboolean(L, 1) != 0); return 0; } static int l_get_fps(lua_State *L) { - fps_ctrl *ctrl = (fps_ctrl*)lua_touserdata(L, lua_upvalueindex(1)); + fps_ctrl *ctrl = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1)); if(ctrl->track_fps) { lua_pushinteger(L, ctrl->frame_count); @@ -309,35 +357,27 @@ return 1; } -/* - Enable or disable the keyboard modifier. - - Takes two parameters: delay and interval. Both are integers in miliseconds - where nil gives default values, and delay of 0 disables the repeat. -*/ -static int l_modify_keyboardrepeat(lua_State *L) -{ - int delay = luaL_optint(L, 1, SDL_DEFAULT_REPEAT_DELAY); - int interval = luaL_optint(L, 2, SDL_DEFAULT_REPEAT_INTERVAL); - - lua_pushboolean(L, SDL_EnableKeyRepeat(delay, interval) == 0 ? 1 : 0); - return 1; -} - -static const struct luaL_reg sdllib[] = { +static const std::vector sdllib = { {"init", l_init}, {"getTicks", l_get_ticks}, - {"modifyKeyboardRepeat", l_modify_keyboardrepeat}, - {NULL, NULL} + {"getKeyModifiers", l_get_key_modifiers}, + {nullptr, nullptr} }; -static const struct luaL_reg sdllib_with_upvalue[] = { +static const std::vector sdllib_with_upvalue = { {"mainloop", l_mainloop}, {"getFPS", l_get_fps}, {"trackFPS", l_track_fps}, {"limitFPS", l_limit_fps}, - {NULL, NULL} + {nullptr, nullptr} }; +inline void load_extra(lua_State *L, const char *name, lua_CFunction fn) +{ + luaT_pushcfunction(L, fn); + lua_call(L, 0, 1); + lua_setfield(L, -2, name); +} + int luaopen_sdl_audio(lua_State *L); int luaopen_sdl_wm(lua_State *L); @@ -345,24 +385,16 @@ { fps_ctrl* ctrl = (fps_ctrl*)lua_newuserdata(L, sizeof(fps_ctrl)); ctrl->init(); - luaL_register(L, "sdl", sdllib); - const luaL_Reg *pUpvaluedFunctions = sdllib_with_upvalue; - for(; pUpvaluedFunctions->name; ++pUpvaluedFunctions) + luaT_register(L, "sdl", sdllib); + for (auto reg = sdllib_with_upvalue.begin(); reg->name; ++reg) { lua_pushvalue(L, -2); - lua_pushcclosure(L, pUpvaluedFunctions->func, 1); - lua_setfield(L, -2, pUpvaluedFunctions->name); + luaT_pushcclosure(L, reg->func, 1); + lua_setfield(L, -2, reg->name); } -#define LOAD_EXTRA(name, fn) \ - luaT_pushcfunction(L, fn); \ - lua_call(L, 0, 1); \ - lua_setfield(L, -2, name) - - LOAD_EXTRA("audio", luaopen_sdl_audio); - LOAD_EXTRA("wm", luaopen_sdl_wm); - -#undef LOAD_EXTRA + load_extra(L, "audio", luaopen_sdl_audio); + load_extra(L, "wm", luaopen_sdl_wm); return 1; } diff -Nru corsix-th-0.30/CorsixTH/Src/sdl_wm.cpp corsix-th-0.62/CorsixTH/Src/sdl_wm.cpp --- corsix-th-0.30/CorsixTH/Src/sdl_wm.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/sdl_wm.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -21,6 +21,7 @@ */ #include "config.h" +#include "th_lua.h" #include "lua_sdl.h" #ifdef CORSIX_TH_USE_WIN32_SDK #include @@ -28,27 +29,22 @@ #include "../resource.h" #endif -static int l_set_caption(lua_State *L) -{ - SDL_WM_SetCaption(luaL_checkstring(L, 1), NULL); - return 0; -} - static int l_set_icon_win32(lua_State *L) { // Hack to set the window icon from the EXE resource under Windows. // Does nothing (and returns false) on other platforms. lua_pushboolean(L, 0); -#ifdef CORSIX_TH_USE_WIN32_SDK +#if 0 + // XXX: Doesn't work any more, since window is inside renderer. Move to renderer. SDL_SysWMinfo oWindowInfo; oWindowInfo.version.major = SDL_MAJOR_VERSION; oWindowInfo.version.minor = SDL_MINOR_VERSION; oWindowInfo.version.patch = SDL_PATCHLEVEL; - if(SDL_GetWMInfo(&oWindowInfo) == 1) + if(SDL_GetWindowWMInfo(window,&oWindowInfo) == 1) { - HWND hWindow = oWindowInfo.window; - HICON hIcon = LoadIcon((HINSTANCE)GetModuleHandle(NULL), (LPCTSTR)IDI_CORSIXTH); + HWND hWindow = oWindowInfo.info.win.window; + HICON hIcon = LoadIcon((HINSTANCE)GetModuleHandle(nullptr), (LPCTSTR)IDI_CORSIXTH); SetClassLongPtr(hWindow, GCLP_HICON, (LONG_PTR)hIcon); SetClassLongPtr(hWindow, GCLP_HICONSM, (LONG_PTR)hIcon); lua_pushboolean(L, 1); @@ -63,17 +59,16 @@ return 0; } -static const struct luaL_reg sdl_wmlib[] = { +static const struct luaL_Reg sdl_wmlib[] = { {"setIconWin32", l_set_icon_win32}, - {"setCaption", l_set_caption}, {"showCursor", l_show_cursor}, - {NULL, NULL} + {nullptr, nullptr} }; int luaopen_sdl_wm(lua_State *L) { lua_newtable(L); - luaL_register(L, NULL, sdl_wmlib); + luaT_setfuncs(L, sdl_wmlib); return 1; } diff -Nru corsix-th-0.30/CorsixTH/Src/shaders/blue_filter.psh corsix-th-0.62/CorsixTH/Src/shaders/blue_filter.psh --- corsix-th-0.30/CorsixTH/Src/shaders/blue_filter.psh 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/shaders/blue_filter.psh 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/* -Copyright (c) 2013 Edvin "Lego3" Linge - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -// Pixel shader input structure -struct PS_INPUT -{ - float2 Texture : TEXCOORD0; -}; - - -// Pixel shader output structure -struct PS_OUTPUT -{ - float4 Color : COLOR0; -}; - - -// Global variables -sampler2D Tex0; - - -// Name: Simple Pixel Shader -// Type: Pixel shader -// Desc: Fetch texture and blend with constant color -// -PS_OUTPUT ps_main( in PS_INPUT In ) -{ - PS_OUTPUT Out; //create an output pixel - - Out.Color = tex2D(Tex0, In.Texture); //do a texture lookup - Out.Color *= float4(0.7f, 0.7f, 1.0f, 1); //do a simple effect (blue color) - - return Out; //return output pixel -} \ No newline at end of file diff -Nru corsix-th-0.30/CorsixTH/Src/th.cpp corsix-th-0.62/CorsixTH/Src/th.cpp --- corsix-th-0.30/CorsixTH/Src/th.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -22,55 +22,39 @@ #include "config.h" #include "th.h" -#include -#include -#include +#include +#include -THLinkList::THLinkList() +link_list::link_list() { - m_drawingLayer = 0; - m_pPrev = NULL; - m_pNext = NULL; + drawing_layer = 0; + prev = nullptr; + next = nullptr; } -THLinkList::~THLinkList() +link_list::~link_list() { - removeFromList(); + remove_from_list(); } -void THLinkList::removeFromList() +void link_list::remove_from_list() { - if(m_pPrev != NULL) + if(prev != nullptr) { - m_pPrev->m_pNext = m_pNext; + prev->next = next; } - if(m_pNext != NULL) + if(next != nullptr) { - m_pNext->m_pPrev = m_pPrev; - m_pNext = NULL; + next->prev = prev; + next = nullptr; } - m_pPrev = NULL; -} - -THStringList::THStringList() -{ - m_iSectionCount = 0; - m_pSections = NULL; - m_sData = NULL; -} - -THStringList::~THStringList() -{ - for(unsigned int i = 0; i < m_iSectionCount; ++i) - delete[] m_pSections[i].pStrings; - delete[] m_pSections; - delete[] m_sData; + prev = nullptr; } #include "cp437_table.h" #include "cp936_table.h" -static void utf8encode(unsigned char*& sOut, uint32_t iCodepoint) +static void utf8encode(uint8_t*& sOut, uint32_t iCodepoint) { if(iCodepoint <= 0x7F) { @@ -79,50 +63,42 @@ } else if(iCodepoint <= 0x7FF) { - unsigned char cSextet = iCodepoint & 0x3F; + uint8_t cSextet = iCodepoint & 0x3F; iCodepoint >>= 6; - sOut[0] = 0xC0 + iCodepoint; - sOut[1] = 0x80 + cSextet; + sOut[0] = static_cast(0xC0 + iCodepoint); + sOut[1] = static_cast(0x80 + cSextet); sOut += 2; } else if(iCodepoint <= 0xFFFF) { - unsigned char cSextet2 = iCodepoint & 0x3F; + uint8_t cSextet2 = iCodepoint & 0x3F; iCodepoint >>= 6; - unsigned char cSextet1 = iCodepoint & 0x3F; + uint8_t cSextet1 = iCodepoint & 0x3F; iCodepoint >>= 6; - sOut[0] = 0xE0 + iCodepoint; - sOut[1] = 0x80 + cSextet1; - sOut[2] = 0x80 + cSextet2; + sOut[0] = static_cast(0xE0 + iCodepoint); + sOut[1] = static_cast(0x80 + cSextet1); + sOut[2] = static_cast(0x80 + cSextet2); sOut += 3; } else { - unsigned char cSextet3 = iCodepoint & 0x3F; + uint8_t cSextet3 = iCodepoint & 0x3F; iCodepoint >>= 6; - unsigned char cSextet2 = iCodepoint & 0x3F; + uint8_t cSextet2 = iCodepoint & 0x3F; iCodepoint >>= 6; - unsigned char cSextet1 = iCodepoint & 0x3F; + uint8_t cSextet1 = iCodepoint & 0x3F; iCodepoint >>= 6; - sOut[0] = 0xF0 + iCodepoint; - sOut[1] = 0x80 + cSextet1; - sOut[2] = 0x80 + cSextet2; - sOut[3] = 0x80 + cSextet3; + sOut[0] = static_cast(0xF0 + iCodepoint); + sOut[1] = static_cast(0x80 + cSextet1); + sOut[2] = static_cast(0x80 + cSextet2); + sOut[3] = static_cast(0x80 + cSextet3); sOut += 4; } } -static void CopyStringId(const unsigned char*& sIn, unsigned char*& sOut) -{ - size_t iLength = strlen(reinterpret_cast(sIn)) + 1; - memcpy(sOut, sIn, iLength); - sIn += iLength; - sOut += iLength; -} - -static void CopyStringCP437(const unsigned char*& sIn, unsigned char*& sOut) +static void CopyStringCP437(const uint8_t*& sIn, uint8_t*& sOut) { - unsigned char cChar; + uint8_t cChar; do { cChar = *sIn; @@ -134,14 +110,14 @@ } else { - utf8encode(sOut, g_aCP437toUnicode[cChar - 0x80]); + utf8encode(sOut, cp437_to_unicode_table[cChar - 0x80]); } } while(cChar != 0); } -static void CopyStringCP936(const unsigned char*& sIn, unsigned char*& sOut) +static void CopyStringCP936(const uint8_t*& sIn, uint8_t*& sOut) { - unsigned char cChar1, cChar2; + uint8_t cChar1, cChar2; do { cChar1 = *sIn; @@ -157,7 +133,7 @@ ++sIn; if(0x40 <= cChar2 && cChar2 <= 0xFE) { - utf8encode(sOut, g_aCP936toUnicode[cChar1-0x81][cChar2-0x40]); + utf8encode(sOut, cp936_to_unicode_table[cChar1-0x81][cChar2-0x40]); // The Theme Hospital string tables seem to like following a // multibyte character with a superfluous space. cChar2 = *sIn; @@ -175,89 +151,78 @@ } while(cChar1 != 0); } -bool THStringList::loadFromTHFile(const unsigned char* pData, size_t iDataLength) +th_string_list::th_string_list(const uint8_t* data, size_t length) { - for(unsigned int i = 0; i < m_iSectionCount; ++i) - delete[] m_pSections[i].pStrings; - delete[] m_pSections; - delete[] m_sData; - m_pSections = NULL; - m_sData = NULL; - m_iSectionCount = 0; + if(length < 2) + throw std::invalid_argument("length must be 2 or larger"); - if(iDataLength < 2) - return false; + size_t iSectionCount = *reinterpret_cast(data); + size_t iHeaderLength = (iSectionCount + 1) * 2; - unsigned int iSectionCount = *reinterpret_cast(pData); - unsigned int iHeaderLength = (iSectionCount + 1) * 2; + if(length < iHeaderLength) + throw std::invalid_argument("iDataLength must be larger than the header"); - if(iDataLength < iHeaderLength) - return false; + size_t iStringDataLength = length - iHeaderLength; + const uint8_t *sStringData = data + iHeaderLength; + const uint8_t *sDataEnd = sStringData + iStringDataLength; // Determine whether the encoding is CP437 or GB2312 (CP936). // The range of bytes 0xB0 through 0xDF are box drawing characters in CP437 // which shouldn't occur much (if ever) in TH strings, whereas they are - // commonly used in GB2312 encoding. - const unsigned char *sStringData = pData + iHeaderLength; - size_t iStringDataLength = iDataLength - iHeaderLength; + // commonly used in GB2312 encoding. We use 10% as a threshold. size_t iBCDCount = 0; for(size_t i = 0; i < iStringDataLength; ++i) { if(0xB0 <= sStringData[i] && sStringData[i] <= 0xDF) ++iBCDCount; } - void (*fnCopyString)(const unsigned char*&, unsigned char*&); + void (*fnCopyString)(const uint8_t*&, uint8_t*&); if(iBCDCount * 10 >= iStringDataLength) fnCopyString = CopyStringCP936; else fnCopyString = CopyStringCP437; - m_sData = new (std::nothrow) unsigned char[iStringDataLength * 2 + 2]; - if(m_sData == NULL) - return false; - - unsigned char *sDataOut = m_sData; - const unsigned char *sDataEnd = sStringData + iStringDataLength; - - m_iSectionCount = iSectionCount; - m_pSections = new section_t[iSectionCount]; - for(unsigned int i = 0; i < iSectionCount; ++i) - { - m_pSections[i].iSize = reinterpret_cast(pData)[i + 1]; - m_pSections[i].pStrings = new const char*[m_pSections[i].iSize]; - - for(unsigned int j = 0; j < m_pSections[i].iSize; ++j) + // String buffer sized to accept the largest possible reencoding of the + // characters interpreted as CP936 or CP437 (2 bytes per character). + string_buffer.resize(iStringDataLength * 2 + 2); + + uint8_t *sDataOut = string_buffer.data(); + sections.resize(iSectionCount); + for(size_t i = 0; i < iSectionCount; ++i) + { + size_t section_size = reinterpret_cast(data)[i + 1]; + sections[i].reserve(section_size); + for(size_t j = 0; j < section_size; ++j) { - m_pSections[i].pStrings[j] = reinterpret_cast(sDataOut); + sections[i].push_back(reinterpret_cast(sDataOut)); if(sStringData != sDataEnd) { fnCopyString(sStringData, sDataOut); } } } + // Terminate final string with nil character *sDataOut = 0; - - return true; } -unsigned int THStringList::getSectionCount() +th_string_list::~th_string_list() +{} + +size_t th_string_list::get_section_count() { - return m_iSectionCount; + return sections.size(); } -unsigned int THStringList::getSectionSize(unsigned int iSection) +size_t th_string_list::get_section_size(size_t section) { - return iSection < m_iSectionCount ? m_pSections[iSection].iSize : 0; + return section < sections.size() ? sections[section].size() : 0; } -const char* THStringList::getString(unsigned int iSection, unsigned int iIndex) +const char* th_string_list::get_string(size_t section, size_t index) { - if(iSection < m_iSectionCount) + if(index < get_section_size(section)) { - if(iIndex < m_pSections[iSection].iSize) - { - return m_pSections[iSection].pStrings[iIndex]; - } + return sections[section][index]; } - return NULL; + return nullptr; } diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx.cpp corsix-th-0.62/CorsixTH/Src/th_gfx.cpp --- corsix-th-0.30/CorsixTH/Src/th_gfx.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -27,299 +27,815 @@ #include "th_sound.h" #include #include -#include -#include +#include +#include +#include -THAnimationManager::THAnimationManager() +/** Data retrieval class, simulating sequential access to the data, keeping track of available length. */ +class memory_reader { - m_pFirstFrames = NULL; - m_pFrames = NULL; - m_pElementList = NULL; - m_pElements = NULL; - m_pSpriteSheet = NULL; - m_iAnimationCount = 0; - m_iFrameCount = 0; +public: + memory_reader(const uint8_t *pData, size_t iLength) + { + data = pData; + remaining_bytes = iLength; + } + + const uint8_t *data; ///< Pointer to the remaining data. + size_t remaining_bytes; ///< Remaining number of bytes. + + //! Can \a iSize bytes be read from the file? + /*! + @param iSize Number of bytes that are queried. + @return Whether the requested number of bytes is still available. + */ + bool are_bytes_available(size_t iSize) + { + return iSize <= remaining_bytes; + } + + //! Is EOF reached? + /*! + @return Whether EOF has been reached. + */ + bool is_at_end_of_file() + { + return remaining_bytes == 0; + } + + //! Get an 8 bit value from the file. + /*! + @return Read 8 bit value. + @pre There should be at least a byte available for reading. + */ + uint8_t read_uint8() + { + assert(remaining_bytes > 0); + + uint8_t iVal = *data; + data++; + remaining_bytes--; + return iVal; + } + + //! Get a 16 bit value from the file. + /*! + @return Read 16 bit value. + @pre There should be at least 2 bytes available for reading. + */ + uint16_t read_uint16() + { + uint16_t iVal = read_uint8(); + uint16_t iVal2 = read_uint8(); + return static_cast(iVal | (iVal2 << 8)); + } + + //! Get a signed 16 bit value from the file. + /*! + @return The read signed 16 bit value. + @pre There should be at least 2 bytes available for reading. + */ + int read_int16() + { + int val = read_uint16(); + if (val < 0x7FFF) + return val; + + int ret = -1; + return (ret & ~0xFFFF) | val; + } + + //! Get a 32 bit value from the file. + /*! + @return Read 32 bit value. + @pre There should be at least 4 bytes available for reading. + */ + uint32_t read_uint32() + { + uint32_t iVal = read_uint16(); + uint32_t iVal2 = read_uint16(); + return iVal | (iVal2 << 16); + } + + //! Load string from the memory_reader. + /*! + @param [out] pStr String to load. + @return Whether the string could be loaded. + */ + bool read_string(std::string *pStr) + { + char buff[256]; + + if (is_at_end_of_file()) + return false; + + size_t iLength = read_uint8(); + if (!are_bytes_available(iLength)) + return false; + + size_t idx; + for (idx = 0; idx < iLength; idx++) + buff[idx] = read_uint8(); + buff[idx] = '\0'; + *pStr = std::string(buff); + return true; + } +}; + +animation_manager::animation_manager() +{ + first_frames.clear(); + frames.clear(); + element_list.clear(); + elements.clear(); + custom_sheets.clear(); + + sheet = nullptr; + + animation_count = 0; + frame_count = 0; + element_list_count = 0; + element_count = 0; +} + +animation_manager::~animation_manager() +{ + for (size_t i = 0; i < custom_sheets.size(); i++) + delete custom_sheets[i]; } -THAnimationManager::~THAnimationManager() +void animation_manager::set_sprite_sheet(sprite_sheet* pSpriteSheet) { - delete[] m_pFirstFrames; - delete[] m_pFrames; - delete[] m_pElementList; - delete[] m_pElements; + sheet = pSpriteSheet; } -void THAnimationManager::setSpriteSheet(THSpriteSheet* pSpriteSheet) +bool animation_manager::load_from_th_file( + const uint8_t* pStartData, size_t iStartDataLength, + const uint8_t* pFrameData, size_t iFrameDataLength, + const uint8_t* pListData, size_t iListDataLength, + const uint8_t* pElementData, size_t iElementDataLength) { - m_pSpriteSheet = pSpriteSheet; + size_t iAnimationCount = iStartDataLength / sizeof(th_animation_properties); + size_t iFrameCount = iFrameDataLength / sizeof(th_frame_properties); + size_t iListCount = iListDataLength / 2; + size_t iElementCount = iElementDataLength / sizeof(th_element_properties); + + if(iAnimationCount == 0 || iFrameCount == 0 || iListCount == 0 || iElementCount == 0) + return false; + + // Start offset of the file data into the vectors. + size_t iAnimationStart = animation_count; + size_t iFrameStart = frame_count; + size_t iListStart = element_list_count; + size_t iElementStart = element_count; + + // Original data file must start at offset 0 due to the hard-coded animation numbers in the Lua code. + if (iAnimationStart > 0 || iFrameStart > 0 || iListStart > 0 || iElementStart > 0) + return false; + + if (iElementStart + iElementCount >= 0xFFFF) // Overflow of list elements. + return false; + + // Create new space for the data. + first_frames.reserve(iAnimationStart + iAnimationCount); + frames.reserve(iFrameStart + iFrameCount); + element_list.reserve(iListStart + iListCount + 1); + elements.reserve(iElementStart + iElementCount); + + // Read animations. + for(size_t i = 0; i < iAnimationCount; ++i) + { + size_t iFirstFrame = reinterpret_cast(pStartData)[i].first_frame; + if(iFirstFrame > iFrameCount) + iFirstFrame = 0; + + iFirstFrame += iFrameStart; + first_frames.push_back(iFirstFrame); + } + + // Read frames. + for(size_t i = 0; i < iFrameCount; ++i) + { + const th_frame_properties* pFrame = reinterpret_cast(pFrameData) + i; + + frame oFrame; + oFrame.list_index = iListStart + (pFrame->list_index < iListCount ? pFrame->list_index : 0); + oFrame.next_frame = iFrameStart + (pFrame->next < iFrameCount ? pFrame->next : 0); + oFrame.sound = pFrame->sound; + oFrame.flags = pFrame->flags; + // Bounding box fields initialised later + oFrame.marker_x = 0; + oFrame.marker_y = 0; + oFrame.secondary_marker_x = 0; + oFrame.secondary_marker_y = 0; + + frames.push_back(oFrame); + } + + // Read element list. + for(size_t i = 0; i < iListCount; ++i) + { + uint16_t iElmNumber = *(reinterpret_cast(pListData) + i); + if (iElmNumber >= iElementCount) + { + iElmNumber = 0xFFFF; + } + else + { + iElmNumber = static_cast(iElmNumber + iElementStart); + } + + element_list.push_back(iElmNumber); + } + element_list.push_back(0xFFFF); + + // Read elements. + size_t iSpriteCount = sheet->get_sprite_count(); + for(size_t i = 0; i < iElementCount; ++i) + { + const th_element_properties* pTHElement = reinterpret_cast(pElementData) + i; + + element oElement; + oElement.sprite = pTHElement->table_position / 6; + oElement.flags = pTHElement->flags & 0xF; + oElement.x = static_cast(pTHElement->offx) - 141; + oElement.y = static_cast(pTHElement->offy) - 186; + oElement.layer = static_cast(pTHElement->flags >> 4); // High nibble, layer of the element. + if(oElement.layer > 12) + oElement.layer = 6; // Nothing lives on layer 6 + oElement.layer_id = pTHElement->layerid; + if (oElement.sprite < iSpriteCount) { + oElement.element_sprite_sheet = sheet; + } else { + oElement.element_sprite_sheet = nullptr; + } + + elements.push_back(oElement); + } + + // Compute bounding box of the animations using the sprite sheet. + for(size_t i = 0; i < iFrameCount; ++i) + { + set_bounding_box(frames[iFrameStart + i]); + } + + animation_count += iAnimationCount; + frame_count += iFrameCount; + element_list_count += iListCount + 1; + element_count += iElementCount; + + assert(first_frames.size() == animation_count); + assert(frames.size() == frame_count); + assert(element_list.size() == element_list_count); + assert(elements.size() == element_count); + + return true; } -inline static void _setmin(int& iLeft, int iRight) +//! Update \a iLeft with the smallest of both values. +/*! + @param [inout] iLeft Left value to check and update. + @param iRight Second value to check. + */ +static void set_left_to_min(int& iLeft, int iRight) { if(iRight < iLeft) iLeft = iRight; } -inline static void _setmax(int& iLeft, int iRight) +//! Update \a iLeft with the biggest of both values. +/*! + @param [inout] iLeft Left value to check and update. + @param iRight Second value to check. + */ +static void set_left_to_max(int& iLeft, int iRight) { if(iRight > iLeft) iLeft = iRight; } -bool THAnimationManager::loadFromTHFile( - const unsigned char* pStartData, size_t iStartDataLength, - const unsigned char* pFrameData, size_t iFrameDataLength, - const unsigned char* pListData, size_t iListDataLength, - const unsigned char* pElementData, size_t iElementDataLength) +void animation_manager::set_bounding_box(frame &oFrame) { - m_iAnimationCount = (unsigned int)(iStartDataLength / sizeof(th_anim_t)); - m_iFrameCount = (unsigned int)(iFrameDataLength / sizeof(th_frame_t)); - unsigned int iListCount = (unsigned int)(iListDataLength / 2); - m_iElementCount = (unsigned int)(iElementDataLength / sizeof(th_element_t)); - - if(m_iAnimationCount == 0 || m_iFrameCount == 0 || iListCount == 0 || m_iElementCount == 0) + oFrame.bounding_left = INT_MAX; + oFrame.bounding_right = INT_MIN; + oFrame.bounding_top = INT_MAX; + oFrame.bounding_bottom = INT_MIN; + size_t iListIndex = oFrame.list_index; + for(; ; ++iListIndex) { - m_iAnimationCount = 0; - m_iFrameCount = 0; - return false; - } + uint16_t iElement = element_list[iListIndex]; + if(iElement >= elements.size()) + break; - delete[] m_pFirstFrames; - delete[] m_pFrames; - delete[] m_pElementList; - delete[] m_pElements; + element& oElement = elements[iElement]; + if(oElement.element_sprite_sheet == nullptr) + continue; - m_pFirstFrames = NULL; - m_pFrames = NULL; - m_pElementList = NULL; - m_pElements = NULL; + unsigned int iWidth, iHeight; + oElement.element_sprite_sheet->get_sprite_size_unchecked(oElement.sprite, &iWidth, &iHeight); + set_left_to_min(oFrame.bounding_left , oElement.x); + set_left_to_min(oFrame.bounding_top , oElement.y); + set_left_to_max(oFrame.bounding_right , oElement.x - 1 + (int)iWidth); + set_left_to_max(oFrame.bounding_bottom, oElement.y - 1 + (int)iHeight); + } +} - m_pFirstFrames = new (std::nothrow) unsigned int[m_iAnimationCount]; - m_pFrames = new (std::nothrow) frame_t[m_iFrameCount]; - m_pElementList = new (std::nothrow) uint16_t[iListCount + 1]; - m_pElements = new (std::nothrow) element_t[m_iElementCount]; +void animation_manager::set_canvas(render_target *pCanvas) +{ + canvas = pCanvas; +} - if(m_pFirstFrames == NULL || m_pFrames == NULL || m_pElementList == NULL || m_pElements == NULL) - { - m_iAnimationCount = 0; - m_iFrameCount = 0; +//! Load the header. +/*! + @param [inout] input Data to read. + @return Number of consumed bytes, a negative number indicates an error. + */ +static int load_header(memory_reader &input) +{ + static const uint8_t aHdr[] = {'C', 'T', 'H', 'G', 1, 2}; + + if (!input.are_bytes_available(6)) return false; + for (int i = 0; i < 6; i++) + { + if (input.read_uint8() != aHdr[i]) + return false; + } + return true; +} + +size_t animation_manager::load_elements(memory_reader &input, sprite_sheet *pSpriteSheet, + size_t iNumElements, size_t &iLoadedElements, + size_t iElementStart, size_t iElementCount) +{ + size_t iFirst = iLoadedElements + iElementStart; + + size_t iSpriteCount = pSpriteSheet->get_sprite_count(); + while (iNumElements > 0) + { + if (iLoadedElements >= iElementCount || !input.are_bytes_available(12)) + return SIZE_MAX; + + size_t iSprite = input.read_uint32(); + int iX = input.read_int16(); + int iY = input.read_int16(); + uint8_t iLayerClass = input.read_uint8(); + uint8_t iLayerId = input.read_uint8(); + uint32_t iFlags = input.read_uint16(); + + if (iLayerClass > 12) + iLayerClass = 6; // Nothing lives on layer 6 + + element oElement; + oElement.sprite = iSprite; + oElement.flags = iFlags; + oElement.x = iX; + oElement.y = iY; + oElement.layer = iLayerClass; + oElement.layer_id = iLayerId; + if (oElement.sprite >= iSpriteCount) + oElement.element_sprite_sheet = nullptr; + else + oElement.element_sprite_sheet = pSpriteSheet; + + elements.push_back(oElement); + iLoadedElements++; + iNumElements--; } + return iFirst; +} + +size_t animation_manager::make_list_elements(size_t iFirstElement, size_t iNumElements, + size_t &iLoadedListElements, + size_t iListStart, size_t iListCount) +{ + size_t iFirst = iLoadedListElements + iListStart; - for(unsigned int i = 0; i < m_iAnimationCount; ++i) + // Verify there is enough room for all list elements + 0xFFFF + if (iLoadedListElements + iNumElements + 1 > iListCount) + return SIZE_MAX; + assert(iFirstElement + iNumElements < 0xFFFF); // Overflow for list elements. + + while (iNumElements > 0) { - unsigned int iFirstFrame = reinterpret_cast(pStartData)[i].frame; - if(iFirstFrame > m_iFrameCount) - iFirstFrame = 0; - m_pFirstFrames[i] = iFirstFrame; + element_list.push_back(static_cast(iFirstElement)); + iLoadedListElements++; + iFirstElement++; + iNumElements--; } + // Add 0xFFFF. + element_list.push_back(0xFFFF); + iLoadedListElements++; + + return iFirst; +} + +//! Shift the first frame if all frames are available. +/*! + @param iFirst First frame number, or 0xFFFFFFFFu if no animation. + @param iLength Number of frames in the animation. + @param iStart Start of the frames for this file. + @param iLoaded Number of loaded frames. + @return The shifted first frame, or 0xFFFFFFFFu. + */ +static uint32_t shift_first(uint32_t iFirst, size_t iLength, + size_t iStart, size_t iLoaded) +{ + if (iFirst == 0xFFFFFFFFu || iFirst + iLength > iLoaded) + return 0xFFFFFFFFu; + return iFirst + static_cast(iStart); +} + +void animation_manager::fix_next_frame(uint32_t iFirst, size_t iLength) +{ + if (iFirst == 0xFFFFFFFFu) + return; + + frame &oFirst = frames[iFirst]; + oFirst.flags |= 0x1; // Start of animation flag. + + frame &oLast = frames[iFirst + iLength - 1]; + oLast.next_frame = iFirst; // Loop last frame back to the first. +} + +bool animation_manager::load_custom_animations(const uint8_t* pData, size_t iDataLength) +{ + memory_reader input(pData, iDataLength); + + if (!load_header(input)) + return false; + + if (!input.are_bytes_available(5*4)) + return false; - for(unsigned int i = 0; i < m_iFrameCount; ++i) + size_t iAnimationCount = input.read_uint32(); + size_t iFrameCount = input.read_uint32(); + size_t iElementCount = input.read_uint32(); + size_t iSpriteCount = input.read_uint32(); + input.read_uint32(); // Total number of bytes sprite data is not used. + + // Every element is referenced once, and one 0xFFFF for every frame. + size_t iListCount = iElementCount + iFrameCount; + + size_t iFrameStart = frame_count; + size_t iListStart = element_list_count; + size_t iElementStart = element_count; + + if (iAnimationCount == 0 || iFrameCount == 0 || iElementCount == 0 || iSpriteCount == 0) + return false; + + if (iElementStart + iElementCount >= 0xFFFF) // Overflow of list elements. + return false; + + // Create new space for the elements. + first_frames.reserve(first_frames.size() + iAnimationCount * 4); // Be optimistic in reservation. + frames.reserve(iFrameStart + iFrameCount); + element_list.reserve(iListStart + iListCount); + elements.reserve(iElementStart + iElementCount); + + // Construct a sprite sheet for the sprites to be loaded. + sprite_sheet *pSheet = new sprite_sheet; + pSheet->set_sprite_count(iSpriteCount, canvas); + custom_sheets.push_back(pSheet); + + size_t iLoadedFrames = 0; + size_t iLoadedListElements = 0; + size_t iLoadedElements = 0; + size_t iLoadedSprites = 0; + + // Read the blocks of the file, until hitting EOF. + for (;;) { - const th_frame_t* pFrame = reinterpret_cast(pFrameData) + i; - m_pFrames[i].iListIndex = pFrame->list_index < iListCount ? pFrame->list_index : 0; - m_pFrames[i].iNextFrame = pFrame->next < m_iFrameCount ? pFrame->next : 0; - m_pFrames[i].iSound = pFrame->sound; - m_pFrames[i].iFlags = pFrame->flags; - // Bounding box fields initialised later - m_pFrames[i].iMarkerX = 0; - m_pFrames[i].iMarkerY = 0; - m_pFrames[i].iSecondaryMarkerX = 0; - m_pFrames[i].iSecondaryMarkerY = 0; - } - - memcpy(m_pElementList, pListData, iListCount * 2); - m_pElementList[iListCount] = 0xFFFF; - - for(unsigned int i = 0; i < m_iElementCount; ++i) - { - const th_element_t* pTHElement = reinterpret_cast(pElementData) + i; - element_t *pElement = m_pElements + i; - pElement->iSprite = pTHElement->table_position / 6; - pElement->iFlags = pTHElement->flags & 0xF; - pElement->iX = static_cast(pTHElement->offx) - 141; - pElement->iY = static_cast(pTHElement->offy) - 186; - pElement->iLayer = pTHElement->flags >> 4; - if(pElement->iLayer > 12) - pElement->iLayer = 6; // Nothing lives on layer 6 - pElement->iLayerId = pTHElement->layerid; - } - - unsigned int iSpriteCount = m_pSpriteSheet->getSpriteCount(); - for(unsigned int i = 0; i < m_iFrameCount; ++i) - { - frame_t* pFrame = m_pFrames + i; - pFrame->iBoundingLeft = INT_MAX; - pFrame->iBoundingRight = INT_MIN; - pFrame->iBoundingTop = INT_MAX; - pFrame->iBoundingBottom = INT_MIN; - unsigned int iListIndex = pFrame->iListIndex; - for(; ; ++iListIndex) + if (input.is_at_end_of_file()) + break; + + // Read identification bytes at the start of each block, and dispatch loading. + if (!input.are_bytes_available(2)) + return false; + int first = input.read_uint8(); + int second = input.read_uint8(); + + // Recognized a grouped animation block, load it. + if (first == 'C' && second == 'A') { - uint16_t iElement = m_pElementList[iListIndex]; - if(iElement >= m_iElementCount) - break; + animation_key oKey; + + if (!input.are_bytes_available(2+4)) + return false; + oKey.tile_size = input.read_uint16(); + size_t iNumFrames = input.read_uint32(); + if (iNumFrames == 0) + return false; + + if (!input.read_string(&oKey.name)) + return false; + + if (!input.are_bytes_available(4*4)) + return false; + uint32_t iNorthFirst = input.read_uint32(); + uint32_t iEastFirst = input.read_uint32(); + uint32_t iSouthFirst = input.read_uint32(); + uint32_t iWestFirst = input.read_uint32(); + + iNorthFirst = shift_first(iNorthFirst, iNumFrames, iFrameStart, iLoadedFrames); + iEastFirst = shift_first(iEastFirst, iNumFrames, iFrameStart, iLoadedFrames); + iSouthFirst = shift_first(iSouthFirst, iNumFrames, iFrameStart, iLoadedFrames); + iWestFirst = shift_first(iWestFirst, iNumFrames, iFrameStart, iLoadedFrames); + + animation_start_frames oFrames; + oFrames.north = -1; + oFrames.east = -1; + oFrames.south = -1; + oFrames.west = -1; - element_t* pElement = m_pElements + iElement; - if(pElement->iSprite >= iSpriteCount) + if (iNorthFirst != 0xFFFFFFFFu) { - continue; + fix_next_frame(iNorthFirst, iNumFrames); + oFrames.north = static_cast(first_frames.size()); + first_frames.push_back(iNorthFirst); + } + if (iEastFirst != 0xFFFFFFFFu) + { + fix_next_frame(iEastFirst, iNumFrames); + oFrames.east = static_cast(first_frames.size()); + first_frames.push_back(iEastFirst); + } + if (iSouthFirst != 0xFFFFFFFFu) + { + fix_next_frame(iSouthFirst, iNumFrames); + oFrames.south = static_cast(first_frames.size()); + first_frames.push_back(iSouthFirst); + } + if (iWestFirst != 0xFFFFFFFFu) + { + fix_next_frame(iWestFirst, iNumFrames); + oFrames.west = static_cast(first_frames.size()); + first_frames.push_back(iWestFirst); } - unsigned int iWidth, iHeight; - m_pSpriteSheet->getSpriteSizeUnchecked(pElement->iSprite, &iWidth, &iHeight); - _setmin(pFrame->iBoundingLeft , pElement->iX); - _setmin(pFrame->iBoundingTop , pElement->iY); - _setmax(pFrame->iBoundingRight , pElement->iX - 1 + (int)iWidth); - _setmax(pFrame->iBoundingBottom, pElement->iY - 1 + (int)iHeight); + named_animation_pair p(oKey, oFrames); + named_animations.insert(p); + continue; + } + + // Recognized a frame block, load it. + else if (first == 'F' && second == 'R') + { + if (iLoadedFrames >= iFrameCount) + return false; + + if (!input.are_bytes_available(2+2)) + return false; + int iSound = input.read_uint16(); + size_t iNumElements = input.read_uint16(); + + size_t iElm = load_elements(input, pSheet, iNumElements, + iLoadedElements, iElementStart, iElementCount); + if (iElm == SIZE_MAX) + return false; + + size_t iListElm = make_list_elements(iElm, iNumElements, + iLoadedListElements, iListStart, iListCount); + if (iListElm == SIZE_MAX) + return false; + + frame oFrame; + oFrame.list_index = iListElm; + oFrame.next_frame = iFrameStart + iLoadedFrames + 1; // Point to next frame (changed later). + oFrame.sound = iSound; + oFrame.flags = 0; // Set later. + oFrame.marker_x = 0; + oFrame.marker_y = 0; + oFrame.secondary_marker_x = 0; + oFrame.secondary_marker_y = 0; + + set_bounding_box(oFrame); + + frames.push_back(oFrame); + iLoadedFrames++; + continue; + } + + // Recognized a Sprite block, load it. + else if (first == 'S' && second == 'P') + { + if (iLoadedSprites >= iSpriteCount) + return false; + + if (!input.are_bytes_available(2+2+4)) + return false; + int iWidth = input.read_uint16(); + int iHeight = input.read_uint16(); + uint32_t iSize = input.read_uint32(); + if (iSize > INT_MAX) // Check it is safe to use as 'int' + return false; + + // Load data. + uint8_t *pData = new (std::nothrow) uint8_t[iSize]; + if (pData == nullptr) { + return false; + } + if (!input.are_bytes_available(iSize)) { + delete[] pData; + return false; + } + for (uint32_t i = 0; i < iSize; i++) + pData[i] = input.read_uint8(); + + if (!pSheet->set_sprite_data(iLoadedSprites, pData, true, iSize, + iWidth, iHeight)) + return false; + + iLoadedSprites++; + continue; + } + + // Unrecognized block, fail. + else + { + return false; } } + assert(iLoadedFrames == iFrameCount); + assert(iLoadedListElements == iListCount); + assert(iLoadedElements == iElementCount); + assert(iLoadedSprites == iSpriteCount); + + // Fix the next pointer of the last frame in case it points to non-existing frames. + frame &oFrame = frames[iFrameStart + iFrameCount - 1]; + if (iFrameCount > 0 && oFrame.next_frame >= iFrameStart + iFrameCount) + oFrame.next_frame = iFrameStart; // Useless, but maybe less crashy. + + animation_count = first_frames.size(); + frame_count += iFrameCount; + element_list_count += iListCount; + element_count += iElementCount; + assert(frames.size() == frame_count); + assert(element_list.size() == element_list_count); + assert(elements.size() == element_count); + return true; } -unsigned int THAnimationManager::getAnimationCount() const +const animation_start_frames &animation_manager::get_named_animations(const std::string &sName, int iTilesize) const +{ + static const animation_start_frames oNoneAnimations = {-1, -1, -1, -1}; + + animation_key oKey; + oKey.name = sName; + oKey.tile_size = iTilesize; + + named_animations_map::const_iterator iter = named_animations.find(oKey); + if (iter == named_animations.end()) + return oNoneAnimations; + return (*iter).second; +} + +size_t animation_manager::get_animation_count() const { - return m_iAnimationCount; + return animation_count; } -unsigned int THAnimationManager::getFrameCount() const +size_t animation_manager::get_frame_count() const { - return m_iFrameCount; + return frame_count; } -unsigned int THAnimationManager::getFirstFrame(unsigned int iAnimation) const +size_t animation_manager::get_first_frame(size_t iAnimation) const { - if(iAnimation < m_iAnimationCount) - return m_pFirstFrames[iAnimation]; + if(iAnimation < animation_count) + return first_frames[iAnimation]; else return 0; } -unsigned int THAnimationManager::getNextFrame(unsigned int iFrame) const +size_t animation_manager::get_next_frame(size_t iFrame) const { - if(iFrame < m_iFrameCount) - return m_pFrames[iFrame].iNextFrame; + if(iFrame < frame_count) + return frames[iFrame].next_frame; else return iFrame; } -void THAnimationManager::setAnimationAltPaletteMap(unsigned int iAnimation, const unsigned char* pMap) +void animation_manager::set_animation_alt_palette_map(size_t iAnimation, const uint8_t* pMap, uint32_t iAlt32) { - if(iAnimation >= m_iAnimationCount || m_pSpriteSheet == NULL) + if(iAnimation >= animation_count) return; - unsigned int iFrame = m_pFirstFrames[iAnimation]; - unsigned int iFirstFrame = iFrame; + size_t iFrame = first_frames[iAnimation]; + size_t iFirstFrame = iFrame; do { - unsigned int iListIndex = m_pFrames[iFrame].iListIndex; + size_t iListIndex = frames[iFrame].list_index; for(; ; ++iListIndex) { - uint16_t iElement = m_pElementList[iListIndex]; - if(iElement >= m_iElementCount) + uint16_t iElement = element_list[iListIndex]; + if(iElement >= element_count) break; - element_t* pElement = m_pElements + iElement; - m_pSpriteSheet->setSpriteAltPaletteMap(pElement->iSprite, pMap); + element& oElement = elements[iElement]; + if (oElement.element_sprite_sheet != nullptr) + oElement.element_sprite_sheet->set_sprite_alt_palette_map(oElement.sprite, pMap, iAlt32); } - iFrame = m_pFrames[iFrame].iNextFrame; + iFrame = frames[iFrame].next_frame; } while(iFrame != iFirstFrame); } -bool THAnimationManager::setFrameMarker(unsigned int iFrame, int iX, int iY) +bool animation_manager::set_frame_marker(size_t iFrame, int iX, int iY) { - if(iFrame >= m_iFrameCount) + if(iFrame >= frame_count) return false; - m_pFrames[iFrame].iMarkerX = iX; - m_pFrames[iFrame].iMarkerY = iY; + frames[iFrame].marker_x = iX; + frames[iFrame].marker_y = iY; return true; } -bool THAnimationManager::setFrameSecondaryMarker(unsigned int iFrame, int iX, int iY) +bool animation_manager::set_frame_secondary_marker(size_t iFrame, int iX, int iY) { - if(iFrame >= m_iFrameCount) + if(iFrame >= frame_count) return false; - m_pFrames[iFrame].iSecondaryMarkerX = iX; - m_pFrames[iFrame].iSecondaryMarkerY = iY; + frames[iFrame].secondary_marker_x = iX; + frames[iFrame].secondary_marker_y = iY; return true; } -bool THAnimationManager::getFrameMarker(unsigned int iFrame, int* pX, int* pY) +bool animation_manager::get_frame_marker(size_t iFrame, int* pX, int* pY) { - if(iFrame >= m_iFrameCount) + if(iFrame >= frame_count) return false; - *pX = m_pFrames[iFrame].iMarkerX; - *pY = m_pFrames[iFrame].iMarkerY; + *pX = frames[iFrame].marker_x; + *pY = frames[iFrame].marker_y; return true; } -bool THAnimationManager::getFrameSecondaryMarker(unsigned int iFrame, int* pX, int* pY) +bool animation_manager::get_frame_secondary_marker(size_t iFrame, int* pX, int* pY) { - if(iFrame >= m_iFrameCount) + if(iFrame >= frame_count) return false; - *pX = m_pFrames[iFrame].iSecondaryMarkerX; - *pY = m_pFrames[iFrame].iSecondaryMarkerY; + *pX = frames[iFrame].secondary_marker_x; + *pY = frames[iFrame].secondary_marker_y; return true; } -bool THAnimationManager::hitTest(unsigned int iFrame, const THLayers_t& oLayers, int iX, int iY, unsigned long iFlags, int iTestX, int iTestY) const +bool animation_manager::hit_test(size_t iFrame, const ::layers& oLayers, + int iX, int iY, uint32_t iFlags, + int iTestX, int iTestY) const { - if(iFrame >= m_iFrameCount) + if(iFrame >= frame_count) return false; - const frame_t* pFrame = m_pFrames + iFrame; + const frame& oFrame = frames[iFrame]; iTestX -= iX; iTestY -= iY; - if(iFlags & THDF_FlipHorizontal) + if(iFlags & thdf_flip_horizontal) iTestX = -iTestX; - if(iTestX < pFrame->iBoundingLeft || iTestX > pFrame->iBoundingRight) + if(iTestX < oFrame.bounding_left || iTestX > oFrame.bounding_right) return false; - if(iFlags & THDF_FlipVertical) + if(iFlags & thdf_flip_vertical) { - if(-iTestY < pFrame->iBoundingTop || -iTestY > pFrame->iBoundingBottom) + if(-iTestY < oFrame.bounding_top || -iTestY > oFrame.bounding_bottom) return false; } else { - if(iTestY < pFrame->iBoundingTop || iTestY > pFrame->iBoundingBottom) + if(iTestY < oFrame.bounding_top || iTestY > oFrame.bounding_bottom) return false; } - if(iFlags & THDF_BoundBoxHitTest) + if(iFlags & thdf_bound_box_hit_test) return true; - unsigned int iListIndex = pFrame->iListIndex; - unsigned int iSpriteCount = m_pSpriteSheet->getSpriteCount(); + size_t iListIndex = oFrame.list_index; for(; ; ++iListIndex) { - uint16_t iElement = m_pElementList[iListIndex]; - if(iElement >= m_iElementCount) + uint16_t iElement = element_list[iListIndex]; + if(iElement >= element_count) break; - element_t* pElement = m_pElements + iElement; - if((pElement->iLayerId != 0 && oLayers.iLayerContents[pElement->iLayer] != pElement->iLayerId) - || pElement->iSprite >= iSpriteCount) + const element &oElement = elements[iElement]; + if((oElement.layer_id != 0 && oLayers.layer_contents[oElement.layer] != oElement.layer_id) + || oElement.element_sprite_sheet == nullptr) { continue; } - if(iFlags & THDF_FlipHorizontal) + if(iFlags & thdf_flip_horizontal) { unsigned int iWidth, iHeight; - m_pSpriteSheet->getSpriteSizeUnchecked(pElement->iSprite, &iWidth, &iHeight); - if(m_pSpriteSheet->hitTestSprite(pElement->iSprite, pElement->iX + iWidth - iTestX, - iTestY - pElement->iY, pElement->iFlags ^ THDF_FlipHorizontal)) + oElement.element_sprite_sheet->get_sprite_size_unchecked(oElement.sprite, &iWidth, &iHeight); + if(oElement.element_sprite_sheet->hit_test_sprite(oElement.sprite, oElement.x + iWidth - iTestX, + iTestY - oElement.y, oElement.flags ^ thdf_flip_horizontal)) { return true; } } else { - if(m_pSpriteSheet->hitTestSprite(pElement->iSprite, iTestX - pElement->iX, - iTestY - pElement->iY, pElement->iFlags)) + if(oElement.element_sprite_sheet->hit_test_sprite(oElement.sprite, iTestX - oElement.x, + iTestY - oElement.y, oElement.flags)) { return true; } @@ -329,24 +845,27 @@ return false; } -void THAnimationManager::drawFrame(THRenderTarget* pCanvas, unsigned int iFrame, const THLayers_t& oLayers, int iX, int iY, unsigned long iFlags) const +void animation_manager::draw_frame(render_target* pCanvas, size_t iFrame, + const ::layers& oLayers, + int iX, int iY, uint32_t iFlags) const { - if(iFrame >= m_iFrameCount || m_pSpriteSheet == NULL) + if(iFrame >= frame_count) return; - unsigned int iSpriteCount = m_pSpriteSheet->getSpriteCount(); - unsigned int iPassOnFlags = iFlags & THDF_AltPalette; + uint32_t iPassOnFlags = iFlags & thdf_alt_palette; - unsigned int iListIndex = m_pFrames[iFrame].iListIndex; + size_t iListIndex = frames[iFrame].list_index; for(; ; ++iListIndex) { - uint16_t iElement = m_pElementList[iListIndex]; - if(iElement >= m_iElementCount) + uint16_t iElement = element_list[iListIndex]; + if(iElement >= element_count) break; - element_t* pElement = m_pElements + iElement; - if((pElement->iLayerId != 0 && oLayers.iLayerContents[pElement->iLayer] != pElement->iLayerId) - || pElement->iSprite >= iSpriteCount) + const element &oElement = elements[iElement]; + if (oElement.element_sprite_sheet == nullptr) + continue; + + if(oElement.layer_id != 0 && oLayers.layer_contents[oElement.layer] != oElement.layer_id) { // Some animations involving doctors (i.e. #72, #74, maybe others) // only provide versions for heads W1 and B1, not W2 and B2. The @@ -354,67 +873,69 @@ // the W1 layer as well as W2 if W2 is being used, and similarly // for B1 / B2. A better fix would be to go into each animation // which needs it, and duplicate the W1 / B1 layers to W2 / B2. - if(pElement->iLayer == 5 && oLayers.iLayerContents[5] - 4 == pElement->iLayerId) + if(oElement.layer == 5 && oLayers.layer_contents[5] - 4 == oElement.layer_id) /* don't skip */; else continue; } - if(iFlags & THDF_FlipHorizontal) + if(iFlags & thdf_flip_horizontal) { unsigned int iWidth, iHeight; - m_pSpriteSheet->getSpriteSizeUnchecked(pElement->iSprite, &iWidth, &iHeight); + oElement.element_sprite_sheet->get_sprite_size_unchecked(oElement.sprite, &iWidth, &iHeight); - m_pSpriteSheet->drawSprite(pCanvas, pElement->iSprite, iX - pElement->iX - iWidth, - iY + pElement->iY, iPassOnFlags | (pElement->iFlags ^ THDF_FlipHorizontal)); + oElement.element_sprite_sheet->draw_sprite(pCanvas, oElement.sprite, iX - oElement.x - iWidth, + iY + oElement.y, iPassOnFlags | (oElement.flags ^ thdf_flip_horizontal)); } else { - m_pSpriteSheet->drawSprite(pCanvas, pElement->iSprite, - iX + pElement->iX, iY + pElement->iY, iPassOnFlags | pElement->iFlags); + oElement.element_sprite_sheet->draw_sprite(pCanvas, oElement.sprite, + iX + oElement.x, iY + oElement.y, iPassOnFlags | oElement.flags); } } } -unsigned int THAnimationManager::getFrameSound(unsigned int iFrame) +size_t animation_manager::get_frame_sound(size_t iFrame) { - if(iFrame < m_iFrameCount) - return m_pFrames[iFrame].iSound; + if(iFrame < frame_count) + return frames[iFrame].sound; else return 0; } -void THAnimationManager::getFrameExtent(unsigned int iFrame, const THLayers_t& oLayers, int* pMinX, int* pMaxX, int* pMinY, int* pMaxY, unsigned long iFlags) const +void animation_manager::get_frame_extent(size_t iFrame, const ::layers& oLayers, + int* pMinX, int* pMaxX, + int* pMinY, int* pMaxY, + uint32_t iFlags) const { int iMinX = INT_MAX; int iMaxX = INT_MIN; int iMinY = INT_MAX; int iMaxY = INT_MIN; - if(iFrame < m_iFrameCount && m_pSpriteSheet != NULL) + if(iFrame < frame_count) { - unsigned int iSpriteCount = m_pSpriteSheet->getSpriteCount(); - unsigned int iListIndex = m_pFrames[iFrame].iListIndex; + size_t iListIndex = frames[iFrame].list_index; for(; ; ++iListIndex) { - uint16_t iElement = m_pElementList[iListIndex]; - if(iElement >= m_iElementCount) + uint16_t iElement = element_list[iListIndex]; + if(iElement >= element_count) break; - element_t* pElement = m_pElements + iElement; - if((pElement->iLayerId != 0 && oLayers.iLayerContents[pElement->iLayer] != pElement->iLayerId) - || pElement->iSprite >= iSpriteCount) + const element &oElement = elements[iElement]; + if((oElement.layer_id != 0 && oLayers.layer_contents[oElement.layer] != oElement.layer_id) + || oElement.element_sprite_sheet == nullptr) { continue; } - int iX = pElement->iX; - int iY = pElement->iY; + int iX = oElement.x; + int iY = oElement.y; unsigned int iWidth_, iHeight_; - m_pSpriteSheet->getSpriteSizeUnchecked(pElement->iSprite, &iWidth_, &iHeight_); + oElement.element_sprite_sheet->get_sprite_size_unchecked(oElement.sprite, &iWidth_, &iHeight_); int iWidth = static_cast(iWidth_); int iHeight = static_cast(iHeight_); - if(iFlags & THDF_FlipHorizontal) + if(iFlags & thdf_flip_horizontal) iX = -(iX + iWidth); if(iX < iMinX) iMinX = iX; @@ -436,112 +957,112 @@ *pMaxY = iMaxY; } -THChunkRenderer::THChunkRenderer(int width, int height, unsigned char *buffer) +chunk_renderer::chunk_renderer(int width, int height, uint8_t *buffer) { - m_data = buffer ? buffer : new unsigned char[width * height]; - m_ptr = m_data; - m_end = m_data + width * height; - m_x = 0; - m_y = 0; - m_width = width; - m_height = height; - m_skip_eol = false; + data = buffer ? buffer : new uint8_t[width * height]; + ptr = data; + end = data + width * height; + x = 0; + y = 0; + this->width = width; + this->height = height; + skip_eol = false; } -THChunkRenderer::~THChunkRenderer() +chunk_renderer::~chunk_renderer() { - delete[] m_data; + delete[] data; } -unsigned char* THChunkRenderer::takeData() +uint8_t* chunk_renderer::take_data() { - unsigned char *buffer = m_data; - m_data = 0; + uint8_t *buffer = data; + data = 0; return buffer; } -void THChunkRenderer::chunkFillToEndOfLine(unsigned char value) +void chunk_renderer::chunk_fill_to_end_of_line(uint8_t value) { - if(m_x != 0 || !m_skip_eol) + if(x != 0 || !skip_eol) { - chunkFill(m_width - m_x, value); + chunk_fill(width - x, value); } - m_skip_eol = false; + skip_eol = false; } -void THChunkRenderer::chunkFinish(unsigned char value) +void chunk_renderer::chunk_finish(uint8_t value) { - chunkFill(static_cast(m_end - m_ptr), value); + chunk_fill(static_cast(end - ptr), value); } -void THChunkRenderer::chunkFill(int npixels, unsigned char value) +void chunk_renderer::chunk_fill(int npixels, uint8_t value) { - _fixNpixels(npixels); + fix_n_pixels(npixels); if(npixels > 0) { - memset(m_ptr, value, npixels); - _incrementPosition(npixels); + std::memset(ptr, value, npixels); + increment_position(npixels); } } -void THChunkRenderer::chunkCopy(int npixels, const unsigned char* data) +void chunk_renderer::chunk_copy(int npixels, const uint8_t* in_data) { - _fixNpixels(npixels); + fix_n_pixels(npixels); if(npixels > 0) { - memcpy(m_ptr, data, npixels); - _incrementPosition(npixels); + std::memcpy(ptr, in_data, npixels); + increment_position(npixels); } } -inline void THChunkRenderer::_fixNpixels(int& npixels) const +void chunk_renderer::fix_n_pixels(int& npixels) const { - if(m_ptr + npixels > m_end) + if(ptr + npixels > end) { - npixels = static_cast(m_end - m_ptr); + npixels = static_cast(end - ptr); } } -inline void THChunkRenderer::_incrementPosition(int npixels) +void chunk_renderer::increment_position(int npixels) { - m_ptr += npixels; - m_x += npixels; - m_y += m_x / m_width; - m_x = m_x % m_width; - m_skip_eol = true; + ptr += npixels; + x += npixels; + y += x / width; + x = x % width; + skip_eol = true; } -void THChunkRenderer::decodeChunks(const unsigned char* data, int datalen, bool complex) +void chunk_renderer::decode_chunks(const uint8_t* data, int datalen, bool complex) { if(complex) { - while(!_isDone() && datalen > 0) + while(!is_done() && datalen > 0) { - unsigned char b = *data; + uint8_t b = *data; --datalen; ++data; if(b == 0) { - chunkFillToEndOfLine(0xFF); + chunk_fill_to_end_of_line(0xFF); } else if(b < 0x40) { int amt = b; if(datalen < amt) amt = datalen; - chunkCopy(amt, data); + chunk_copy(amt, data); data += amt; datalen -= amt; } else if((b & 0xC0) == 0x80) { - chunkFill(b - 0x80, 0xFF); + chunk_fill(b - 0x80, 0xFF); } else { int amt; - unsigned char colour = 0; + uint8_t colour = 0; if(b == 0xFF) { if(datalen < 2) @@ -563,105 +1084,105 @@ --datalen; } } - chunkFill(amt, colour); + chunk_fill(amt, colour); } } } else { - while(!_isDone() && datalen > 0) + while(!is_done() && datalen > 0) { - unsigned char b = *data; + uint8_t b = *data; --datalen; ++data; if(b == 0) { - chunkFillToEndOfLine(0xFF); + chunk_fill_to_end_of_line(0xFF); } else if(b < 0x80) { int amt = b; if(datalen < amt) amt = datalen; - chunkCopy(amt, data); + chunk_copy(amt, data); data += amt; datalen -= amt; } else { - chunkFill(0x100 - b, 0xFF); + chunk_fill(0x100 - b, 0xFF); } } } - chunkFinish(0xFF); + chunk_finish(0xFF); } -#define AreFlagsSet(val, flags) (((val) & (flags)) == (flags)) +#define ARE_FLAGS_SET(val, flags) (((val) & (flags)) == (flags)) -void THAnimation::draw(THRenderTarget* pCanvas, int iDestX, int iDestY) +void animation::draw(render_target* pCanvas, int iDestX, int iDestY) { - if(AreFlagsSet(m_iFlags, THDF_Alpha50 | THDF_Alpha75)) + if(ARE_FLAGS_SET(flags, thdf_alpha_50 | thdf_alpha_75)) return; - iDestX += m_iX; - iDestY += m_iY; - if(m_iSoundToPlay) + iDestX += x_relative_to_tile; + iDestY += y_relative_to_tile; + if(sound_to_play) { - THSoundEffects *pSounds = THSoundEffects::getSingleton(); + sound_player *pSounds = sound_player::get_singleton(); if(pSounds) - pSounds->playSoundAt(m_iSoundToPlay, iDestX, iDestY); - m_iSoundToPlay = 0; + pSounds->play_at(sound_to_play, iDestX, iDestY); + sound_to_play = 0; } - if(m_pManager) + if(manager) { - if(m_iFlags & THDF_Crop) + if(flags & thdf_crop) { - THClipRect rcOld, rcNew; - pCanvas->getClipRect(&rcOld); + clip_rect rcOld, rcNew; + pCanvas->get_clip_rect(&rcOld); rcNew.y = rcOld.y; rcNew.h = rcOld.h; - rcNew.x = iDestX + (m_iCropColumn - 1) * 32; + rcNew.x = iDestX + (crop_column - 1) * 32; rcNew.w = 64; - IntersectTHClipRect(rcNew, rcOld); - pCanvas->setClipRect(&rcNew); - m_pManager->drawFrame(pCanvas, m_iFrame, m_oLayers, iDestX, iDestY, - m_iFlags); - pCanvas->setClipRect(&rcOld); + clip_rect_intersection(rcNew, rcOld); + pCanvas->set_clip_rect(&rcNew); + manager->draw_frame(pCanvas, frame_index, layers, iDestX, iDestY, + flags); + pCanvas->set_clip_rect(&rcOld); } else - m_pManager->drawFrame(pCanvas, m_iFrame, m_oLayers, iDestX, iDestY, - m_iFlags); + manager->draw_frame(pCanvas, frame_index, layers, iDestX, iDestY, + flags); } } -void THAnimation::drawChild(THRenderTarget* pCanvas, int iDestX, int iDestY) +void animation::draw_child(render_target* pCanvas, int iDestX, int iDestY) { - if(AreFlagsSet(m_iFlags, THDF_Alpha50 | THDF_Alpha75)) + if(ARE_FLAGS_SET(flags, thdf_alpha_50 | thdf_alpha_75)) return; - if(AreFlagsSet(m_pParent->m_iFlags, THDF_Alpha50 | THDF_Alpha75)) + if(ARE_FLAGS_SET(parent->flags, thdf_alpha_50 | thdf_alpha_75)) return; int iX = 0, iY = 0; - m_pParent->getMarker(&iX, &iY); - iX += m_iX + iDestX; - iY += m_iY + iDestY; - if(m_iSoundToPlay) + parent->get_marker(&iX, &iY); + iX += x_relative_to_tile + iDestX; + iY += y_relative_to_tile + iDestY; + if(sound_to_play) { - THSoundEffects *pSounds = THSoundEffects::getSingleton(); + sound_player *pSounds = sound_player::get_singleton(); if(pSounds) - pSounds->playSoundAt(m_iSoundToPlay, iX, iY); - m_iSoundToPlay = 0; + pSounds->play_at(sound_to_play, iX, iY); + sound_to_play = 0; } - if(m_pManager) - m_pManager->drawFrame(pCanvas, m_iFrame, m_oLayers, iX, iY, m_iFlags); + if(manager) + manager->draw_frame(pCanvas, frame_index, layers, iX, iY, flags); } -bool THAnimation::hitTestChild(int iDestX, int iDestY, int iTestX, int iTestY) +bool animation::hit_test_child(int iDestX, int iDestY, int iTestX, int iTestY) { // TODO return false; } -static void CalculateMorphRect(const THClipRect& rcOriginal, THClipRect& rcMorph, int iYLow, int iYHigh) +static void CalculateMorphRect(const clip_rect& rcOriginal, clip_rect& rcMorph, int iYLow, int iYHigh) { rcMorph = rcOriginal; if(rcMorph.y < iYLow) @@ -675,102 +1196,102 @@ } } -void THAnimation::drawMorph(THRenderTarget* pCanvas, int iDestX, int iDestY) +void animation::draw_morph(render_target* pCanvas, int iDestX, int iDestY) { - if(AreFlagsSet(m_iFlags, THDF_Alpha50 | THDF_Alpha75)) + if(ARE_FLAGS_SET(flags, thdf_alpha_50 | thdf_alpha_75)) return; - if(!m_pManager) + if(!manager) return; - iDestX += m_iX; - iDestY += m_iY; - if(m_iSoundToPlay) + iDestX += x_relative_to_tile; + iDestY += y_relative_to_tile; + if(sound_to_play) { - THSoundEffects *pSounds = THSoundEffects::getSingleton(); + sound_player *pSounds = sound_player::get_singleton(); if(pSounds) - pSounds->playSoundAt(m_iSoundToPlay, iDestX, iDestY); - m_iSoundToPlay = 0; + pSounds->play_at(sound_to_play, iDestX, iDestY); + sound_to_play = 0; } - THClipRect oClipRect; - pCanvas->getClipRect(&oClipRect); - THClipRect oMorphRect; - CalculateMorphRect(oClipRect, oMorphRect, iDestY + m_pMorphTarget->m_iX, - iDestY + m_pMorphTarget->m_iY + 1); - pCanvas->setClipRect(&oMorphRect); - m_pManager->drawFrame(pCanvas, m_iFrame, m_oLayers, iDestX, iDestY, - m_iFlags); - CalculateMorphRect(oClipRect, oMorphRect, iDestY + m_pMorphTarget->m_iY, - iDestY + m_pMorphTarget->m_iSpeedX); - pCanvas->setClipRect(&oMorphRect); - m_pManager->drawFrame(pCanvas, m_pMorphTarget->m_iFrame, - m_pMorphTarget->m_oLayers, iDestX, - iDestY, m_pMorphTarget->m_iFlags); - pCanvas->setClipRect(&oClipRect); + clip_rect oClipRect; + pCanvas->get_clip_rect(&oClipRect); + clip_rect oMorphRect; + CalculateMorphRect(oClipRect, oMorphRect, iDestY + morph_target->x_relative_to_tile, + iDestY + morph_target->y_relative_to_tile + 1); + pCanvas->set_clip_rect(&oMorphRect); + manager->draw_frame(pCanvas, frame_index, layers, iDestX, iDestY, + flags); + CalculateMorphRect(oClipRect, oMorphRect, iDestY + morph_target->y_relative_to_tile, + iDestY + morph_target->speed.dx); + pCanvas->set_clip_rect(&oMorphRect); + manager->draw_frame(pCanvas, morph_target->frame_index, + morph_target->layers, iDestX, + iDestY, morph_target->flags); + pCanvas->set_clip_rect(&oClipRect); } -bool THAnimation::hitTest(int iDestX, int iDestY, int iTestX, int iTestY) +bool animation::hit_test(int iDestX, int iDestY, int iTestX, int iTestY) { - if(AreFlagsSet(m_iFlags, THDF_Alpha50 | THDF_Alpha75)) + if(ARE_FLAGS_SET(flags, thdf_alpha_50 | thdf_alpha_75)) return false; - if(m_pManager == NULL) + if(manager == nullptr) return false; - return m_pManager->hitTest(m_iFrame, m_oLayers, m_iX + iDestX, - m_iY + iDestY, m_iFlags, iTestX, iTestY); + return manager->hit_test(frame_index, layers, x_relative_to_tile + iDestX, + y_relative_to_tile + iDestY, flags, iTestX, iTestY); } -bool THAnimation::hitTestMorph(int iDestX, int iDestY, int iTestX, int iTestY) +bool animation::hit_test_morph(int iDestX, int iDestY, int iTestX, int iTestY) { - if(AreFlagsSet(m_iFlags, THDF_Alpha50 | THDF_Alpha75)) + if(ARE_FLAGS_SET(flags, thdf_alpha_50 | thdf_alpha_75)) return false; - if(m_pManager == NULL) + if(manager == nullptr) return false; - return m_pManager->hitTest(m_iFrame, m_oLayers, m_iX + iDestX, - m_iY + iDestY, m_iFlags, iTestX, iTestY) || m_pMorphTarget->hitTest( + return manager->hit_test(frame_index, layers, x_relative_to_tile + iDestX, + y_relative_to_tile + iDestY, flags, iTestX, iTestY) || morph_target->hit_test( iDestX, iDestY, iTestX, iTestY); } -#undef AreFlagsSet +#undef ARE_FLAGS_SET -static bool THAnimation_HitTestChild(THDrawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY) +static bool THAnimation_hit_test_child(drawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY) { - return reinterpret_cast(pSelf)->hitTestChild(iDestX, iDestY, iTestX, iTestY); + return reinterpret_cast(pSelf)->hit_test_child(iDestX, iDestY, iTestX, iTestY); } -static void THAnimation_DrawChild(THDrawable* pSelf, THRenderTarget* pCanvas, int iDestX, int iDestY) +static void THAnimation_draw_child(drawable* pSelf, render_target* pCanvas, int iDestX, int iDestY) { - reinterpret_cast(pSelf)->drawChild(pCanvas, iDestX, iDestY); + reinterpret_cast(pSelf)->draw_child(pCanvas, iDestX, iDestY); } -static bool THAnimation_HitTestMorph(THDrawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY) +static bool THAnimation_hit_test_morph(drawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY) { - return reinterpret_cast(pSelf)->hitTestMorph(iDestX, iDestY, iTestX, iTestY); + return reinterpret_cast(pSelf)->hit_test_morph(iDestX, iDestY, iTestX, iTestY); } -static void THAnimation_DrawMorph(THDrawable* pSelf, THRenderTarget* pCanvas, int iDestX, int iDestY) +static void THAnimation_draw_morph(drawable* pSelf, render_target* pCanvas, int iDestX, int iDestY) { - reinterpret_cast(pSelf)->drawMorph(pCanvas, iDestX, iDestY); + reinterpret_cast(pSelf)->draw_morph(pCanvas, iDestX, iDestY); } -static bool THAnimation_HitTest(THDrawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY) +static bool THAnimation_hit_test(drawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY) { - return reinterpret_cast(pSelf)->hitTest(iDestX, iDestY, iTestX, iTestY); + return reinterpret_cast(pSelf)->hit_test(iDestX, iDestY, iTestX, iTestY); } -static void THAnimation_Draw(THDrawable* pSelf, THRenderTarget* pCanvas, int iDestX, int iDestY) +static void THAnimation_draw(drawable* pSelf, render_target* pCanvas, int iDestX, int iDestY) { - reinterpret_cast(pSelf)->draw(pCanvas, iDestX, iDestY); + reinterpret_cast(pSelf)->draw(pCanvas, iDestX, iDestY); } -static bool THAnimation_isMultipleFrameAnimation(THDrawable* pSelf) +static bool THAnimation_is_multiple_frame_animation(drawable* pSelf) { - THAnimation *pAnimation = reinterpret_cast(pSelf); + animation *pAnimation = reinterpret_cast(pSelf); if(pAnimation) { - int firstFrame = pAnimation->getAnimationManager()->getFirstFrame(pAnimation->getAnimation()); - int nextFrame = pAnimation->getAnimationManager()->getNextFrame(firstFrame); + size_t firstFrame = pAnimation->get_animation_manager()->get_first_frame(pAnimation->get_animation()); + size_t nextFrame = pAnimation->get_animation_manager()->get_next_frame(firstFrame); return nextFrame != firstFrame; } else @@ -778,88 +1299,87 @@ } -THAnimationBase::THAnimationBase() +animation_base::animation_base() { - m_iX = 0; - m_iY = 0; + x_relative_to_tile = 0; + y_relative_to_tile = 0; for(int i = 0; i < 13; ++i) - m_oLayers.iLayerContents[i] = 0; - m_iFlags = 0; + layers.layer_contents[i] = 0; + flags = 0; } -THAnimation::THAnimation() +animation::animation(): + manager(nullptr), + morph_target(nullptr), + animation_index(0), + frame_index(0), + speed({0,0}), + sound_to_play(0), + crop_column(0) { - m_fnDraw = THAnimation_Draw; - m_fnHitTest = THAnimation_HitTest; - m_fnIsMultipleFrameAnimation = THAnimation_isMultipleFrameAnimation; - m_pManager = NULL; - m_pMorphTarget = NULL; - m_iAnimation = 0; - m_iFrame = 0; - m_iCropColumn = 0; - m_iSpeedX = 0; - m_iSpeedY = 0; - m_iSoundToPlay = 0; + draw_fn = THAnimation_draw; + hit_test_fn = THAnimation_hit_test; + is_multiple_frame_animation_fn = THAnimation_is_multiple_frame_animation; } -void THAnimation::persist(LuaPersistWriter *pWriter) const +void animation::persist(lua_persist_writer *pWriter) const { - lua_State *L = pWriter->getStack(); + lua_State *L = pWriter->get_stack(); // Write the next chained thing lua_rawgeti(L, luaT_environindex, 2); - lua_pushlightuserdata(L, m_pNext); + lua_pushlightuserdata(L, next); lua_rawget(L, -2); - pWriter->fastWriteStackObject(-1); + pWriter->fast_write_stack_object(-1); lua_pop(L, 2); - // Write the THDrawable fields - pWriter->writeVUInt(m_iFlags); -#define IsUsingFunctionSet(d, ht) m_fnDraw == (THAnimation_ ## d) \ - && m_fnHitTest == (THAnimation_ ## ht) - - if(IsUsingFunctionSet(Draw, HitTest)) - pWriter->writeVUInt(1); - else if(IsUsingFunctionSet(DrawChild, HitTestChild)) - pWriter->writeVUInt(2); - else if(IsUsingFunctionSet(DrawMorph, HitTestMorph)) + // Write the drawable fields + pWriter->write_uint(flags); +#define IS_USING_FUNCTION_SET(d, ht) draw_fn == (THAnimation_ ## d) \ + && hit_test_fn == (THAnimation_ ## ht) + + if(IS_USING_FUNCTION_SET(draw, hit_test)) + pWriter->write_uint(1); + else if(IS_USING_FUNCTION_SET(draw_child, hit_test_child)) + pWriter->write_uint(2); + else if(IS_USING_FUNCTION_SET(draw_morph, hit_test_morph)) { // NB: Prior version of code used the number 3 here, and forgot // to persist the morph target. - pWriter->writeVUInt(4); + pWriter->write_uint(4); lua_rawgeti(L, luaT_environindex, 2); - lua_pushlightuserdata(L, m_pMorphTarget); + lua_pushlightuserdata(L, morph_target); lua_rawget(L, -2); - pWriter->writeStackObject(-1); + pWriter->write_stack_object(-1); lua_pop(L, 2); } else - pWriter->writeVUInt(0); + pWriter->write_uint(0); -#undef IsUsingFunctionSet +#undef IS_USING_FUNCTION_SET // Write the simple fields - pWriter->writeVUInt(m_iAnimation); - pWriter->writeVUInt(m_iFrame); - pWriter->writeVInt(m_iX); - pWriter->writeVInt(m_iY); - pWriter->writeVInt((int)m_iSoundToPlay); // Not a VUInt, for compatibility - pWriter->writeVInt(0); // For compatibility - if(m_iFlags & THDF_Crop) - pWriter->writeVInt(m_iCropColumn); + pWriter->write_uint(animation_index); + pWriter->write_uint(frame_index); + pWriter->write_int(x_relative_to_tile); + pWriter->write_int(y_relative_to_tile); + pWriter->write_int((int)sound_to_play); // Not a uint, for compatibility + pWriter->write_int(0); // For compatibility + if(flags & thdf_crop) + pWriter->write_int(crop_column); // Write the unioned fields - if(m_fnDraw != THAnimation_DrawChild) + if(draw_fn != THAnimation_draw_child) { - pWriter->writeVInt(m_iSpeedX); - pWriter->writeVInt(m_iSpeedY); + pWriter->write_int(speed.dx); + pWriter->write_int(speed.dy); } else { lua_rawgeti(L, luaT_environindex, 2); - lua_pushlightuserdata(L, m_pParent); + lua_pushlightuserdata(L, parent); lua_rawget(L, -2); - pWriter->writeStackObject(-1); + pWriter->write_stack_object(-1); lua_pop(L, 2); } @@ -867,32 +1387,32 @@ int iNumLayers = 13; for( ; iNumLayers >= 1; --iNumLayers) { - if(m_oLayers.iLayerContents[iNumLayers - 1] != 0) + if(layers.layer_contents[iNumLayers - 1] != 0) break; } - pWriter->writeVUInt(iNumLayers); - pWriter->writeByteStream(m_oLayers.iLayerContents, iNumLayers); + pWriter->write_uint(iNumLayers); + pWriter->write_byte_stream(layers.layer_contents, iNumLayers); } -void THAnimation::depersist(LuaPersistReader *pReader) +void animation::depersist(lua_persist_reader *pReader) { - lua_State *L = pReader->getStack(); + lua_State *L = pReader->get_stack(); do { // Read the chain - if(!pReader->readStackObject()) + if(!pReader->read_stack_object()) break; - m_pNext = reinterpret_cast(lua_touserdata(L, -1)); - if(m_pNext) - m_pNext->m_pPrev = this; + next = reinterpret_cast(lua_touserdata(L, -1)); + if(next) + next->prev = this; lua_pop(L, 1); - // Read THDrawable fields - if(!pReader->readVUInt(m_iFlags)) + // Read drawable fields + if(!pReader->read_uint(flags)) break; int iFunctionSet; - if(!pReader->readVUInt(iFunctionSet)) + if(!pReader->read_uint(iFunctionSet)) break; switch(iFunctionSet) { @@ -901,226 +1421,229 @@ // missing, so settle for a graphical bug rather than a segfault // by reverting to the normal function set. case 1: - m_fnDraw = THAnimation_Draw; - m_fnHitTest = THAnimation_HitTest; + draw_fn = THAnimation_draw; + hit_test_fn = THAnimation_hit_test; break; case 2: - m_fnDraw = THAnimation_DrawChild; - m_fnHitTest = THAnimation_HitTestChild; + draw_fn = THAnimation_draw_child; + hit_test_fn = THAnimation_hit_test_child; break; case 4: - m_fnDraw = THAnimation_DrawMorph; - m_fnHitTest = THAnimation_HitTestMorph; - pReader->readStackObject(); - m_pMorphTarget = reinterpret_cast(lua_touserdata(L, -1)); + draw_fn = THAnimation_draw_morph; + hit_test_fn = THAnimation_hit_test_morph; + pReader->read_stack_object(); + morph_target = reinterpret_cast(lua_touserdata(L, -1)); lua_pop(L, 1); break; default: - pReader->setError(lua_pushfstring(L, "Unknown animation function set #%i", iFunctionSet)); + pReader->set_error(lua_pushfstring(L, "Unknown animation function set #%i", iFunctionSet)); return; } // Read the simple fields - if(!pReader->readVUInt(m_iAnimation)) + if(!pReader->read_uint(animation_index)) break; - if(!pReader->readVUInt(m_iFrame)) + if(!pReader->read_uint(frame_index)) break; - if(!pReader->readVInt(m_iX)) + if(!pReader->read_int(x_relative_to_tile)) break; - if(!pReader->readVInt(m_iY)) + if(!pReader->read_int(y_relative_to_tile)) break; int iDummy; - if(!pReader->readVInt(iDummy)) + if(!pReader->read_int(iDummy)) break; if(iDummy >= 0) - m_iSoundToPlay = (unsigned int)iDummy; - if(!pReader->readVInt(iDummy)) + sound_to_play = (unsigned int)iDummy; + if(!pReader->read_int(iDummy)) break; - if(m_iFlags & THDF_Crop) + if(flags & thdf_crop) { - if(!pReader->readVInt(m_iCropColumn)) + if(!pReader->read_int(crop_column)) break; } else - m_iCropColumn = 0; + crop_column = 0; // Read the unioned fields - if(m_fnDraw != THAnimation_DrawChild) + if(draw_fn != THAnimation_draw_child) { - if(!pReader->readVInt(m_iSpeedX)) + if(!pReader->read_int(speed.dx)) break; - if(!pReader->readVInt(m_iSpeedY)) + if(!pReader->read_int(speed.dy)) break; } else { - if(!pReader->readStackObject()) + if(!pReader->read_stack_object()) break; - m_pParent = (THAnimation*)lua_touserdata(L, -1); + parent = (animation*)lua_touserdata(L, -1); lua_pop(L, 1); } // Read the layers - memset(m_oLayers.iLayerContents, 0, sizeof(m_oLayers.iLayerContents)); + std::memset(layers.layer_contents, 0, sizeof(layers.layer_contents)); int iNumLayers; - if(!pReader->readVUInt(iNumLayers)) + if(!pReader->read_uint(iNumLayers)) break; if(iNumLayers > 13) { - if(!pReader->readByteStream(m_oLayers.iLayerContents, 13)) + if(!pReader->read_byte_stream(layers.layer_contents, 13)) break; - if(!pReader->readByteStream(NULL, iNumLayers - 13)) + if(!pReader->read_byte_stream(nullptr, iNumLayers - 13)) break; } else { - if(!pReader->readByteStream(m_oLayers.iLayerContents, iNumLayers)) + if(!pReader->read_byte_stream(layers.layer_contents, iNumLayers)) break; } // Fix the m_pAnimator field luaT_getenvfield(L, 2, "animator"); - m_pManager = (THAnimationManager*)lua_touserdata(L, -1); + manager = (animation_manager*)lua_touserdata(L, -1); lua_pop(L, 1); return; } while(false); - pReader->setError("Cannot depersist THAnimation instance"); + pReader->set_error("Cannot depersist animation instance"); } -void THAnimation::tick() +void animation::tick() { - m_iFrame = m_pManager->getNextFrame(m_iFrame); - if(m_fnDraw != THAnimation_DrawChild) + frame_index = manager->get_next_frame(frame_index); + if(draw_fn != THAnimation_draw_child) { - m_iX += m_iSpeedX; - m_iY += m_iSpeedY; + x_relative_to_tile += speed.dx; + y_relative_to_tile += speed.dy; } - if(m_pMorphTarget) + if(morph_target) { - m_pMorphTarget->m_iY += m_pMorphTarget->m_iSpeedY; - if(m_pMorphTarget->m_iY < m_pMorphTarget->m_iX) - m_pMorphTarget->m_iY = m_pMorphTarget->m_iX; + morph_target->y_relative_to_tile += morph_target->speed.dy; + if(morph_target->y_relative_to_tile < morph_target->x_relative_to_tile) + morph_target->y_relative_to_tile = morph_target->x_relative_to_tile; } - m_iSoundToPlay = m_pManager->getFrameSound(m_iFrame); + //Female flying to heaven sound fix: + if(frame_index == 6987) + sound_to_play = 123; + else + sound_to_play = manager->get_frame_sound(frame_index); } -void THAnimationBase::removeFromTile() +void animation_base::remove_from_tile() { - THLinkList::removeFromList(); + link_list::remove_from_list(); } -void THAnimationBase::attachToTile(THMapNode *pMapNode, int layer) +void animation_base::attach_to_tile(map_tile *pMapNode, int layer) { - removeFromTile(); - THLinkList *pList; - if(m_iFlags & THDF_EarlyList) + remove_from_tile(); + link_list *pList; + if(flags & thdf_early_list) pList = &pMapNode->oEarlyEntities; else pList = pMapNode; - this->setDrawingLayer(layer); + this->set_drawing_layer(layer); -#define GetFlags(x) (reinterpret_cast(x)->m_iFlags) - while(pList->m_pNext && pList->m_pNext->getDrawingLayer() < layer) +#define GetFlags(x) (reinterpret_cast(x)->m_iFlags) + while(pList->next && pList->next->get_drawing_layer() < layer) { - pList = pList->m_pNext; + pList = pList->next; } #undef GetFlags - m_pPrev = pList; - if(pList->m_pNext != NULL) + prev = pList; + if(pList->next != nullptr) { - pList->m_pNext->m_pPrev = this; - this->m_pNext = pList->m_pNext; + pList->next->prev = this; + this->next = pList->next; } else { - m_pNext = NULL; + next = nullptr; } - pList->m_pNext = this; + pList->next = this; } -void THAnimation::setParent(THAnimation *pParent) +void animation::set_parent(animation *pParent) { - removeFromTile(); - if(pParent == NULL) + remove_from_tile(); + if(pParent == nullptr) { - m_fnDraw = THAnimation_Draw; - m_fnHitTest = THAnimation_HitTest; - m_iSpeedX = 0; - m_iSpeedY = 0; + draw_fn = THAnimation_draw; + hit_test_fn = THAnimation_hit_test; + speed = { 0, 0 }; } else { - m_fnDraw = THAnimation_DrawChild; - m_fnHitTest = THAnimation_HitTestChild; - m_pParent = pParent; - m_pNext = m_pParent->m_pNext; - if(m_pNext) - m_pNext->m_pPrev = this; - m_pPrev = m_pParent; - m_pParent->m_pNext = this; + draw_fn = THAnimation_draw_child; + hit_test_fn = THAnimation_hit_test_child; + parent = pParent; + next = parent->next; + if(next) + next->prev = this; + prev = parent; + parent->next = this; } } -void THAnimation::setAnimation(THAnimationManager* pManager, unsigned int iAnimation) +void animation::set_animation(animation_manager* pManager, size_t iAnimation) { - m_pManager = pManager; - m_iAnimation = iAnimation; - m_iFrame = pManager->getFirstFrame(iAnimation); - if(m_pMorphTarget) + manager = pManager; + animation_index = iAnimation; + frame_index = pManager->get_first_frame(iAnimation); + if(morph_target) { - m_pMorphTarget = NULL; - m_fnDraw = THAnimation_Draw; - m_fnHitTest = THAnimation_HitTest; + morph_target = nullptr; + draw_fn = THAnimation_draw; + hit_test_fn = THAnimation_hit_test; } } -bool THAnimation::getMarker(int* pX, int* pY) +bool animation::get_marker(int* pX, int* pY) { - if(!m_pManager || !m_pManager->getFrameMarker(m_iFrame, pX, pY)) + if(!manager || !manager->get_frame_marker(frame_index, pX, pY)) return false; - if(m_iFlags & THDF_FlipHorizontal) + if(flags & thdf_flip_horizontal) *pX = -*pX; - *pX += m_iX; - *pY += m_iY + 16; + *pX += x_relative_to_tile; + *pY += y_relative_to_tile + 16; return true; } -bool THAnimation::getSecondaryMarker(int* pX, int* pY) +bool animation::get_secondary_marker(int* pX, int* pY) { - if(!m_pManager || !m_pManager->getFrameSecondaryMarker(m_iFrame, pX, pY)) + if(!manager || !manager->get_frame_secondary_marker(frame_index, pX, pY)) return false; - if(m_iFlags & THDF_FlipHorizontal) + if(flags & thdf_flip_horizontal) *pX = -*pX; - *pX += m_iX; - *pY += m_iY + 16; + *pX += x_relative_to_tile; + *pY += y_relative_to_tile + 16; return true; } -static int GetAnimationDurationAndExtent(THAnimationManager *pManager, - unsigned int iFrame, - const THLayers_t& oLayers, +static int GetAnimationDurationAndExtent(animation_manager *pManager, + size_t iFrame, + const ::layers& oLayers, int* pMinY, int* pMaxY, - unsigned long iFlags) + uint32_t iFlags) { int iMinY = INT_MAX; int iMaxY = INT_MIN; int iDuration = 0; - unsigned int iCurFrame = iFrame; + size_t iCurFrame = iFrame; do { int iFrameMinY; int iFrameMaxY; - pManager->getFrameExtent(iCurFrame, oLayers, NULL, NULL, &iFrameMinY, &iFrameMaxY, iFlags); + pManager->get_frame_extent(iCurFrame, oLayers, nullptr, nullptr, &iFrameMinY, &iFrameMaxY, iFlags); if(iFrameMinY < iMinY) iMinY = iFrameMinY; if(iFrameMaxY > iMaxY) iMaxY = iFrameMaxY; - iCurFrame = pManager->getNextFrame(iCurFrame); + iCurFrame = pManager->get_next_frame(iCurFrame); ++iDuration; } while(iCurFrame != iFrame); if(pMinY) @@ -1130,11 +1653,11 @@ return iDuration; } -void THAnimation::setMorphTarget(THAnimation *pMorphTarget, unsigned int iDurationFactor) +void animation::set_morph_target(animation *pMorphTarget, unsigned int iDurationFactor) { - m_pMorphTarget = pMorphTarget; - m_fnDraw = THAnimation_DrawMorph; - m_fnHitTest = THAnimation_HitTestMorph; + morph_target = pMorphTarget; + draw_fn = THAnimation_draw_morph; + hit_test_fn = THAnimation_hit_test_morph; /* Morphing is the process by which two animations are combined to give a single animation of one animation turning into another. At the moment, @@ -1145,10 +1668,10 @@ are cured at the pharmacy cabinet. The process of morphing requires four state variables, which are stored in the morph target animation: - * The y value top limit - m_pMorphTarget->m_iX - * The y value threshold - m_pMorphTarget->m_iY - * The y value bottom limit - m_pMorphTarget->m_iSpeedX - * The y value increment per frame - m_pMorphTarget->m_iSpeedY + * The y value top limit - morph_target->x + * The y value threshold - morph_target->y + * The y value bottom limit - morph_target->speed.dx + * The y value increment per frame - morph_target->speed.dy This obviously means that the morph target should not be ticked or rendered as it's position and speed contain other values. */ @@ -1157,241 +1680,241 @@ int iMorphMinY, iMorphMaxY; #define GADEA GetAnimationDurationAndExtent - int iOriginalDuration = GADEA(m_pManager, m_iFrame, m_oLayers, &iOrigMinY, - &iOrigMaxY, m_iFlags); - int iMorphDuration = GADEA(m_pMorphTarget->m_pManager, - m_pMorphTarget->m_iFrame, - m_pMorphTarget->m_oLayers, &iMorphMinY, - &iMorphMaxY, m_pMorphTarget->m_iFlags); + int iOriginalDuration = GADEA(manager, frame_index, layers, &iOrigMinY, + &iOrigMaxY, flags); + int iMorphDuration = GADEA(morph_target->manager, + morph_target->frame_index, + morph_target->layers, &iMorphMinY, + &iMorphMaxY, morph_target->flags); if(iMorphDuration > iOriginalDuration) iMorphDuration = iOriginalDuration; #undef GADEA iMorphDuration *= iDurationFactor; if(iOrigMinY < iMorphMinY) - m_pMorphTarget->m_iX = iOrigMinY; + morph_target->x_relative_to_tile = iOrigMinY; else - m_pMorphTarget->m_iX = iMorphMinY; + morph_target->x_relative_to_tile = iMorphMinY; if(iOrigMaxY > iMorphMaxY) - m_pMorphTarget->m_iSpeedX = iOrigMaxY; + morph_target->speed.dx = iOrigMaxY; else - m_pMorphTarget->m_iSpeedX = iMorphMaxY; + morph_target->speed.dx = iMorphMaxY; - int iDist = m_pMorphTarget->m_iX - m_pMorphTarget->m_iSpeedX; - m_pMorphTarget->m_iSpeedY = (iDist - iMorphDuration + 1) / iMorphDuration; - m_pMorphTarget->m_iY = m_pMorphTarget->m_iSpeedX; + int iDist = morph_target->x_relative_to_tile - morph_target->speed.dx; + morph_target->speed.dy = (iDist - iMorphDuration + 1) / iMorphDuration; + morph_target->y_relative_to_tile = morph_target->speed.dx; } -void THAnimation::setFrame(unsigned int iFrame) +void animation::set_frame(size_t iFrame) { - m_iFrame = iFrame; + frame_index = iFrame; } -void THAnimationBase::setLayer(int iLayer, int iId) +void animation_base::set_layer(int iLayer, int iId) { if(0 <= iLayer && iLayer <= 12) { - m_oLayers.iLayerContents[iLayer] = (unsigned char)iId; + layers.layer_contents[iLayer] = static_cast(iId); } } -static bool THSpriteRenderList_HitTest(THDrawable* pSelf, int iDestX, +static bool THSpriteRenderList_hit_test(drawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY) { - return reinterpret_cast(pSelf)-> - hitTest(iDestX, iDestY, iTestX, iTestY); + return reinterpret_cast(pSelf)-> + hit_test(iDestX, iDestY, iTestX, iTestY); } -static void THSpriteRenderList_Draw(THDrawable* pSelf, THRenderTarget* pCanvas, +static void THSpriteRenderList_draw(drawable* pSelf, render_target* pCanvas, int iDestX, int iDestY) { - reinterpret_cast(pSelf)-> + reinterpret_cast(pSelf)-> draw(pCanvas, iDestX, iDestY); } -static bool THSpriteRenderList_isMultipleFrameAnimation(THDrawable* pSelf) +static bool THSpriteRenderList_is_multiple_frame_animation(drawable* pSelf) { return false; } -THSpriteRenderList::THSpriteRenderList() +sprite_render_list::sprite_render_list() { - m_fnDraw = THSpriteRenderList_Draw; - m_fnHitTest = THSpriteRenderList_HitTest; - m_fnIsMultipleFrameAnimation = THSpriteRenderList_isMultipleFrameAnimation; - m_iBufferSize = 0; - m_iNumSprites = 0; - m_pSpriteSheet = NULL; - m_pSprites = NULL; - m_iSpeedX = 0; - m_iSpeedY = 0; - m_iLifetime = -1; + draw_fn = THSpriteRenderList_draw; + hit_test_fn = THSpriteRenderList_hit_test; + is_multiple_frame_animation_fn = THSpriteRenderList_is_multiple_frame_animation; + buffer_size = 0; + sprite_count = 0; + sheet = nullptr; + sprites = nullptr; + dx_per_tick = 0; + dy_per_tick = 0; + lifetime = -1; } -THSpriteRenderList::~THSpriteRenderList() +sprite_render_list::~sprite_render_list() { - delete[] m_pSprites; + delete[] sprites; } -void THSpriteRenderList::tick() +void sprite_render_list::tick() { - m_iX += m_iSpeedX; - m_iY += m_iSpeedY; - if(m_iLifetime > 0) - --m_iLifetime; + x_relative_to_tile += dx_per_tick; + y_relative_to_tile += dy_per_tick; + if(lifetime > 0) + --lifetime; } -void THSpriteRenderList::draw(THRenderTarget* pCanvas, int iDestX, int iDestY) +void sprite_render_list::draw(render_target* pCanvas, int iDestX, int iDestY) { - if(!m_pSpriteSheet) + if(!sheet) return; - iDestX += m_iX; - iDestY += m_iY; - for(_sprite_t *pSprite = m_pSprites, *pLast = m_pSprites + m_iNumSprites; + iDestX += x_relative_to_tile; + iDestY += y_relative_to_tile; + for(sprite *pSprite = sprites, *pLast = sprites + sprite_count; pSprite != pLast; ++pSprite) { - m_pSpriteSheet->drawSprite(pCanvas, pSprite->iSprite, - iDestX + pSprite->iX, iDestY + pSprite->iY, m_iFlags); + sheet->draw_sprite(pCanvas, pSprite->index, + iDestX + pSprite->x, iDestY + pSprite->y, flags); } } -bool THSpriteRenderList::hitTest(int iDestX, int iDestY, int iTestX, int iTestY) +bool sprite_render_list::hit_test(int iDestX, int iDestY, int iTestX, int iTestY) { // TODO return false; } -void THSpriteRenderList::setLifetime(int iLifetime) +void sprite_render_list::set_lifetime(int iLifetime) { if(iLifetime < 0) iLifetime = -1; - m_iLifetime = iLifetime; + lifetime = iLifetime; } -void THSpriteRenderList::appendSprite(unsigned int iSprite, int iX, int iY) +void sprite_render_list::append_sprite(size_t iSprite, int iX, int iY) { - if(m_iBufferSize == m_iNumSprites) + if(buffer_size == sprite_count) { - int iNewSize = m_iBufferSize * 2; + int iNewSize = buffer_size * 2; if(iNewSize == 0) iNewSize = 4; - _sprite_t* pNewSprites = new _sprite_t[iNewSize]; + sprite* pNewSprites = new sprite[iNewSize]; #ifdef _MSC_VER #pragma warning(disable: 4996) #endif - std::copy(m_pSprites, m_pSprites + m_iNumSprites, pNewSprites); + std::copy(sprites, sprites + sprite_count, pNewSprites); #ifdef _MSC_VER #pragma warning(default: 4996) #endif - delete[] m_pSprites; - m_pSprites = pNewSprites; - m_iBufferSize = iNewSize; - } - m_pSprites[m_iNumSprites].iSprite = iSprite; - m_pSprites[m_iNumSprites].iX = iX; - m_pSprites[m_iNumSprites].iY = iY; - ++m_iNumSprites; -} - -void THSpriteRenderList::persist(LuaPersistWriter *pWriter) const -{ - lua_State *L = pWriter->getStack(); - - pWriter->writeVUInt(m_iNumSprites); - pWriter->writeVUInt(m_iFlags); - pWriter->writeVInt(m_iX); - pWriter->writeVInt(m_iY); - pWriter->writeVInt(m_iSpeedX); - pWriter->writeVInt(m_iSpeedY); - pWriter->writeVInt(m_iLifetime); - for(_sprite_t *pSprite = m_pSprites, *pLast = m_pSprites + m_iNumSprites; + delete[] sprites; + sprites = pNewSprites; + buffer_size = iNewSize; + } + sprites[sprite_count].index = iSprite; + sprites[sprite_count].x = iX; + sprites[sprite_count].y = iY; + ++sprite_count; +} + +void sprite_render_list::persist(lua_persist_writer *pWriter) const +{ + lua_State *L = pWriter->get_stack(); + + pWriter->write_uint(sprite_count); + pWriter->write_uint(flags); + pWriter->write_int(x_relative_to_tile); + pWriter->write_int(y_relative_to_tile); + pWriter->write_int(dx_per_tick); + pWriter->write_int(dy_per_tick); + pWriter->write_int(lifetime); + for(sprite *pSprite = sprites, *pLast = sprites + sprite_count; pSprite != pLast; ++pSprite) { - pWriter->writeVUInt(pSprite->iSprite); - pWriter->writeVInt(pSprite->iX); - pWriter->writeVInt(pSprite->iY); + pWriter->write_uint(pSprite->index); + pWriter->write_int(pSprite->x); + pWriter->write_int(pSprite->y); } // Write the layers int iNumLayers = 13; for( ; iNumLayers >= 1; --iNumLayers) { - if(m_oLayers.iLayerContents[iNumLayers - 1] != 0) + if(layers.layer_contents[iNumLayers - 1] != 0) break; } - pWriter->writeVUInt(iNumLayers); - pWriter->writeByteStream(m_oLayers.iLayerContents, iNumLayers); + pWriter->write_uint(iNumLayers); + pWriter->write_byte_stream(layers.layer_contents, iNumLayers); // Write the next chained thing lua_rawgeti(L, luaT_environindex, 2); - lua_pushlightuserdata(L, m_pNext); + lua_pushlightuserdata(L, next); lua_rawget(L, -2); - pWriter->fastWriteStackObject(-1); + pWriter->fast_write_stack_object(-1); lua_pop(L, 2); } -void THSpriteRenderList::depersist(LuaPersistReader *pReader) +void sprite_render_list::depersist(lua_persist_reader *pReader) { - lua_State *L = pReader->getStack(); + lua_State *L = pReader->get_stack(); - if(!pReader->readVUInt(m_iNumSprites)) + if(!pReader->read_uint(sprite_count)) return; - m_iBufferSize = m_iNumSprites; - delete[] m_pSprites; - m_pSprites = new _sprite_t[m_iBufferSize]; + buffer_size = sprite_count; + delete[] sprites; + sprites = new sprite[buffer_size]; - if(!pReader->readVUInt(m_iFlags)) + if(!pReader->read_uint(flags)) return; - if(!pReader->readVInt(m_iX)) + if(!pReader->read_int(x_relative_to_tile)) return; - if(!pReader->readVInt(m_iY)) + if(!pReader->read_int(y_relative_to_tile)) return; - if(!pReader->readVInt(m_iSpeedX)) + if(!pReader->read_int(dx_per_tick)) return; - if(!pReader->readVInt(m_iSpeedY)) + if(!pReader->read_int(dy_per_tick)) return; - if(!pReader->readVInt(m_iLifetime)) + if(!pReader->read_int(lifetime)) return; - for(_sprite_t *pSprite = m_pSprites, *pLast = m_pSprites + m_iNumSprites; + for(sprite *pSprite = sprites, *pLast = sprites + sprite_count; pSprite != pLast; ++pSprite) { - if(!pReader->readVUInt(pSprite->iSprite)) + if(!pReader->read_uint(pSprite->index)) return; - if(!pReader->readVInt(pSprite->iX)) + if(!pReader->read_int(pSprite->x)) return; - if(!pReader->readVInt(pSprite->iY)) + if(!pReader->read_int(pSprite->y)) return; } // Read the layers - memset(m_oLayers.iLayerContents, 0, sizeof(m_oLayers.iLayerContents)); + std::memset(layers.layer_contents, 0, sizeof(layers.layer_contents)); int iNumLayers; - if(!pReader->readVUInt(iNumLayers)) + if(!pReader->read_uint(iNumLayers)) return; if(iNumLayers > 13) { - if(!pReader->readByteStream(m_oLayers.iLayerContents, 13)) + if(!pReader->read_byte_stream(layers.layer_contents, 13)) return; - if(!pReader->readByteStream(NULL, iNumLayers - 13)) + if(!pReader->read_byte_stream(nullptr, iNumLayers - 13)) return; } else { - if(!pReader->readByteStream(m_oLayers.iLayerContents, iNumLayers)) + if(!pReader->read_byte_stream(layers.layer_contents, iNumLayers)) return; } // Read the chain - if(!pReader->readStackObject()) + if(!pReader->read_stack_object()) return; - m_pNext = reinterpret_cast(lua_touserdata(L, -1)); - if(m_pNext) - m_pNext->m_pPrev = this; + next = reinterpret_cast(lua_touserdata(L, -1)); + if(next) + next->prev = this; lua_pop(L, 1); - // Fix the m_pSpriteSheet field + // Fix the sheet field luaT_getenvfield(L, 2, "sheet"); - m_pSpriteSheet = (THSpriteSheet*)lua_touserdata(L, -1); + sheet = (sprite_sheet*)lua_touserdata(L, -1); lua_pop(L, 1); } diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx_dx9.cpp corsix-th-0.62/CorsixTH/Src/th_gfx_dx9.cpp --- corsix-th-0.30/CorsixTH/Src/th_gfx_dx9.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx_dx9.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2031 +0,0 @@ -/* -Copyright (c) 2009-2013 Peter "Corsix" Cawley and Edvin "Lego3" Linge - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "config.h" -#ifdef CORSIX_TH_USE_DX9_RENDERER -#ifndef CORSIX_TH_USE_WIN32_SDK -#error Windows Platform SDK usage must be enabled to use DX9 renderer -#endif -#include "th_gfx.h" -#include -#include -#include -#include -#include -#ifdef _MSC_VER -#pragma comment(lib, "D3D9") -#pragma comment(lib, "D3DX9.lib") -#pragma warning(disable: 4996) // Deprecated fopen -#endif - -template -static void THDX9_OnDeviceChangeThunk(THDX9_DeviceResource *pThis, - eTHDX9DeviceChangeType eType) -{ - reinterpret_cast(pThis)->onDeviceChange(eType); -} - -THRenderTarget::THRenderTarget() -{ - fnOnDeviceChange = THDX9_OnDeviceChangeThunk; - m_pD3D = NULL; - m_pDevice = NULL; - m_pPixelShader = NULL; - m_pVerticies = NULL; - m_pWhiteTexture = NULL; - m_pZoomRenderTexture = NULL; - m_pZoomRenderSurface = NULL; - m_pOriginalBackBuffer = NULL; - m_sLastError = ""; - setClipRect(NULL); - m_iVertexCount = 0; - m_iVertexLength = 0; - m_iNonOverlappingStart = 0; - m_iNonOverlapping = 0; - m_iWidth = 0; - m_iHeight = 0; - m_iZoomTextureSize = 0; - m_fZoomScale = 0.0f; - m_pCursor = NULL; - m_bHasLostDevice = false; -} - -THRenderTarget::~THRenderTarget() -{ - if(m_pPixelShader != NULL) { - m_pPixelShader->Release(); - m_pPixelShader = NULL; - } - if(m_pOriginalBackBuffer != NULL) - { - if(m_pDevice != NULL) - m_pDevice->SetRenderTarget(0, m_pOriginalBackBuffer); - m_pOriginalBackBuffer->Release(); - m_pOriginalBackBuffer = NULL; - } - if(m_pZoomRenderSurface != NULL) - { - m_pZoomRenderSurface->Release(); - m_pZoomRenderSurface = NULL; - } - if(m_pZoomRenderTexture != NULL) - { - m_pZoomRenderTexture->Release(); - m_pZoomRenderTexture = NULL; - } - if(m_pWhiteTexture != NULL) - { - m_pWhiteTexture->Release(); - m_pWhiteTexture = NULL; - } - if(m_pVerticies != NULL) - { - free(m_pVerticies); - m_pVerticies = NULL; - } - if(m_pDevice != NULL) - { - while(m_pNext) - { - THDX9_DeviceResource* pResource = - reinterpret_cast(m_pNext); - pResource->fnOnDeviceChange(pResource, THDX9DCT_DeviceDestroyed); - } - D3DDEVICE_CREATION_PARAMETERS oParams; - m_pDevice->GetCreationParameters(&oParams); - if(this == (THRenderTarget*)GetWindowLongPtr(oParams.hFocusWindow, GWLP_USERDATA)) - SetWindowLongPtr(oParams.hFocusWindow, GWLP_USERDATA, 0); - assert(m_pDevice->Release() == 0); - m_pDevice = NULL; - } - if(m_pD3D != NULL) - { - m_pD3D->Release(); - m_pD3D = NULL; - } -} - -void THRenderTarget::onDeviceChange(eTHDX9DeviceChangeType eChangeType) -{ - // We caused the device change, so there is no need to do anything in - // response to that change. -} - -IDirect3DDevice9* THRenderTarget::getRawDevice(THDX9_DeviceResource* pUser) -{ - pUser->removeFromList(); - pUser->m_pPrev = this; - pUser->m_pNext = m_pNext; - if(m_pNext) - m_pNext->m_pPrev = pUser; - m_pNext = pUser; - return getRawDevice(); -} - -static WNDPROC g_fnSDLWindowProc = NULL; -LRESULT CALLBACK WindowProcIntercept(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) -{ - if(iMessage == WM_SETCURSOR) - { - THRenderTarget* pTarget = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); - if(pTarget && pTarget->hasCursor()) - { - IDirect3DDevice9* pDevice = pTarget->getRawDevice(); - if(pDevice) - { - SetCursor(NULL); - pDevice->ShowCursor(TRUE); - return TRUE; - } - } - } - return CallWindowProc(g_fnSDLWindowProc, hWnd, iMessage, wParam, lParam); -} - -bool THRenderTarget::create(const THRenderTargetCreationParams* pParams) -{ - SDL_Surface *pSDLSurface = SDL_SetVideoMode(pParams->iWidth, - pParams->iHeight, pParams->iBPP, pParams->iSDLFlags); - if(pSDLSurface == NULL) - { - m_sLastError = SDL_GetError(); - return false; - } - - SDL_SysWMinfo oWindowInfo; - HWND hWindow; - oWindowInfo.version.major = SDL_MAJOR_VERSION; - oWindowInfo.version.minor = SDL_MINOR_VERSION; - oWindowInfo.version.patch = SDL_PATCHLEVEL; - if(SDL_GetWMInfo(&oWindowInfo) == 1) - { - hWindow = oWindowInfo.window; - } - else - { - m_sLastError = "Could not get HWND from SDL"; - return false; - } - - // When the video mode is changed (i.e. from windowed to fullscreen), SDL - // reuses the same HWND, so be careful not to subclass it twice, as that - // will lead to a stack overflow. - if(g_fnSDLWindowProc == NULL) - g_fnSDLWindowProc = (WNDPROC)GetWindowLongPtr(hWindow, GWLP_WNDPROC); - if(g_fnSDLWindowProc == (WNDPROC)GetWindowLongPtr(hWindow, GWLP_WNDPROC)) - { - SetWindowLongPtr(hWindow, GWLP_WNDPROC, (LONG_PTR)WindowProcIntercept); - } - - m_pD3D = Direct3DCreate9(D3D_SDK_VERSION); - if(m_pD3D == NULL) - { - m_sLastError = "Could not create Direct3D object"; - return false; - } - - D3DDISPLAYMODE d3ddm; - if(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm) != D3D_OK) - { - m_sLastError = "Could not query display adapter"; - return false; - } - - ZeroMemory(&m_oDeviceCaps, sizeof(m_oDeviceCaps)); - D3DDEVTYPE eDeviceTypeToUse = D3DDEVTYPE_HAL; - if(m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, eDeviceTypeToUse, &m_oDeviceCaps) != D3D_OK) - { - eDeviceTypeToUse = D3DDEVTYPE_SW; - if(m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, eDeviceTypeToUse, &m_oDeviceCaps) != D3D_OK) - { - eDeviceTypeToUse = D3DDEVTYPE_REF; - if(m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, eDeviceTypeToUse, &m_oDeviceCaps) != D3D_OK) - { - m_sLastError = "Could not get DirectX device capabilities for HAL, SW or REF"; - return false; - } - } - } - - ZeroMemory(&m_oPresentParams, sizeof(m_oPresentParams)); - m_oPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD; - m_oPresentParams.EnableAutoDepthStencil = false; - m_oPresentParams.AutoDepthStencilFormat = D3DFMT_D16; - m_oPresentParams.hDeviceWindow = hWindow; - m_oPresentParams.BackBufferCount = 1; - m_oPresentParams.Windowed = pParams->bFullscreen ? FALSE : TRUE; - m_oPresentParams.BackBufferWidth = pParams->iWidth; - m_oPresentParams.BackBufferHeight = pParams->iHeight; - m_oPresentParams.BackBufferFormat = d3ddm.Format; - m_oPresentParams.PresentationInterval = pParams->bPresentImmediate ? - D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_DEFAULT; - - DWORD dwBehaviour = D3DCREATE_FPU_PRESERVE; // For Lua - if(m_oDeviceCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) - dwBehaviour |= D3DCREATE_HARDWARE_VERTEXPROCESSING; - else - dwBehaviour |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; - - D3DPRESENT_PARAMETERS oPresentParams = m_oPresentParams; - if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, eDeviceTypeToUse, - hWindow, dwBehaviour, &oPresentParams, &m_pDevice))) - { - m_sLastError = "Could not create device"; - return false; - } - - m_bIsWindowed = !pParams->bFullscreen; - m_bIsHardwareCursorSupported = (m_oDeviceCaps.CursorCaps & (pParams->iHeight - < 400 ? D3DCURSORCAPS_LOWRES : D3DCURSORCAPS_COLOR)) != 0; - m_iVertexCount = 0; - m_iVertexLength = 768; - m_pVerticies = (THDX9_Vertex*)malloc(sizeof(THDX9_Vertex) * m_iVertexLength); - if(m_pVerticies == NULL) - { - m_sLastError = "Could not allocate vertex buffer"; - return false; - } - m_iNonOverlapping = 0; - m_iWidth = pParams->iWidth; - m_iHeight = pParams->iHeight; - if(!_initialiseDeviceSettings()) - return false; - - THDX9_FillIndexBuffer(m_aiVertexIndicies, 0, THDX9_INDEX_BUFFER_LENGTH); - - if((m_pWhiteTexture = THDX9_CreateSolidTexture(1, 1, - D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0xFF), m_pDevice)) == NULL) - { - m_sLastError = "Could not create reference texture"; - return false; - } - - // Create the pixel shader used for making a blue filter effect - // when the game is paused. - m_bBlueFilterActive = false; - if (m_pPixelShader == NULL) { - LPD3DXBUFFER m_pCode; - m_pResult = D3DXCompileShaderFromFile("Src/shaders/blue_filter.psh", - NULL, //macro's - NULL, //includes - "ps_main", //main function - "ps_2_0", //shader profile - 0, //flags - &m_pCode, //compiled operations - NULL, //errors - NULL); //constants - - m_pDevice->CreatePixelShader((DWORD*)m_pCode->GetBufferPointer(), - &m_pPixelShader); - } - - SetWindowLongPtr(hWindow, GWLP_USERDATA, (LONG_PTR)this); - return true; -} - -bool THRenderTarget::_initialiseDeviceSettings() -{ - if(m_pDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) != D3D_OK) - { - m_sLastError = "Could not set the DirectX fixed function vertex type"; - return false; - } - - m_pDevice->SetRenderState(D3DRS_ZENABLE, FALSE); - m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - m_pDevice->SetRenderState(D3DRS_CLIPPING, FALSE); - m_pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA - | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE); - m_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - m_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); - m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - m_pDevice->SetRenderState(D3DRS_LOCALVIEWER, FALSE); - m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); - m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - m_pDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); - m_pDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - if(m_oDeviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) - m_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); - else - m_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - m_pDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, m_oDeviceCaps.MaxAnisotropy); - if(m_oDeviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) - m_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); - else - m_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - if(m_oDeviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MIPFLINEAR) - m_pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); - else - m_pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); - - D3DMATRIX mtxIdentity = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f}; - - if(m_pDevice->SetTransform(D3DTS_WORLD, &mtxIdentity) != D3D_OK) - { - m_sLastError = "Could not set DirectX world transform matrix"; - return false; - } - if(m_pDevice->SetTransform(D3DTS_VIEW, &mtxIdentity) != D3D_OK) - { - m_sLastError = "Could not set DirectX view transform matrix"; - return false; - } - - return _setProjectionMatrix(m_iWidth, m_iHeight); -} - -bool THRenderTarget::_setProjectionMatrix(int iWidth, int iHeight) -{ - float fWidth = (float)iWidth; - float fHeight = (float)iHeight; - - D3DMATRIX mtxWorldToScreen = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f}; - - mtxWorldToScreen.m[0][0] = 2.0f / fWidth; - mtxWorldToScreen.m[1][1] = -2.0f / fHeight; - mtxWorldToScreen.m[3][0] = -1.0f - (1.0f / fWidth); - mtxWorldToScreen.m[3][1] = 1.0f + (1.0f / fHeight); - - if(m_pDevice->SetTransform(D3DTS_PROJECTION, &mtxWorldToScreen) != D3D_OK) - { - m_sLastError = "Could not set DirectX projection transform matrix"; - return false; - } - - return true; -} - -void THRenderTarget::_flushZoomBuffer() -{ - if(m_pOriginalBackBuffer == NULL) - { - // No zoom buffer in use - return; - } - - // Restore original render settings - m_pDevice->SetRenderTarget(0, m_pOriginalBackBuffer); - _setProjectionMatrix(m_iWidth, m_iHeight); - m_pOriginalBackBuffer->Release(); - m_pOriginalBackBuffer = NULL; - - // Draw zoom buffer onto screen (the scaling here performs the actual - // zooming). - float fFactor = m_fZoomScale * static_cast(m_iZoomTextureSize); -#define SetVertexData(n, x_, y_) \ - pVerticies[n].x = (float)x_; \ - pVerticies[n].y = (float)y_; \ - pVerticies[n].z = 0.0f; \ - pVerticies[n].colour = D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0xFF); \ - pVerticies[n].u = (float)x_ / fFactor; \ - pVerticies[n].v = (float)y_ / fFactor - - THDX9_Vertex *pVerticies = allocVerticies(4, m_pZoomRenderTexture); - SetVertexData(0, 0, 0); - SetVertexData(1, m_iWidth, 0); - SetVertexData(2, m_iWidth, m_iHeight); - SetVertexData(3, 0, m_iHeight); -#undef SetVertexData - m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE2X); - flushSprites(); - m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); -} - -bool THRenderTarget::setScaleFactor(float fScale, THScaledItems eWhatToScale) -{ - flushSprites(); - _flushZoomBuffer(); - - if(eWhatToScale == THSI_None || (0.999 <= fScale && fScale <= 1.001)) - { - // Effectively back to no scaling, so nothing more to do - return true; - } - if(eWhatToScale != THSI_All) - { - // TODO: Implement selective scaling. - return false; - } - - // Calculate "virtual screen size" and round up to a power of 2 (as - // textures need to be powers of 2) - if(fScale <= 0.0f) - return false; - float fVirtualSize = static_cast(max(m_iWidth, m_iHeight)) / fScale; - unsigned int iZoomTextureSize = 1 << static_cast( - ceil(logf(fVirtualSize) / logf(2))); - if(iZoomTextureSize == 0) // Catch integer overflow - return false; - - // Create the render texture - if(m_iZoomTextureSize != iZoomTextureSize) - { - if(m_pZoomRenderSurface) - { - m_pZoomRenderSurface->Release(); - m_pZoomRenderSurface = NULL; - } - if(m_pZoomRenderTexture) - { - m_pZoomRenderTexture->Release(); - m_pZoomRenderTexture = NULL; - } - m_iZoomTextureSize = 0; - if(m_pDevice->CreateTexture(iZoomTextureSize, iZoomTextureSize, 1, - D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, &m_pZoomRenderTexture, NULL) != D3D_OK) - { - return false; - } - if(m_pZoomRenderTexture->GetSurfaceLevel(0, &m_pZoomRenderSurface) - != D3D_OK) - { - return false; - } - m_iZoomTextureSize = iZoomTextureSize; - } - - // Set device to render to the zoom texture (for pixel-art like in TH, it - // looks much nicer to have all sprites rendered pixel-perfectly into the - // zoom texture, and then scale the zoom texture, as compared to zooming - // each sprite as it is drawn directly onto the screen). - if(m_pDevice->GetRenderTarget(0, &m_pOriginalBackBuffer) != D3D_OK) - return false; - if(m_pDevice->SetRenderTarget(0, m_pZoomRenderSurface) != D3D_OK) - { - m_pDevice->SetRenderTarget(0, m_pOriginalBackBuffer); - m_pOriginalBackBuffer->Release(); - m_pOriginalBackBuffer = NULL; - return false; - } - m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET, - D3DCOLOR_ARGB(0x00, 0x00, 0x00, 0x00), 1.0f, 0); - m_fZoomScale = fScale; - m_iZoomTextureSize = iZoomTextureSize; - - return _setProjectionMatrix(iZoomTextureSize, iZoomTextureSize); -} - -const char* THRenderTarget::getLastError() -{ - return m_sLastError; -} - -bool THRenderTarget::takeScreenshot(const char* sFile) -{ - D3DDISPLAYMODE oMode; - if(m_pDevice->GetDisplayMode(0, &oMode) != D3D_OK) - { - m_sLastError = "Could not get display mode"; - return false; - } - IDirect3DSurface9 *pSurfaceBuffer; - if(m_pDevice->CreateOffscreenPlainSurface(oMode.Width, oMode.Height, - D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurfaceBuffer, NULL) != D3D_OK) - { - m_sLastError = "Could not create screenshot buffer"; - return false; - } - if(m_pDevice->GetFrontBufferData(0, pSurfaceBuffer) != D3D_OK) - { - m_sLastError = "Could not obtain screenshot data"; - pSurfaceBuffer->Release(); - return false; - } - D3DLOCKED_RECT oLock; - if(pSurfaceBuffer->LockRect(&oLock, NULL, D3DLOCK_READONLY) != D3D_OK) - { - m_sLastError = "Could not lock screenshot data"; - pSurfaceBuffer->Release(); - return false; - } - FILE* fBitmap = fopen(sFile, "wb"); - if(fBitmap == NULL) - { - m_sLastError = "Could not open output file"; - pSurfaceBuffer->UnlockRect(); - pSurfaceBuffer->Release(); - return false; - } - BITMAPFILEHEADER oFileHeader; - oFileHeader.bfType = 'MB'; - oFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); - oFileHeader.bfSize = oFileHeader.bfOffBits + oMode.Width * oMode.Height * 4; - oFileHeader.bfReserved1 = 0; - oFileHeader.bfReserved2 = 0; - BITMAPINFOHEADER oInfoHeader; - oInfoHeader.biSize = sizeof(BITMAPINFOHEADER); - oInfoHeader.biWidth = oMode.Width; - oInfoHeader.biHeight = oMode.Height; - oInfoHeader.biPlanes = 1; - oInfoHeader.biBitCount = 32; - oInfoHeader.biCompression = BI_RGB; - oInfoHeader.biSizeImage = 0; - oInfoHeader.biXPelsPerMeter = 72; - oInfoHeader.biYPelsPerMeter = 72; - oInfoHeader.biClrUsed = 0; - oInfoHeader.biClrImportant = 0; - fwrite(&oFileHeader, sizeof(BITMAPFILEHEADER), 1, fBitmap); - fwrite(&oInfoHeader, sizeof(BITMAPINFOHEADER), 1, fBitmap); - for(int iY = oMode.Height - 1; iY >= 0; --iY) - { - fwrite(reinterpret_cast(oLock.pBits) + oLock.Pitch * iY, - 4, oMode.Width, fBitmap); - } - fclose(fBitmap); - pSurfaceBuffer->UnlockRect(); - pSurfaceBuffer->Release(); - return true; -} - -bool THRenderTarget::startFrame() -{ - if(!m_pDevice) - { - m_sLastError = "No device"; - return false; - } - if(m_bHasLostDevice) - { - if(m_pZoomRenderSurface) - { - m_pZoomRenderSurface->Release(); - m_pZoomRenderSurface = NULL; - } - if(m_pZoomRenderTexture) - { - m_pZoomRenderTexture->Release(); - m_pZoomRenderTexture = NULL; - } - m_iZoomTextureSize = 0; - if(m_pDevice->TestCooperativeLevel() != D3DERR_DEVICENOTRESET) - return false; - D3DPRESENT_PARAMETERS oPresentParams = m_oPresentParams; - if(m_pDevice->Reset(&oPresentParams) == D3D_OK) - { - m_bHasLostDevice = false; - _initialiseDeviceSettings(); - if(hasCursor()) - setCursor(m_pCursor); - } - else - return false; - } - m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); - m_pDevice->BeginScene(); - return true; -} - -bool THRenderTarget::endFrame() -{ - if(!m_pDevice) - { - m_sLastError = "No device"; - return false; - } - flushSprites(); - _flushZoomBuffer(); - m_pDevice->EndScene(); - switch(m_pDevice->Present(NULL, NULL, NULL, NULL)) - { - case D3D_OK: - return true; - case D3DERR_DEVICELOST: - m_sLastError = "Could not present (device lost)"; - m_bHasLostDevice = true; - break; - default: - m_sLastError = "Could not present"; - break; - } - return false; -} - -bool THRenderTarget::fillBlack() -{ - if(!m_pDevice) - { - m_sLastError = "No device"; - return false; - } - m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); - return true; -} - -void THRenderTarget::setBlueFilterActive(bool bActivate) -{ - m_bBlueFilterActive = bActivate; - if (m_bBlueFilterActive) - { - m_pDevice->SetPixelShader(m_pPixelShader); - } - else - { - m_pDevice->SetPixelShader(NULL); - } -} - -uint32_t THRenderTarget::mapColour(uint8_t iR, uint8_t iG, uint8_t iB) -{ - return D3DCOLOR_ARGB(0xFF, iR, iG, iB); -} - -bool THRenderTarget::fillRect(uint32_t iColour, int iX, int iY, int iW, int iH) -{ - draw(m_pWhiteTexture, iW, iH, iX, iY, 0, 1, 1, 0, 0); - THDX9_Vertex* pVerts = m_pVerticies + m_iVertexCount; - for(int i = 1; i <= 4; ++i) - { - pVerts[-i].colour = iColour; - } - return true; -} - -void THRenderTarget::getClipRect(THClipRect* pRect) const -{ - *pRect = m_rcClip; -} - -int THRenderTarget::getWidth() const -{ - return m_iWidth; -} - -int THRenderTarget::getHeight() const -{ - return m_iHeight; -} - -void THRenderTarget::setClipRect(const THClipRect* pRect) -{ - if(pRect != NULL) - { - m_rcClip = *pRect; - } - else - { - m_rcClip.x = -1000; - m_rcClip.y = -1000; - m_rcClip.w = 0xFFFF; - m_rcClip.h = 0xFFFF; - } -} - -void THRenderTarget::startNonOverlapping() -{ - if(m_iNonOverlapping++ == 0) - m_iNonOverlappingStart = m_iVertexCount; -} - -static int sprite_tex_compare(const void* left, const void* right) -{ - const THDX9_Vertex *pLeft = reinterpret_cast(left); - const THDX9_Vertex *pRight = reinterpret_cast(right); - - if(pLeft->tex == pRight->tex) - return 0; - else if(pLeft->tex < pRight->tex) - return -1; - else - return 1; -} - -void THRenderTarget::finishNonOverlapping() -{ - if(--m_iNonOverlapping > 0) - return; - - // If more than one texture is used in the range of non-overlapping - // sprites, then sort the entire range by texture. - - size_t iStart = m_iNonOverlappingStart; - IDirect3DTexture9 *pTexture = m_pVerticies[iStart].tex; - for(size_t i = iStart + 4; i < m_iVertexCount; i += 4) - { - if(m_pVerticies[i].tex != pTexture) - { - qsort(m_pVerticies + iStart, (m_iVertexCount - iStart) / 4, - sizeof(THDX9_Vertex) * 4, sprite_tex_compare); - break; - } - } -} - -THPalette::THPalette() -{ -} - -static const unsigned char gs_iTHColourLUT[0x40] = { - // Maps 0-63 to 0-255 - 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, - 0x20, 0x24, 0x28, 0x2D, 0x31, 0x35, 0x39, 0x3D, - 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, - 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, - 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, - 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, - 0xC2, 0xC6, 0xCA, 0xCE, 0xD2, 0xD7, 0xDB, 0xDF, - 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF, -}; - -bool THPalette::loadFromTHFile(const unsigned char* pData, size_t iDataLength) -{ - if(iDataLength != 256 * 3) - return false; - - m_iNumColours = static_cast(iDataLength / 3); - for(int i = 0; i < m_iNumColours; ++i, pData += 3) - { - unsigned char iR = gs_iTHColourLUT[pData[0] & 0x3F]; - unsigned char iG = gs_iTHColourLUT[pData[1] & 0x3F]; - unsigned char iB = gs_iTHColourLUT[pData[2] & 0x3F]; - D3DCOLOR iColour = D3DCOLOR_ARGB(0xFF, iR, iG, iB); - // Remap magenta to transparent - if(iColour == D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0xFF)) - iColour = D3DCOLOR_ARGB(0x00, 0x00, 0x00, 0x00); - m_aColoursARGB[i] = iColour; - } - - return true; -} - -bool THPalette::setEntry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB) -{ - if(iEntry < 0 || iEntry >= m_iNumColours) - return false; - D3DCOLOR iColour = D3DCOLOR_ARGB(0xFF, iR, iG, iB); - // Remap magenta to transparent - if(iColour == D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0xFF)) - iColour = D3DCOLOR_ARGB(0x00, 0x00, 0x00, 0x00); - m_aColoursARGB[iEntry] = iColour; - return true; -} - -int THPalette::getColourCount() const -{ - return m_iNumColours; -} - -const uint32_t* THPalette::getARGBData() const -{ - return m_aColoursARGB; -} - -IDirect3DTexture9* THDX9_CreateSolidTexture(int iWidth, int iHeight, - uint32_t iColour, - IDirect3DDevice9* pDevice) -{ - IDirect3DTexture9 *pTexture = NULL; - if(pDevice->CreateTexture(iWidth, iHeight, 1, 0, D3DFMT_A8R8G8B8, - D3DPOOL_MANAGED, &pTexture, NULL) != D3D_OK || pTexture == NULL) - { - return NULL; - } - D3DLOCKED_RECT rcLocked; - if(pTexture->LockRect(0, &rcLocked, NULL, D3DLOCK_DISCARD) != D3D_OK) - { - pTexture->Release(); - return NULL; - } - - uint8_t* pData = reinterpret_cast(rcLocked.pBits); - for(int y = 0; y < iHeight; ++y, pData += rcLocked.Pitch) - { - uint32_t* pRow = reinterpret_cast(pData); - for(int x = 0; x < iWidth; ++x, ++pRow) - { - *pRow = iColour; - } - } - - pTexture->UnlockRect(0); - return pTexture; -} - -IDirect3DTexture9* THDX9_CreateTexture(int iWidth, int iHeight, - const unsigned char* pPixels, - const THPalette* pPalette, - IDirect3DDevice9* pDevice, - int* pWidth2, - int* pHeight2) -{ - int iWidth2 = 1; - int iHeight2 = 1; - while(iWidth2 < iWidth) - iWidth2 <<= 1; - while(iHeight2 < iHeight) - iHeight2 <<= 1; - if(pWidth2) - *pWidth2 = iWidth2; - if(pHeight2) - *pHeight2 = iHeight2; - - // It might seem attractive to try and use 8-bit paletted textures rather - // than 32-bit RGBA textures, but very few cards support 8-bit textures, so - // it isn't worth implementing. - - IDirect3DTexture9 *pTexture = NULL; - if(pDevice->CreateTexture(iWidth2, iHeight2, 1, 0, D3DFMT_A8R8G8B8, - D3DPOOL_MANAGED, &pTexture, NULL) != D3D_OK || pTexture == NULL) - { - return NULL; - } - D3DLOCKED_RECT rcLocked; - if(pTexture->LockRect(0, &rcLocked, NULL, D3DLOCK_DISCARD) != D3D_OK) - { - pTexture->Release(); - return NULL; - } - - uint8_t* pData = reinterpret_cast(rcLocked.pBits); - const uint32_t* pColours = pPalette->getARGBData(); - for(int y = 0; y < iHeight; ++y, pData += rcLocked.Pitch) - { - uint32_t* pRow = reinterpret_cast(pData); - for(int x = 0; x < iWidth; ++x, ++pPixels, ++pRow) - { - *pRow = pColours[*pPixels]; - } - for(int x = iWidth; x < iWidth2; ++x, ++pRow) - { - *pRow = D3DCOLOR_ARGB(0, 0, 0, 0); - } - } - for(int y = iHeight; y < iHeight2; ++y, pData += rcLocked.Pitch) - { - uint32_t* pRow = reinterpret_cast(pData); - for(int x = 0; x < iWidth2; ++x, ++pRow) - { - *pRow = D3DCOLOR_ARGB(0, 0, 0, 0); - } - } - - pTexture->UnlockRect(0); - return pTexture; -} - -THDX9_Vertex* THRenderTarget::allocVerticies(size_t iCount, - IDirect3DTexture9* pTexture) -{ - if(m_iVertexCount + iCount > m_iVertexLength) - { - m_iVertexLength = (m_iVertexLength * 2) + iCount; - m_pVerticies = (THDX9_Vertex*)realloc(m_pVerticies, - sizeof(THDX9_Vertex) * m_iVertexLength); - } - THDX9_Vertex *pResult = m_pVerticies + m_iVertexCount; - pResult[0].tex = pTexture; - m_iVertexCount += iCount; - return pResult; -} - -void THRenderTarget::_drawVerts(size_t iFirst, size_t iLast) -{ - // Note: Convential wisdom might suggest that DrawIndexedPrimitive - // would be more efficient to use than DrawIndexedPrimitiveUP, however the - // vertex buffer would have to be modified each frame. My experiments have - // shown that using vertex buffers and index buffers yields no frame rate - // increase, whilst still increasing the complexity. Therefore the code - // should stick to using DrawIndexedPrimitiveUP for the immediate future. - - UINT iCount = static_cast(iLast - iFirst); - m_pDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, iCount, - iCount / 2, m_aiVertexIndicies, D3DFMT_INDEX16, m_pVerticies + iFirst, - static_cast(sizeof(THDX9_Vertex))); -} - -void THRenderTarget::flushSprites() -{ - if(m_iVertexCount == 0) - return; - - IDirect3DTexture9 *pTexture = m_pVerticies[0].tex; - m_pDevice->SetTexture(0, pTexture); - size_t iStart = 0; - size_t iIndexCount = 0; - for(size_t i = 4; i < m_iVertexCount; i += 4) - { - iIndexCount += 6; - if(m_pVerticies[i].tex != pTexture || - iIndexCount == THDX9_INDEX_BUFFER_LENGTH) - { - _drawVerts(iStart, i); - iIndexCount = 0; - iStart = i; - pTexture = m_pVerticies[i].tex; - m_pDevice->SetTexture(0, pTexture); - } - } - _drawVerts(iStart, m_iVertexCount); - - m_iVertexCount = 0; -} - -THRawBitmap::THRawBitmap() -{ - fnOnDeviceChange = THDX9_OnDeviceChangeThunk; - m_pBitmap = NULL; - m_pPalette = NULL; - m_iWidth = -1; - m_iHeight = -1; -} - -THRawBitmap::~THRawBitmap() -{ - if(m_pBitmap) - m_pBitmap->Release(); -} - -void THRawBitmap::onDeviceChange(eTHDX9DeviceChangeType eChangeType) -{ - if(m_pBitmap) - { - m_pBitmap->Release(); - m_pBitmap = NULL; - } - removeFromList(); -} - -void THRawBitmap::setPalette(const THPalette* pPalette) -{ - m_pPalette = pPalette; -} - -bool THRawBitmap::loadFromTHFile(const unsigned char* pPixelData, - size_t iPixelDataLength, - int iWidth, THRenderTarget *pEventualCanvas) -{ - if(m_pPalette == NULL || pEventualCanvas == NULL) - return false; - - if(m_pBitmap) - { - m_pBitmap->Release(); - m_pBitmap = NULL; - } - - m_iWidth = iWidth; - m_iHeight = static_cast(iPixelDataLength) / iWidth; - m_pBitmap = THDX9_CreateTexture(iWidth, m_iHeight, pPixelData, m_pPalette, - pEventualCanvas->getRawDevice(this), &m_iWidth2, &m_iHeight2); - - return m_pBitmap != NULL; -} - -void THRawBitmap::draw(THRenderTarget* pCanvas, int iX, int iY) -{ - pCanvas->draw(m_pBitmap, m_iWidth, m_iHeight, iX, iY, 0, m_iWidth2, - m_iHeight2, 0, 0); -} - -void THRawBitmap::draw(THRenderTarget* pCanvas, int iX, int iY, - int iSrcX, int iSrcY, int iWidth, int iHeight) -{ - pCanvas->draw(m_pBitmap, iWidth, iHeight, iX, iY, 0, m_iWidth2, m_iHeight2, - iSrcX, iSrcY); -} - -THSpriteSheet::THSpriteSheet() -{ - fnOnDeviceChange = THDX9_OnDeviceChangeThunk; - m_pSprites = 0; - m_iSpriteCount = 0; - m_pPalette = NULL; - m_pDevice = NULL; - m_pMegaSheet = NULL; -} - -THSpriteSheet::~THSpriteSheet() -{ - _freeSprites(); -} - -void THSpriteSheet::onDeviceChange(eTHDX9DeviceChangeType eChangeType) -{ - _freeSprites(); -} - -void THSpriteSheet::_freeSprites() -{ - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - if(m_pSprites[i].pBitmap && m_pSprites[i].pBitmap != m_pMegaSheet) - m_pSprites[i].pBitmap->Release(); - if(m_pSprites[i].pAltBitmap) - m_pSprites[i].pAltBitmap->Release(); - if(m_pSprites[i].pData) - delete[] m_pSprites[i].pData; - } - if(m_pMegaSheet) - { - m_pMegaSheet->Release(); - m_pMegaSheet = NULL; - } - delete[] m_pSprites; - m_pSprites = NULL; - m_iSpriteCount = 0; - if(m_pDevice) - { - m_pDevice->Release(); - m_pDevice = NULL; - } - removeFromList(); -} - -void THSpriteSheet::setPalette(const THPalette* pPalette) -{ - m_pPalette = pPalette; -} - -bool THSpriteSheet::loadFromTHFile( - const unsigned char* pTableData, size_t iTableDataLength, - const unsigned char* pChunkData, size_t iChunkDataLength, - bool bComplexChunks, THRenderTarget* pCanvas) -{ - _freeSprites(); - if(pCanvas == NULL) - { - return false; - } - m_pDevice = pCanvas->getRawDevice(this); - m_pDevice->AddRef(); - - m_iSpriteCount = (unsigned int)(iTableDataLength / sizeof(th_sprite_t)); - m_pSprites = new (std::nothrow) sprite_t[m_iSpriteCount]; - if(m_pSprites == NULL) - { - m_iSpriteCount = 0; - return false; - } - - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - sprite_t *pSprite = m_pSprites + i; - const th_sprite_t *pTHSprite = reinterpret_cast(pTableData) + i; - - pSprite->pBitmap = NULL; - pSprite->pAltBitmap = NULL; - pSprite->pData = NULL; - pSprite->pAltPaletteMap = NULL; - pSprite->iWidth = pTHSprite->width; - pSprite->iHeight = pTHSprite->height; - pSprite->iWidth2 = 1; - pSprite->iHeight2 = 1; - while(pSprite->iWidth2 < pSprite->iWidth) - pSprite->iWidth2 <<= 1; - while(pSprite->iHeight2 < pSprite->iHeight) - pSprite->iHeight2 <<= 1; - - if(pSprite->iWidth == 0 || pSprite->iHeight == 0) - continue; - - { - unsigned char *pData = new unsigned char[pSprite->iWidth * pSprite->iHeight]; - THChunkRenderer oRenderer(pSprite->iWidth, pSprite->iHeight, pData); - int iDataLen = static_cast(iChunkDataLength) - static_cast(pTHSprite->position); - if(iDataLen < 0 || iDataLen > static_cast(iChunkDataLength)) - iDataLen = 0; - oRenderer.decodeChunks(pChunkData + pTHSprite->position, iDataLen, bComplexChunks); - pSprite->pData = oRenderer.takeData(); - } - } - - sprite_t **ppSortedSprites = new sprite_t*[m_iSpriteCount]; - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - ppSortedSprites[i] = m_pSprites + i; - } - qsort(ppSortedSprites, m_iSpriteCount, sizeof(sprite_t*), _sortSpritesHeight); - - unsigned int iSize; - if(_tryFitSingleTex(ppSortedSprites, 2048)) - { - iSize = 2048; - if(_tryFitSingleTex(ppSortedSprites, 1024)) - { - iSize = 1024; - if(_tryFitSingleTex(ppSortedSprites, 512)) - { - iSize = 512; - if(_tryFitSingleTex(ppSortedSprites, 256)) - { - iSize = 256; - if(_tryFitSingleTex(ppSortedSprites, 128)) - iSize = 128; - } - } - } - } - else - { - delete[] ppSortedSprites; - return true; - } - - _makeSingleTex(ppSortedSprites, iSize); - delete[] ppSortedSprites; - return true; -} - -void THSpriteSheet::_makeSingleTex(sprite_t** ppSortedSprites, unsigned int iSize) -{ - IDirect3DTexture9 *pTexture = NULL; - if(m_pDevice->CreateTexture(iSize, iSize, 1, 0, D3DFMT_A8R8G8B8, - D3DPOOL_MANAGED, &pTexture, NULL) != D3D_OK || pTexture == NULL) - { - return; - } - D3DLOCKED_RECT rcLocked; - if(pTexture->LockRect(0, &rcLocked, NULL, D3DLOCK_DISCARD) != D3D_OK) - { - pTexture->Release(); - return; - } - - // Pass 1: Fill entirely transparent - uint8_t* pData = reinterpret_cast(rcLocked.pBits); - for(unsigned int y = 0; y < iSize; ++y, pData += rcLocked.Pitch) - { - uint32_t* pRow = reinterpret_cast(pData); - for(unsigned int x = 0; x < iSize; ++x, ++pRow) - { - *pRow = D3DCOLOR_ARGB(0, 0, 0, 0); - } - } - - // Pass 2: Blit sprites onto sheet - const uint32_t* pColours = m_pPalette->getARGBData(); - unsigned int iX = 0; - unsigned int iY = 0; - unsigned int iTallest = ppSortedSprites[0]->iHeight; - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - sprite_t *pSprite = ppSortedSprites[i]; - if(pSprite->pData == NULL) - break; - - pSprite->pBitmap = pTexture; - if(iX + pSprite->iWidth > iSize) - { - iX = 0; - iY += iTallest; - iTallest = pSprite->iHeight; - } - pSprite->iSheetX = iX; - pSprite->iSheetY = iY; - iX += pSprite->iWidth; - - const unsigned char *pPixels = pSprite->pData; - uint8_t* pData = reinterpret_cast(rcLocked.pBits); - pData += pSprite->iSheetY * rcLocked.Pitch + pSprite->iSheetX * 4; - for(unsigned int y = 0; y < pSprite->iHeight; ++y, pData += rcLocked.Pitch) - { - uint32_t* pRow = reinterpret_cast(pData); - for(unsigned int x = 0; x < pSprite->iWidth; ++x, ++pRow, ++pPixels) - { - *pRow = pColours[*pPixels]; - } - } - } - - pTexture->UnlockRect(0); - m_pMegaSheet = pTexture; - m_iMegaSheetSize = iSize; -} - -int THSpriteSheet::_sortSpritesHeight(const void* left, const void* right) -{ - const sprite_t *pLeft = *reinterpret_cast(left); - const sprite_t *pRight = *reinterpret_cast(right); - - // Move all NULL datas to the end - if(pLeft->pData == NULL || pRight->pData == NULL) - { - if(pLeft->pData == NULL && pRight->pData == NULL) - return 0; - if(pLeft->pData == NULL) - return 1; - else - return -1; - } - - // Sort from tallest to shortest - return static_cast(pRight->iHeight) - static_cast(pLeft->iHeight); -} - -bool THSpriteSheet::_tryFitSingleTex(sprite_t** ppSortedSprites, unsigned int iSize) -{ - // There are probably better algorithms for trying to fit lots of small - // rectangular sprites onto a single square sheet, but sorting them by - // height and then filling up one row at a time is simple and yields a good - // enough result. - - unsigned int iX = 0; - unsigned int iY = 0; - unsigned int iTallest = ppSortedSprites[0]->iHeight; - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - sprite_t *pSprite = ppSortedSprites[i]; - if(pSprite->pData == NULL) - break; - if(pSprite->iWidth > iSize || pSprite->iHeight > iSize) - return false; - if(iX + pSprite->iWidth > iSize) - { - iX = 0; - iY += iTallest; - iTallest = pSprite->iHeight; - } - iX += pSprite->iWidth; - } - - iY += iTallest; - return iY <= iSize; -} - -void THSpriteSheet::setSpriteAltPaletteMap(unsigned int iSprite, const unsigned char* pMap) -{ - if(iSprite >= m_iSpriteCount) - return; - - sprite_t *pSprite = m_pSprites + iSprite; - if(pSprite->pAltPaletteMap != pMap) - { - pSprite->pAltPaletteMap = pMap; - if(pSprite->pAltBitmap) - { - pSprite->pAltBitmap->Release(); - pSprite->pAltBitmap = NULL; - } - } -} - -unsigned int THSpriteSheet::getSpriteCount() const -{ - return m_iSpriteCount; -} - -bool THSpriteSheet::getSpriteSize(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const -{ - if(iSprite >= m_iSpriteCount) - return false; - if(pX != NULL) - *pX = m_pSprites[iSprite].iWidth; - if(pY != NULL) - *pY = m_pSprites[iSprite].iHeight; - return true; -} - -void THSpriteSheet::getSpriteSizeUnchecked(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const -{ - *pX = m_pSprites[iSprite].iWidth; - *pY = m_pSprites[iSprite].iHeight; -} - -bool THSpriteSheet::getSpriteAverageColour(unsigned int iSprite, THColour* pColour) const -{ - if(iSprite >= m_iSpriteCount) - return false; - const sprite_t *pSprite = m_pSprites + iSprite; - int iCountTotal = 0; - int iUsageCounts[256] = {0}; - for(unsigned int i = 0; i < pSprite->iWidth * pSprite->iHeight; ++i) - { - unsigned char cPalIndex = pSprite->pData[i]; - uint32_t iColour = m_pPalette->getARGBData()[cPalIndex]; - if((iColour >> 24) == 0) - continue; - // Grant higher score to pixels with high or low intensity (helps avoid grey fonts) - unsigned char iR = static_cast ((iColour >> 16) & 0xFF); - unsigned char iG = static_cast ((iColour >> 8) & 0xFF); - unsigned char iB = static_cast ((iColour >> 0) & 0xFF); - unsigned char cIntensity = (unsigned char)(((int)iR + (int)iG + (int)iB) / 3); - int iScore = 1 + max(0, 3 - ((255 - cIntensity) / 32)) + max(0, 3 - (cIntensity / 32)); - iUsageCounts[cPalIndex] += iScore; - iCountTotal += iScore; - } - if(iCountTotal == 0) - return false; - int iHighestCountIndex = 0; - for(int i = 0; i < 256; ++i) - { - if(iUsageCounts[i] > iUsageCounts[iHighestCountIndex]) - iHighestCountIndex = i; - } - *pColour = m_pPalette->getARGBData()[iHighestCountIndex]; - return true; -} - -void THSpriteSheet::drawSprite(THRenderTarget* pCanvas, unsigned int iSprite, int iX, int iY, unsigned long iFlags) -{ - if(iSprite >= m_iSpriteCount || pCanvas == NULL) - return; - sprite_t *pSprite = m_pSprites + iSprite; - - // Find or create the texture - IDirect3DTexture9 *pTexture = pSprite->pBitmap; - if(pTexture == NULL) - { - if(pSprite->pData == NULL) - return; - - pTexture = THDX9_CreateTexture(pSprite->iWidth, pSprite->iHeight, - pSprite->pData, m_pPalette, m_pDevice); - pSprite->pBitmap = pTexture; - } - if(iFlags & THDF_AltPalette) - { - pTexture = pSprite->pAltBitmap; - if(pTexture == NULL) - { - pTexture = _makeAltBitmap(pSprite); - if(pTexture == NULL) - return; - } - } - - if(pTexture == m_pMegaSheet) - { - pCanvas->draw(pTexture, m_pSprites[iSprite].iWidth, - m_pSprites[iSprite].iHeight, iX, iY, iFlags, m_iMegaSheetSize, - m_iMegaSheetSize, m_pSprites[iSprite].iSheetX, - m_pSprites[iSprite].iSheetY); - } - else - { - pCanvas->draw(pTexture, m_pSprites[iSprite].iWidth, - m_pSprites[iSprite].iHeight, iX, iY, iFlags, - m_pSprites[iSprite].iWidth2, m_pSprites[iSprite].iHeight2, 0, 0); - } -} - -bool THSpriteSheet::hitTestSprite(unsigned int iSprite, int iX, int iY, unsigned long iFlags) const -{ - if(iX < 0 || iY < 0 || iSprite >= m_iSpriteCount) - return false; - int iWidth = m_pSprites[iSprite].iWidth; - int iHeight = m_pSprites[iSprite].iHeight; - if(iX >= iWidth || iY >= iHeight) - return false; - if(iFlags & THDF_FlipHorizontal) - iX = iWidth - iX - 1; - if(iFlags & THDF_FlipVertical) - iY = iHeight - iY - 1; - return (m_pPalette->getARGBData() - [m_pSprites[iSprite].pData[iY * iWidth + iX]] >> 24) != 0; -} - -void THRenderTarget::draw(IDirect3DTexture9 *pTexture, unsigned int iWidth, - unsigned int iHeight, int iX, int iY, - unsigned long iFlags, unsigned int iWidth2, - unsigned int iHeight2, unsigned int iTexX, - unsigned int iTexY, D3DCOLOR cColour) -{ - // Crop to clip rectangle - RECT rcSource; - rcSource.left = 0; - rcSource.top = 0; - rcSource.right = iWidth; - rcSource.bottom = iHeight; - if(iX + rcSource.right > m_rcClip.x + m_rcClip.w) - { - rcSource.right = m_rcClip.x + m_rcClip.w - iX; - } - if(iY + rcSource.bottom > m_rcClip.y + m_rcClip.h) - { - rcSource.bottom = m_rcClip.y + m_rcClip.h - iY; - } - if(iX + rcSource.left < m_rcClip.x) - { - rcSource.left = m_rcClip.x - iX; - iX = m_rcClip.x; - } - if(iY + rcSource.top < m_rcClip.y) - { - rcSource.top = m_rcClip.y - iY; - iY = m_rcClip.y; - } - if(rcSource.right < rcSource.left) - rcSource.right = rcSource.left; - if(rcSource.bottom < rcSource.top) - rcSource.bottom = rcSource.top; - - rcSource.left += iTexX; - rcSource.right += iTexX; - rcSource.bottom += iTexY; - rcSource.top += iTexY; - - // Set alpha blending options - switch(iFlags & (THDF_Alpha50 | THDF_Alpha75)) - { - case 0: - cColour |= 0xFF000000UL; - break; - case THDF_Alpha50: - cColour |= 0x80000000UL; - break; - default: - cColour |= 0x40000000UL; - break; - } - float fX = (float)iX; - float fY = (float)iY; - float fWidth = (float)(rcSource.right - rcSource.left); - float fHeight = (float)(rcSource.bottom - rcSource.top); - float fSprWidth = (float)iWidth2; - float fSprHeight = (float)iHeight2; - if(iFlags & THDF_FlipHorizontal) - { - rcSource.left = iTexX * 2 + iWidth - rcSource.left; - rcSource.right = iTexX * 2 + iWidth - rcSource.right; - } - if(iFlags & THDF_FlipVertical) - { - rcSource.top = iTexY * 2 + iHeight - rcSource.top; - rcSource.bottom = iTexY * 2 + iHeight - rcSource.bottom; - } - -#define SetVertexData(n, x_, y_, u_, v_) \ - pVerticies[n].x = fX + (float) x_; \ - pVerticies[n].y = fY + (float) y_; \ - pVerticies[n].z = 0.0f; \ - pVerticies[n].colour = cColour; \ - pVerticies[n].u = (float) u_; \ - pVerticies[n].v = (float) v_ - - THDX9_Vertex *pVerticies = allocVerticies(4, pTexture); - SetVertexData(0, 0, 0, rcSource.left / fSprWidth, rcSource.top / fSprHeight); - SetVertexData(1, fWidth, 0, rcSource.right / fSprWidth, pVerticies[0].v); - SetVertexData(2, fWidth, fHeight, pVerticies[1].u, rcSource.bottom / fSprHeight); - SetVertexData(3, 0, fHeight, pVerticies[0].u, pVerticies[2].v); -#undef SetVertexData -} - -uint16_t gs_iIndexLUT[6] = {0, 1, 2, 0, 2, 3}; - -void THDX9_FillIndexBuffer(uint16_t* pVerticies, size_t iFirst, size_t iCount) -{ - for(; iCount > 0; ++iFirst, --iCount) - { - size_t iMod = iFirst % 6; - size_t iBase = (iFirst / 6) * 4; - pVerticies[iFirst] = static_cast(iBase) + gs_iIndexLUT[iMod]; - } -} - -IDirect3DTexture9* THSpriteSheet::_makeAltBitmap(sprite_t *pSprite) -{ - if(pSprite->pAltPaletteMap == NULL) - { - pSprite->pAltBitmap = pSprite->pBitmap; - pSprite->pAltBitmap->AddRef(); - } - else - { - int iPixelCount = pSprite->iHeight * pSprite->iWidth; - unsigned char *pData = new unsigned char[iPixelCount]; - for(int i = 0; i < iPixelCount; ++i) - { - unsigned char iPixel = pSprite->pData[i]; - if(iPixel != 0xFF) - iPixel = pSprite->pAltPaletteMap[iPixel]; - pData[i] = iPixel; - } - pSprite->pAltBitmap = THDX9_CreateTexture(pSprite->iWidth, - pSprite->iHeight, pData, m_pPalette, m_pDevice); - delete[] pData; - } - return pSprite->pAltBitmap; -} - -THCursor::THCursor() -{ - fnOnDeviceChange = THDX9_OnDeviceChangeThunk; - m_pBitmap = NULL; - m_iHotspotX = 0; - m_iHotspotY = 0; - m_bHardwareCompatible = false; -} - -THCursor::~THCursor() -{ - if(m_pBitmap) - m_pBitmap->Release(); -} - -void THCursor::onDeviceChange(eTHDX9DeviceChangeType eChangeType) -{ - if(m_pBitmap) - { - m_pBitmap->Release(); - m_pBitmap = NULL; - } - removeFromList(); -} - -bool THCursor::createFromSprite(THSpriteSheet* pSheet, unsigned int iSprite, - int iHotspotX, int iHotspotY) -{ - if(m_pBitmap) - m_pBitmap->Release(); - m_pBitmap = NULL; - m_bHardwareCompatible = false; - removeFromList(); - - if(iHotspotX < 0 || iHotspotY < 0) - return false; - - unsigned int iWidth, iHeight; - if(pSheet == NULL || !pSheet->getSpriteSize(iSprite, &iWidth, &iHeight) - || pSheet->m_pDevice == NULL) - { - return false; - } - - m_pPrev = pSheet->m_pPrev; - m_pNext = pSheet; - m_pPrev->m_pNext = this; - m_pNext->m_pPrev = this; - - // Hardware cursors must be size 32x32 - unsigned int iSize = 32; - if(iWidth > 32 || iHeight > 32) - { - m_bHardwareCompatible = false; - while(iSize < iWidth || iSize < iHeight) - iSize <<= 1; - } - else - m_bHardwareCompatible = true; - - if(pSheet->m_pDevice->CreateOffscreenPlainSurface(iSize, iSize, - D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &m_pBitmap, NULL) != D3D_OK) - { - return false; - } - - D3DLOCKED_RECT rcLocked; - if(m_pBitmap->LockRect(&rcLocked, NULL, D3DLOCK_DISCARD) != D3D_OK) - { - m_pBitmap->Release(); - m_pBitmap = NULL; - return false; - } - - const unsigned char* pPixels = pSheet->m_pSprites[iSprite].pData; - uint8_t* pData = reinterpret_cast(rcLocked.pBits); - const uint32_t* pColours = pSheet->m_pPalette->getARGBData(); - for(unsigned int y = 0; y < iHeight; ++y, pData += rcLocked.Pitch) - { - uint32_t* pRow = reinterpret_cast(pData); - for(unsigned int x = 0; x < iWidth; ++x, ++pPixels, ++pRow) - { - uint32_t iColour = pColours[*pPixels]; - // Cursors cannot have semi-transparency - if((iColour >> 24) != 0) - iColour |= 0xFF000000; - *pRow = iColour; - } - for(unsigned int x = iWidth; x < iSize; ++x, ++pRow) - { - *pRow = D3DCOLOR_ARGB(0, 0, 0, 0); - } - } - for(unsigned int y = iHeight; y < iSize; ++y, pData += rcLocked.Pitch) - { - uint32_t* pRow = reinterpret_cast(pData); - for(unsigned int x = 0; x < iSize; ++x, ++pRow) - { - *pRow = D3DCOLOR_ARGB(0, 0, 0, 0); - } - } - - m_pBitmap->UnlockRect(); - return true; -} - -void THRenderTarget::setCursor(THCursor* pCursor) -{ - SetCursor(NULL); - m_pDevice->SetCursorProperties(pCursor->m_iHotspotX, - pCursor->m_iHotspotY, pCursor->m_pBitmap); - m_pDevice->ShowCursor(TRUE); - m_pCursor = pCursor; - m_bIsCursorInHardware = m_bIsWindowed || (m_bIsHardwareCursorSupported && - pCursor->m_bHardwareCompatible); -} - -void THCursor::use(THRenderTarget* pTarget) -{ - pTarget->setCursor(this); -} - -bool THRenderTarget::setCursorPosition(int iX, int iY) -{ - if(m_bIsCursorInHardware) - { - // Cursor movement done by operating system / hardware - no need to do - // anything or repaint anything. - return false; - } - - m_pDevice->SetCursorPosition(iX, iY, 0); - return true; -} - -bool THCursor::setPosition(THRenderTarget* pTarget, int iX, int iY) -{ - return pTarget->setCursorPosition(iX, iY); -} - -THLine::THLine() -{ - initialize(); -} - -void THLine::initialize() -{ - m_fWidth = 1; - m_iR = 0; - m_iG = 0; - m_iB = 0; - m_iA = 255; - - // We start at 0,0 - m_pFirstOp = new THLineOperation(THLOP_MOVE, 0, 0); - m_pCurrentOp = m_pFirstOp; -} - - -THLine::~THLine() -{ - THLineOperation* op = m_pFirstOp; - while (op) { - THLineOperation* next = (THLineOperation*)(op->m_pNext); - delete(op); - op = next; - } -} - -void THLine::moveTo(double fX, double fY) -{ - THLineOperation* previous = m_pCurrentOp; - m_pCurrentOp = new THLineOperation(THLOP_MOVE, fX, fY); - previous->m_pNext = m_pCurrentOp; -} - -void THLine::lineTo(double fX, double fY) -{ - THLineOperation* previous = m_pCurrentOp; - m_pCurrentOp = new THLineOperation(THLOP_LINE, fX, fY); - previous->m_pNext = m_pCurrentOp; -} - -void THLine::setWidth(double pLineWidth) -{ - m_fWidth = pLineWidth; -} - -void THLine::setColour(uint8_t iR, uint8_t iG, uint8_t iB, uint8_t iA) -{ - m_iR = iR; - m_iG = iG; - m_iB = iB; - m_iA = iA; -} - -void THLine::draw(THRenderTarget* pCanvas, int iX, int iY) -{ - pCanvas->flushSprites(); // Without this the lines are draw behind sprites/textures - - IDirect3DDevice9* device = pCanvas->getRawDevice(); - device->BeginScene(); - - double lastX, lastY; - lastX = m_pFirstOp->m_fX; - lastY = m_pFirstOp->m_fY; - - D3DCOLOR colour = D3DCOLOR_ARGB(m_iA, m_iR, m_iG, m_iB); - - LPD3DXLINE line = NULL; - THLineOperation* op = (THLineOperation*)(m_pFirstOp->m_pNext); - while (op) { - if (op->type == THLOP_LINE) { - if (!line) { - D3DXCreateLine(device, &line); - line->SetWidth(m_fWidth); - line->Begin(); - } - - D3DXVECTOR2 lineVec[] = {D3DXVECTOR2(lastX + iX, lastY +iY), D3DXVECTOR2(op->m_fX + iX, op->m_fY + iY)}; - line->Draw(lineVec, 2, colour); - - } if (op->type == THLOP_MOVE && line) { - line->End(); - line->Release(); - line = NULL; - } - - lastX = op->m_fX; - lastY = op->m_fY; - - op = (THLineOperation*)(op->m_pNext); - } - - if (line) { - line->End(); - line->Release(); - } - - device->EndScene(); -} - -void THLine::persist(LuaPersistWriter *pWriter) const -{ - pWriter->writeVUInt((uint32_t)m_iR); - pWriter->writeVUInt((uint32_t)m_iG); - pWriter->writeVUInt((uint32_t)m_iB); - pWriter->writeVUInt((uint32_t)m_iA); - pWriter->writeVFloat(m_fWidth); - - THLineOperation* op = (THLineOperation*)(m_pFirstOp->m_pNext); - uint32_t numOps = 0; - for (; op; numOps++) { - op = (THLineOperation*)(op->m_pNext); - } - - pWriter->writeVUInt(numOps); - - op = (THLineOperation*)(m_pFirstOp->m_pNext); - while (op) { - pWriter->writeVUInt((uint32_t)op->type); - pWriter->writeVFloat(op->m_fX); - pWriter->writeVFloat(op->m_fY); - - op = (THLineOperation*)(op->m_pNext); - } -} - -void THLine::depersist(LuaPersistReader *pReader) -{ - initialize(); - - pReader->readVUInt(m_iR); - pReader->readVUInt(m_iG); - pReader->readVUInt(m_iB); - pReader->readVUInt(m_iA); - pReader->readVFloat(m_fWidth); - - uint32_t numOps = 0; - pReader->readVUInt(numOps); - for (uint32_t i = 0; i < numOps; i++) { - THLineOpType type; - double fX, fY; - pReader->readVUInt((uint32_t&)type); - pReader->readVFloat(fX); - pReader->readVFloat(fY); - - if (type == THLOP_MOVE) { - moveTo(fX, fY); - } else if (type == THLOP_LINE) { - lineTo(fX, fY); - } - } -} - -#ifdef CORSIX_TH_USE_FREETYPE2 -bool THFreeTypeFont::_isMonochrome() const -{ - return false; -} - -void THFreeTypeFont::_setNullTexture(cached_text_t* pCacheEntry) const -{ - pCacheEntry->pTexture = NULL; -} - -class THDX9_FontTexture : public THDX9_DeviceResource -{ -public: - THDX9_FontTexture() - { - fnOnDeviceChange = THDX9_OnDeviceChangeThunk; - m_pDevice = NULL; - m_pTexture = NULL; - m_pData = NULL; - m_iWidth = 0; - m_iHeight = 0; - } - - ~THDX9_FontTexture() - { - if(m_pTexture != NULL) - m_pTexture->Release(); - } - - void make(unsigned char* pData, int iWidth, int iHeight) - { - m_pData = pData; - m_iWidth = iWidth; - m_iHeight = iHeight; - if(m_pTexture != NULL) - { - m_pTexture->Release(); - m_pTexture = NULL; - m_pDevice = NULL; - } - removeFromList(); - } - - void onDeviceChange(eTHDX9DeviceChangeType eChangeType) - { - if(m_pTexture) - { - m_pTexture->Release(); - m_pTexture = NULL; - } - removeFromList(); - } - - void draw(THRenderTarget* pCanvas, int iX, int iY, uint32_t iColour) - { - if(m_pTexture == NULL || pCanvas->getRawDevice() != m_pDevice) - { - _makeFor(pCanvas); - } - if(m_pTexture) - { - if(m_bIsA8Texture) - { - pCanvas->flushSprites(); - m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_CURRENT); - } - pCanvas->draw(m_pTexture, m_iWidth, m_iHeight, iX, iY, 0, m_iWidth2, m_iHeight2, 0, 0, iColour & 0xFFFFFF); - pCanvas->flushSprites(); - if(m_bIsA8Texture) - { - m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - } - } - } - -protected: - static int _roundUp2(int x) - { - int rounded = 1; - while(rounded < x) - rounded <<= 1; - return rounded; - } - - void _makeFor(THRenderTarget* pCanvas) - { - removeFromList(); - if(m_pTexture != NULL) - { - m_pTexture->Release(); - m_pTexture = NULL; - } - m_pDevice = pCanvas->getRawDevice(this); - - D3DCAPS9 oCaps; - bool bGotCaps = SUCCEEDED(m_pDevice->GetDeviceCaps(&oCaps)); - - // Get power of 2 sizes - m_iWidth2 = _roundUp2(m_iWidth); - m_iHeight2 = _roundUp2(m_iHeight); - if(m_iWidth2 != m_iHeight2 && (!bGotCaps - || (oCaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY))) - { - if(m_iWidth2 < m_iHeight2) - m_iWidth2 = m_iHeight2; - else - m_iHeight2 = m_iWidth2; - } - - // Check aspect ratio - if(bGotCaps) - { - if(m_iWidth2 < m_iHeight2) - { - if(m_iHeight2 / m_iWidth2 > static_cast(oCaps.MaxTextureAspectRatio)) - m_iWidth2 = _roundUp2(m_iHeight2 / oCaps.MaxTextureAspectRatio); - } - else - { - if(m_iWidth2 / m_iHeight2 > static_cast(oCaps.MaxTextureAspectRatio)) - m_iHeight2 = _roundUp2(m_iWidth2 / oCaps.MaxTextureAspectRatio); - } - } - - // Make the texture - if(SUCCEEDED(m_pDevice->CreateTexture(m_iWidth2, m_iHeight2, 1, 0, - D3DFMT_A8, D3DPOOL_MANAGED, &m_pTexture, NULL))) - { - m_bIsA8Texture = true; - } - else if(SUCCEEDED(m_pDevice->CreateTexture(m_iWidth2, m_iHeight2, 1, - 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTexture, NULL))) - { - m_bIsA8Texture = false; - } - else - { - return; - } - - // Copy in texture data - D3DLOCKED_RECT rcLocked; - if(m_pTexture->LockRect(0, &rcLocked, NULL, D3DLOCK_DISCARD) != D3D_OK) - { - m_pTexture->Release(); - m_pTexture = NULL; - return; - } - const unsigned char* pInRow = m_pData; - unsigned char* pOutRow = reinterpret_cast(rcLocked.pBits); - for(int iY = 0; iY < m_iHeight; ++iY, pInRow += m_iWidth, pOutRow += rcLocked.Pitch) - { - if(m_bIsA8Texture) - { - memcpy(pOutRow, pInRow, m_iWidth); - } - else - { - uint32_t iColour; - for(int iX = 0; iX < m_iWidth; ++iX) - { - iColour = (static_cast(pInRow[iX]) << 24) | 0xffffff; - reinterpret_cast(pOutRow)[iX] = iColour; - } - } - } - m_pTexture->UnlockRect(0); - } - - IDirect3DDevice9* m_pDevice; - IDirect3DTexture9* m_pTexture; - const unsigned char* m_pData; - int m_iWidth; - int m_iWidth2; - int m_iHeight; - int m_iHeight2; - bool m_bIsA8Texture; -}; - -void THFreeTypeFont::_freeTexture(cached_text_t* pCacheEntry) const -{ - if(pCacheEntry->pTexture != NULL) - { - delete reinterpret_cast(pCacheEntry->pTexture); - } -} - -void THFreeTypeFont::_makeTexture(cached_text_t* pCacheEntry) const -{ - THDX9_FontTexture *pTexture = new THDX9_FontTexture; - pTexture->make(pCacheEntry->pData, pCacheEntry->iWidth, pCacheEntry->iHeight); - pCacheEntry->pTexture = reinterpret_cast(pTexture); -} - -void THFreeTypeFont::_drawTexture(THRenderTarget* pCanvas, cached_text_t* pCacheEntry, int iX, int iY) const -{ - if(pCacheEntry->pTexture == NULL) - return; - reinterpret_cast(pCacheEntry->pTexture)->draw(pCanvas, iX, iY, m_oColour); -} -#endif // CORSIX_TH_USE_FREETYPE2 - -#endif // CORSIX_TH_USE_DX9_RENDERER diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx_dx9.h corsix-th-0.62/CorsixTH/Src/th_gfx_dx9.h --- corsix-th-0.30/CorsixTH/Src/th_gfx_dx9.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx_dx9.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,363 +0,0 @@ -/* -Copyright (c) 2009-2013 Peter "Corsix" Cawley and Edvin "Lego3" Linge - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef CORSIX_TH_TH_GFX_DX9_H_ -#define CORSIX_TH_TH_GFX_DX9_H_ -#include "config.h" -#ifdef CORSIX_TH_USE_DX9_RENDERER -#ifdef CORSIX_TH_HAS_RENDERING_ENGINE -#error More than one rendering engine enabled in config file -#endif -#define CORSIX_TH_HAS_RENDERING_ENGINE -#include -#include -#include "persist_lua.h" - -struct IDirect3D9; -struct IDirect3DDevice9; -struct IDirect3DTexture9; -struct IDirect3DSurface9; -class THCursor; -struct THRenderTargetCreationParams; - -struct THClipRect -{ - typedef int16_t xy_t; - typedef uint16_t wh_t; - xy_t x, y; - wh_t w, h; -}; - -#if CORSIX_TH_USE_PACK_PRAGMAS -#pragma pack(push) -#pragma pack(1) -#endif -struct THDX9_Vertex -{ - float x, y, z; - uint32_t colour; - float u, v; - // The texture is not part of the FVF, but is included with the vertex data - // to make it simpler to sort verticies by texture. - IDirect3DTexture9 *tex; -} CORSIX_TH_PACKED_FLAGS; - -struct THDX9_SimpleVertex -{ - float x, y, z; - //uint32_t colour; -} CORSIX_TH_PACKED_FLAGS; -#if CORSIX_TH_USE_PACK_PRAGMAS -#pragma pack(pop) -#endif - -enum eTHDX9DeviceChangeType -{ - THDX9DCT_DeviceDestroyed, -}; - -struct THDX9_DeviceResource : public THLinkList -{ - void (*fnOnDeviceChange)(THDX9_DeviceResource*, eTHDX9DeviceChangeType); -}; - -// The index buffer length must be a multiple of 6 (as 6 are used per quad). -// A 16-bit index buffer is used, hence it can only reference 2^16 verticies. -// As each quad uses 4 verticies and 6 indicies, the optimum index buffer -// length is ((2 ^ 16) / 4) * 6 == 0x18000 -#define THDX9_INDEX_BUFFER_LENGTH 0x18000 - -class THRenderTarget : protected THDX9_DeviceResource -{ -public: // External API - THRenderTarget(); - ~THRenderTarget(); - - bool create(const THRenderTargetCreationParams* pParams); - const char* getLastError(); - - bool startFrame(); - bool endFrame(); - bool fillBlack(); - void setBlueFilterActive(bool bActivate); - uint32_t mapColour(uint8_t iR, uint8_t iG, uint8_t iB); - bool fillRect(uint32_t iColour, int iX, int iY, int iW, int iH); - void getClipRect(THClipRect* pRect) const; - int getWidth() const; - int getHeight() const; - void setClipRect(const THClipRect* pRect); - void startNonOverlapping(); - void finishNonOverlapping(); - void setCursor(THCursor* pCursor); - bool setCursorPosition(int iX, int iY); - bool takeScreenshot(const char* sFile); - bool setScaleFactor(float fScale, THScaledItems eWhatToScale); - // If you add any extra methods here which are called from outside the - // rendering engine, then be sure to at least add dummy implementations - // to the other rendering engines. - -public: // Internal (this rendering engine only) API - void onDeviceChange(eTHDX9DeviceChangeType eChangeType); - - IDirect3DDevice9* getRawDevice(THDX9_DeviceResource* pUser); - IDirect3DDevice9* getRawDevice() {return m_pDevice;} - THDX9_Vertex* allocVerticies(size_t iCount, IDirect3DTexture9* pTexture); - void draw(IDirect3DTexture9 *pTexture, unsigned int iWidth, - unsigned int iHeight, int iX, int iY, unsigned long iFlags, - unsigned int iWidth2, unsigned int iHeight2, unsigned int iTexX, - unsigned int iTexY, D3DCOLOR cColour = 0xFFFFFF); - void flushSprites(); - bool hasCursor() const {return m_pCursor != NULL;} - -protected: - IDirect3D9 *m_pD3D; - IDirect3DDevice9 *m_pDevice; - THDX9_Vertex *m_pVerticies; - IDirect3DTexture9 *m_pWhiteTexture; - IDirect3DTexture9 *m_pZoomRenderTexture; - IDirect3DSurface9 *m_pZoomRenderSurface; - IDirect3DSurface9 *m_pOriginalBackBuffer; - const char *m_sLastError; - THCursor* m_pCursor; - THClipRect m_rcClip; - D3DPRESENT_PARAMETERS m_oPresentParams; - D3DCAPS9 m_oDeviceCaps; - size_t m_iVertexCount; - size_t m_iVertexLength; - size_t m_iNonOverlappingStart; - int m_iNonOverlapping; - int m_iWidth; - int m_iHeight; - int m_iZoomTextureSize; - float m_fZoomScale; - bool m_bIsWindowed; - bool m_bIsHardwareCursorSupported; - bool m_bIsCursorInHardware; - bool m_bHasLostDevice; - uint16_t m_aiVertexIndicies[THDX9_INDEX_BUFFER_LENGTH]; - - bool _initialiseDeviceSettings(); - bool _setProjectionMatrix(int iWidth, int iHeight); - void _drawVerts(size_t iFirst, size_t iLast); - void _flushZoomBuffer(); - - LPDIRECT3DPIXELSHADER9 m_pPixelShader; - HRESULT m_pResult; - bool m_bBlueFilterActive; -}; - -typedef uint32_t THColour; - -class THPalette -{ -public: // External API - THPalette(); - - bool loadFromTHFile(const unsigned char* pData, size_t iDataLength); - bool setEntry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB); - -public: // Internal (this rendering engine only) API - int getColourCount() const; - const uint32_t* getARGBData() const; - -protected: - uint32_t m_aColoursARGB[256]; - int m_iNumColours; -}; - -IDirect3DTexture9* THDX9_CreateSolidTexture(int iWidth, int iHeight, - uint32_t iColour, - IDirect3DDevice9* pDevice); - -IDirect3DTexture9* THDX9_CreateTexture(int iWidth, int iHeight, - const unsigned char* pPixels, - const THPalette* pPalette, - IDirect3DDevice9* pDevice, - int* pWidth2 = NULL, - int* pHeight2 = NULL); - -void THDX9_FillIndexBuffer(uint16_t* pVerticies, size_t iFirst, size_t iCount); - -class THRawBitmap : protected THDX9_DeviceResource -{ -public: // External API - THRawBitmap(); - ~THRawBitmap(); - - void setPalette(const THPalette* pPalette); - - bool loadFromTHFile(const unsigned char* pPixelData, size_t iPixelDataLength, - int iWidth, THRenderTarget *pEventualCanvas); - - void draw(THRenderTarget* pCanvas, int iX, int iY); - void draw(THRenderTarget* pCanvas, int iX, int iY, int iSrcX, int iSrcY, - int iWidth, int iHeight); - -public: // Internal (this rendering engine only) API - void onDeviceChange(eTHDX9DeviceChangeType eChangeType); - -protected: - IDirect3DTexture9* m_pBitmap; - const THPalette* m_pPalette; - int m_iWidth; - int m_iWidth2; - int m_iHeight; - int m_iHeight2; -}; - -class THSpriteSheet : protected THDX9_DeviceResource -{ -public: // External API - THSpriteSheet(); - ~THSpriteSheet(); - - void setPalette(const THPalette* pPalette); - - bool loadFromTHFile(const unsigned char* pTableData, size_t iTableDataLength, - const unsigned char* pChunkData, size_t iChunkDataLength, - bool bComplexChunks, THRenderTarget* pEventualCanvas); - - void setSpriteAltPaletteMap(unsigned int iSprite, const unsigned char* pMap); - - unsigned int getSpriteCount() const; - bool getSpriteSize(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const; - void getSpriteSizeUnchecked(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const; - - bool getSpriteAverageColour(unsigned int iSprite, THColour* pColour) const; - - void drawSprite(THRenderTarget* pCanvas, unsigned int iSprite, int iX, int iY, unsigned long iFlags); - bool hitTestSprite(unsigned int iSprite, int iX, int iY, unsigned long iFlags) const; - -public: // Internal (this rendering engine only) API - void onDeviceChange(eTHDX9DeviceChangeType eChangeType); - -protected: - friend class THCursor; -#if CORSIX_TH_USE_PACK_PRAGMAS -#pragma pack(push) -#pragma pack(1) -#endif - struct th_sprite_t - { - uint32_t position; - unsigned char width; - unsigned char height; - } CORSIX_TH_PACKED_FLAGS; -#if CORSIX_TH_USE_PACK_PRAGMAS -#pragma pack(pop) -#endif - - struct sprite_t - { - IDirect3DTexture9 *pBitmap; - IDirect3DTexture9 *pAltBitmap; - unsigned char *pData; - const unsigned char *pAltPaletteMap; - unsigned int iSheetX; - unsigned int iSheetY; - unsigned int iWidth; - unsigned int iHeight; - unsigned int iWidth2; - unsigned int iHeight2; - } *m_pSprites; - const THPalette* m_pPalette; - IDirect3DDevice9* m_pDevice; - IDirect3DTexture9* m_pMegaSheet; - unsigned int m_iMegaSheetSize; - unsigned int m_iSpriteCount; - - void _freeSprites(); - bool _tryFitSingleTex(sprite_t** ppSortedSprites, unsigned int iSize); - void _makeSingleTex(sprite_t** ppSortedSprites, unsigned int iSize); - IDirect3DTexture9* _makeAltBitmap(sprite_t *pSprite); - static int _sortSpritesHeight(const void*, const void*); -}; - -class THCursor : protected THDX9_DeviceResource -{ -public: // External API - THCursor(); - ~THCursor(); - - bool createFromSprite(THSpriteSheet* pSheet, unsigned int iSprite, - int iHotspotX = 0, int iHotspotY = 0); - - void use(THRenderTarget* pTarget); - - static bool setPosition(THRenderTarget* pTarget, int iX, int iY); - -public: // Internal (this rendering engine only) API - void onDeviceChange(eTHDX9DeviceChangeType eChangeType); - -protected: - friend class THRenderTarget; - - IDirect3DSurface9* m_pBitmap; - unsigned int m_iHotspotX; - unsigned int m_iHotspotY; - bool m_bHardwareCompatible; -}; - -class THLine -{ -public: - THLine(); - ~THLine(); - - void moveTo(double fX, double fY); - - void lineTo(double fX, double fY); - - void setWidth(double lineWidth); - - void draw(THRenderTarget* pCanvas, int iX, int iY); - - void setColour(uint8_t iR, uint8_t iG, uint8_t iB, uint8_t iA = 255); - - void persist(LuaPersistWriter *pWriter) const; - void depersist(LuaPersistReader *pReader); - -protected: - void initialize(); - - enum THLineOpType { - THLOP_MOVE, - THLOP_LINE - }; - - struct THLineOperation : public THLinkList - { - THLineOpType type; - double m_fX, m_fY; - THLineOperation(THLineOpType type, double m_fX, double m_fY) : type(type), m_fX(m_fX), m_fY(m_fY) { - m_pNext = NULL; - } - }; - - THLineOperation* m_pFirstOp; - THLineOperation* m_pCurrentOp; - double m_fWidth; - uint8_t m_iR, m_iG, m_iB, m_iA; -}; - -#endif // CORSIX_TH_USE_DX9_RENDERER -#endif // CORSIX_TH_TH_GFX_DX9_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx_font.cpp corsix-th-0.62/CorsixTH/Src/th_gfx_font.cpp --- corsix-th-0.30/CorsixTH/Src/th_gfx_font.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx_font.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -1,8 +1,7 @@ /* Copyright (c) 2010 Peter "Corsix" Cawley -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do @@ -27,10 +26,13 @@ #include #include #endif +#include +#include +#include -static unsigned int utf8next(const char*& sString) +static unsigned int next_utf8_codepoint(const char*& sString) { - unsigned int iCode = *reinterpret_cast(sString++); + unsigned int iCode = *reinterpret_cast(sString++); unsigned int iContinuation; if(iCode & 0x80) { @@ -43,7 +45,7 @@ else { #define CONTINUATION_CHAR \ - iContinuation = *reinterpret_cast(sString); \ + iContinuation = *reinterpret_cast(sString); \ if((iContinuation & 0xC0) != 0x80) \ /* Invalid encoding: not enough continuation characters. */ \ return 0xFFFD; \ @@ -79,12 +81,12 @@ // Since these functions are only used when we use freetype2, this silences // warnings about defined and not used. -static unsigned int utf8decode(const char* sString) +static unsigned int decode_utf8(const char* sString) { - return utf8next(sString); + return next_utf8_codepoint(sString); } -static const char* utf8prev(const char* sString) +static const char* previous_utf8_codepoint(const char* sString) { do { @@ -94,33 +96,25 @@ } #endif -THFont::THFont() +bitmap_font::bitmap_font() { + sheet = nullptr; + letter_spacing = 0; + line_spacing = 0; } -THFont::~THFont() +void bitmap_font::set_sprite_sheet(sprite_sheet* pSpriteSheet) { + sheet = pSpriteSheet; } -THBitmapFont::THBitmapFont() +void bitmap_font::set_separation(int iCharSep, int iLineSep) { - m_pSpriteSheet = NULL; - m_iCharSep = 0; - m_iLineSep = 0; + letter_spacing = iCharSep; + line_spacing = iLineSep; } -void THBitmapFont::setSpriteSheet(THSpriteSheet* pSpriteSheet) -{ - m_pSpriteSheet = pSpriteSheet; -} - -void THBitmapFont::setSeparation(int iCharSep, int iLineSep) -{ - m_iCharSep = iCharSep; - m_iLineSep = iLineSep; -} - -static const uint16_t g_aUnicodeToCP437[0x60] = { +static const uint16_t unicode_to_cp437_table[0x60] = { 0xFF, 0xAD, 0x9B, 0x9C, 0x3F, 0x9D, 0x3F, 0x3F, 0x3F, 0x3F, 0xA6, 0xAE, 0xAA, 0x3F, 0x3F, 0x3F, 0xF8, 0xF1, 0xFD, 0x3F, 0x3F, 0x3F, 0x3F, 0xFA, 0x3F, 0x3F, 0xA7, 0xAF, 0xAC, 0xAB, 0x3F, 0xA8, 0x3F, 0x3F, 0x3F, 0x3F, @@ -131,14 +125,14 @@ 0x93, 0x3F, 0x94, 0xF6, 0x3F, 0x97, 0xA3, 0x96, 0x81, 0x3F, 0x3F, 0x98 }; -static unsigned int unicodeToCodepage437(unsigned int iCodePoint) +static unsigned int unicode_to_codepage_437(unsigned int iCodePoint) { if(iCodePoint < 0x80) return iCodePoint; if(iCodePoint < 0xA0) return '?'; if(iCodePoint < 0x100) - return g_aUnicodeToCP437[iCodePoint - 0xA0]; + return unicode_to_cp437_table[iCodePoint - 0xA0]; switch(iCodePoint) { case 0x0192: return 0x9F; @@ -173,98 +167,84 @@ return 0x3F; } -void THBitmapFont::getTextSize(const char* sMessage, size_t iMessageLength, int* pX, int* pY) const +text_layout bitmap_font::get_text_dimensions(const char* sMessage, size_t iMessageLength, + int iMaxWidth) const { - int iX = 0; - unsigned int iTallest = 0; - if(iMessageLength != 0 && m_pSpriteSheet != NULL) - { - const unsigned int iFirstASCII = 31; - unsigned int iLastASCII = m_pSpriteSheet->getSpriteCount() + iFirstASCII; - const char* sMessageEnd = sMessage + iMessageLength; - iX = -m_iCharSep; - - while(sMessage != sMessageEnd) - { - unsigned int iChar = unicodeToCodepage437(utf8next(sMessage)); - if(iFirstASCII <= iChar && iChar <= iLastASCII) - { - iChar -= iFirstASCII; - unsigned int iWidth, iHeight; - m_pSpriteSheet->getSpriteSizeUnchecked(iChar, &iWidth, &iHeight); - iX += iWidth + m_iCharSep; - if(iHeight > iTallest) - iTallest = iHeight; - } - } - } - if(pX) - *pX = iX; - if(pY) - *pY = (int)iTallest; + return draw_text_wrapped(nullptr, sMessage, iMessageLength, 0, 0, iMaxWidth, INT_MAX, 0); } -void THBitmapFont::drawText(THRenderTarget* pCanvas, const char* sMessage, size_t iMessageLength, int iX, int iY) const +void bitmap_font::draw_text(render_target* pCanvas, const char* sMessage, size_t iMessageLength, int iX, int iY) const { - pCanvas->startNonOverlapping(); - if(iMessageLength != 0 && m_pSpriteSheet != NULL) + pCanvas->start_nonoverlapping_draws(); + if(iMessageLength != 0 && sheet != nullptr) { const unsigned int iFirstASCII = 31; - unsigned int iLastASCII = m_pSpriteSheet->getSpriteCount() + iFirstASCII; + unsigned int iLastASCII = static_cast(sheet->get_sprite_count()) + iFirstASCII; const char* sMessageEnd = sMessage + iMessageLength; while(sMessage != sMessageEnd) { - unsigned int iChar = unicodeToCodepage437(utf8next(sMessage)); + unsigned int iChar = unicode_to_codepage_437(next_utf8_codepoint(sMessage)); if(iFirstASCII <= iChar && iChar <= iLastASCII) { iChar -= iFirstASCII; unsigned int iWidth, iHeight; - m_pSpriteSheet->drawSprite(pCanvas, iChar, iX, iY, 0); - m_pSpriteSheet->getSpriteSizeUnchecked(iChar, &iWidth, &iHeight); - iX += iWidth + m_iCharSep; + sheet->draw_sprite(pCanvas, iChar, iX, iY, 0); + sheet->get_sprite_size_unchecked(iChar, &iWidth, &iHeight); + iX += iWidth + letter_spacing; } } } - pCanvas->finishNonOverlapping(); + pCanvas->finish_nonoverlapping_draws(); } -int THBitmapFont::drawTextWrapped(THRenderTarget* pCanvas, const char* sMessage, - size_t iMessageLength, int iX, int iY, int iWidth, - int *pResultingWidth, int *pLastX, eTHAlign eAlign) const +text_layout bitmap_font::draw_text_wrapped(render_target* pCanvas, const char* sMessage, + size_t iMessageLength, int iX, int iY, int iWidth, + int iMaxRows, int iSkipRows, text_alignment eAlign) const { - int iResultingWidth = 0; - int iLastX = 0; - if(iMessageLength != 0 && m_pSpriteSheet != NULL) + text_layout oDrawArea = {}; + int iSkippedRows = 0; + if(iMessageLength != 0 && sheet != nullptr) { const unsigned int iFirstASCII = 31; - unsigned int iLastASCII = m_pSpriteSheet->getSpriteCount() + iFirstASCII; + unsigned int iLastASCII = static_cast(sheet->get_sprite_count()) + iFirstASCII; const char* sMessageEnd = sMessage + iMessageLength; - while(sMessage != sMessageEnd) + while(sMessage != sMessageEnd && oDrawArea.row_count < iMaxRows) { const char* sBreakPosition = sMessageEnd; const char* sLastGoodBreakPosition = sBreakPosition; - int iMsgWidth = -m_iCharSep; + int iMsgWidth = -letter_spacing; int iMsgBreakWidth = iMsgWidth; unsigned int iTallest = 0; const char* s; + bool foundNewLine = false; + unsigned int iNextChar = 0; for(s = sMessage; s != sMessageEnd; ) { const char* sOld = s; - unsigned int iChar = unicodeToCodepage437(utf8next(s)); + unsigned int iChar = unicode_to_codepage_437(next_utf8_codepoint(s)); + iNextChar = unicode_to_codepage_437(static_cast(*s)); + if((iChar == '\n' && iNextChar == '\n') || (iChar == '/' && iNextChar == '/')) + { + foundNewLine = true; + iMsgBreakWidth = iMsgWidth; + sBreakPosition = sOld; + break; + } unsigned int iCharWidth = 0, iCharHeight = 0; if(iFirstASCII <= iChar && iChar <= iLastASCII) { - m_pSpriteSheet->getSpriteSizeUnchecked(iChar - iFirstASCII, &iCharWidth, &iCharHeight); + sheet->get_sprite_size_unchecked(iChar - iFirstASCII, &iCharWidth, &iCharHeight); } - iMsgWidth += m_iCharSep + iCharWidth; + iMsgWidth += letter_spacing + iCharWidth; if(iChar == ' ') { sLastGoodBreakPosition = sOld; iMsgBreakWidth = iMsgWidth - iCharWidth; } + if(iMsgWidth > iWidth) { sBreakPosition = sLastGoodBreakPosition; @@ -276,119 +256,154 @@ if(s == sMessageEnd) iMsgBreakWidth = iMsgWidth; - if(iMsgBreakWidth > iResultingWidth) - iResultingWidth = iMsgBreakWidth; - if(pCanvas) - { - int iXOffset = 0; - if(iMsgBreakWidth < iWidth) - iXOffset = (iWidth - iMsgBreakWidth) * static_cast(eAlign) / 2; - drawText(pCanvas, sMessage, sBreakPosition - sMessage, iX + iXOffset, iY); + if(iMsgBreakWidth > oDrawArea.width) + oDrawArea.width = iMsgBreakWidth; + + if(iSkippedRows >= iSkipRows) + { + if(pCanvas) + { + int iXOffset = 0; + if(iMsgBreakWidth < iWidth) + iXOffset = (iWidth - iMsgBreakWidth) * static_cast(eAlign) / 2; + draw_text(pCanvas, sMessage, sBreakPosition - sMessage, iX + iXOffset, iY); + } + iY += static_cast(iTallest) + line_spacing; + oDrawArea.end_x = iMsgWidth; + oDrawArea.row_count++; + if (foundNewLine) { + iY += static_cast(iTallest) + line_spacing; + oDrawArea.row_count++; + } + } + else + { + iSkippedRows++; + if(foundNewLine) + { + if(iSkippedRows == iSkipRows) + { + iY += static_cast(iTallest) + line_spacing; + oDrawArea.row_count++; + } + iSkippedRows++; + } } sMessage = sBreakPosition; if(sMessage != sMessageEnd) { - utf8next(sMessage); + next_utf8_codepoint(sMessage); + if(foundNewLine) + { + next_utf8_codepoint(sMessage); + } } - iY += static_cast(iTallest) + m_iLineSep; - iLastX = iMsgWidth; + foundNewLine = 0; } } - if(pResultingWidth != NULL) - *pResultingWidth = iResultingWidth; - if(pLastX != NULL) - *pLastX = iX + iLastX; - return iY; + oDrawArea.end_x = iX + oDrawArea.end_x; + oDrawArea.end_y = iY; + return oDrawArea; } #ifdef CORSIX_TH_USE_FREETYPE2 -FT_Library THFreeTypeFont::ms_pFreeType = NULL; -int THFreeTypeFont::ms_iFreeTypeInitCount = 0; +FT_Library freetype_font::freetype_library = nullptr; +int freetype_font::freetype_init_count = 0; -THFreeTypeFont::THFreeTypeFont() +freetype_font::freetype_font() { - m_pFace = NULL; - m_bDoneFreeTypeInit = false; - for(cached_text_t* pEntry = m_aCache; - pEntry != m_aCache + (1 << ms_CacheSizeLog2); ++pEntry) + font_face = nullptr; + is_done_freetype_init = false; + for(cached_text* pEntry = cache; + pEntry != cache + (1 << cache_size_log2); ++pEntry) { - pEntry->sMessage = NULL; - pEntry->iMessageLength = 0; - pEntry->iMessageBufferLength = 0; - pEntry->eAlign = Align_Left; - pEntry->iWidth = 0; - pEntry->iHeight = 0; - pEntry->iWidestLine = 0; - pEntry->iLastX = 0; - pEntry->pData = NULL; - pEntry->bIsValid = false; - _setNullTexture(pEntry); + pEntry->message = nullptr; + pEntry->message_length = 0; + pEntry->message_buffer_length = 0; + pEntry->alignment = text_alignment::left; + pEntry->width = 0; + pEntry->height = 0; + pEntry->widest_line_width = 0; + pEntry->last_x = 0; + pEntry->data = nullptr; + pEntry->is_valid = false; + pEntry->texture = nullptr; } } -THFreeTypeFont::~THFreeTypeFont() +freetype_font::~freetype_font() { - for(cached_text_t* pEntry = m_aCache; - pEntry != m_aCache + (1 << ms_CacheSizeLog2); ++pEntry) + for(cached_text* pEntry = cache; + pEntry != cache + (1 << cache_size_log2); ++pEntry) { - _freeTexture(pEntry); + free_texture(pEntry); } - if(m_pFace != NULL) - FT_Done_Face(m_pFace); - if(m_bDoneFreeTypeInit) + if(font_face != nullptr) + FT_Done_Face(font_face); + if(is_done_freetype_init) { - if(--ms_iFreeTypeInitCount == 0) + if(--freetype_init_count == 0) { - FT_Done_FreeType(ms_pFreeType); - ms_pFreeType = NULL; + FT_Done_FreeType(freetype_library); + freetype_library = nullptr; } } } -const char* THFreeTypeFont::getCopyrightNotice() +const char* freetype_font::get_copyright_notice() { return "Portions of this software are copyright \xC2\xA9 2010 " \ "The FreeType Project (www.freetype.org). All rights reserved."; } -FT_Error THFreeTypeFont::initialise() +FT_Error freetype_font::initialise() { - if(m_bDoneFreeTypeInit) + if(is_done_freetype_init) return FT_Err_Ok; - if(ms_iFreeTypeInitCount == 0) + if(freetype_init_count == 0) { - int iError = FT_Init_FreeType(&ms_pFreeType); + int iError = FT_Init_FreeType(&freetype_library); if(iError != FT_Err_Ok) return iError; } - ++ms_iFreeTypeInitCount; - m_bDoneFreeTypeInit = true; + ++freetype_init_count; + is_done_freetype_init = true; return FT_Err_Ok; } -FT_Error THFreeTypeFont::setFace(const unsigned char* pData, size_t iLength) +void freetype_font::clear_cache() +{ + for(cached_text* pEntry = cache; + pEntry != cache + (1 << cache_size_log2); ++pEntry) + { + pEntry->is_valid = false; + free_texture(pEntry); + } +} + +FT_Error freetype_font::set_face(const uint8_t* pData, size_t iLength) { int iError; - if(ms_pFreeType == NULL) + if(freetype_library == nullptr) { iError = initialise(); if(iError != FT_Err_Ok) return iError; } - if(m_pFace) + if(font_face) { - iError = FT_Done_Face(m_pFace); + iError = FT_Done_Face(font_face); if(iError != FT_Err_Ok) return iError; - m_pFace = NULL; + font_face = nullptr; } - iError = FT_New_Memory_Face(ms_pFreeType, pData, iLength, 0, &m_pFace); + iError = FT_New_Memory_Face(freetype_library, pData, static_cast(iLength), 0, &font_face); return iError; } -FT_Error THFreeTypeFont::matchBitmapFont(THSpriteSheet* pBitmapFontSpriteSheet) +FT_Error freetype_font::match_bitmap_font(sprite_sheet* pBitmapFontSpriteSheet) { - if(pBitmapFontSpriteSheet == NULL) + if(pBitmapFontSpriteSheet == nullptr) return FT_Err_Invalid_Argument; // Try to take the size and colour of a standard character (em is generally @@ -398,23 +413,23 @@ { unsigned int iWidth, iHeight; unsigned int iSprite = *sCharToTry - 31; - if(pBitmapFontSpriteSheet->getSpriteSize(iSprite, &iWidth, &iHeight) - && pBitmapFontSpriteSheet->getSpriteAverageColour(iSprite, &m_oColour) + if(pBitmapFontSpriteSheet->get_sprite_size(iSprite, &iWidth, &iHeight) + && pBitmapFontSpriteSheet->get_sprite_average_colour(iSprite, &colour) && iWidth > 1 && iHeight > 1) { - return setPixelSize(iWidth, iHeight); + return set_ideal_character_size(iWidth, iHeight); } } // Take the average size of all characters, and the colour of one of them. unsigned int iWidthSum = 0, iHeightSum = 0, iAverageNum = 0; - for(unsigned int i = 0; i < pBitmapFontSpriteSheet->getSpriteCount(); ++i) + for(unsigned int i = 0; i < pBitmapFontSpriteSheet->get_sprite_count(); ++i) { unsigned int iWidth, iHeight; - pBitmapFontSpriteSheet->getSpriteSizeUnchecked(i, &iWidth, &iHeight); + pBitmapFontSpriteSheet->get_sprite_size_unchecked(i, &iWidth, &iHeight); if(iWidth <= 1 || iHeight <= 1) continue; - if(!pBitmapFontSpriteSheet->getSpriteAverageColour(i, &m_oColour)) + if(!pBitmapFontSpriteSheet->get_sprite_average_colour(i, &colour)) continue; iWidthSum += iWidth; iHeightSum += iHeight; @@ -423,26 +438,26 @@ if(iAverageNum == 0) return FT_Err_Divide_By_Zero; - return setPixelSize((iWidthSum + iAverageNum / 2) / iAverageNum, + return set_ideal_character_size((iWidthSum + iAverageNum / 2) / iAverageNum, (iHeightSum + iAverageNum / 2) / iAverageNum); } -FT_Error THFreeTypeFont::setPixelSize(int iWidth, int iHeight) +FT_Error freetype_font::set_ideal_character_size(int iWidth, int iHeight) { - if(m_pFace == NULL) + if(font_face == nullptr) return FT_Err_Invalid_Face_Handle; - if(_isMonochrome() || iHeight <= 14 || iWidth <= 9) + if(is_monochrome() || iHeight <= 14 || iWidth <= 9) { // Look for a bitmap strike of a similar size int iBestBitmapScore = 50; FT_Int iBestBitmapIndex = -1; - for(FT_Int i = 0; i < m_pFace->num_fixed_sizes; ++i) + for(FT_Int i = 0; i < font_face->num_fixed_sizes; ++i) { - if(m_pFace->available_sizes[i].height > iHeight) + if(font_face->available_sizes[i].height > iHeight) continue; - int iDeltaH = iHeight - m_pFace->available_sizes[i].height; - int iDeltaW = m_pFace->available_sizes[i].width - iWidth; + int iDeltaH = iHeight - font_face->available_sizes[i].height; + int iDeltaW = font_face->available_sizes[i].width - iWidth; int iScore = iDeltaH * iDeltaH * 3 + iDeltaW * iDeltaW; if(iScore < iBestBitmapScore) { @@ -453,7 +468,7 @@ // Select the bitmap strike, if there was one if(iBestBitmapIndex != -1) - return FT_Select_Size(m_pFace, iBestBitmapIndex); + return FT_Select_Size(font_face, iBestBitmapIndex); } // Go with the original size request if there was no bitmap strike, unless @@ -469,78 +484,79 @@ iHeight = iHeight * 9 / iWidth; iWidth = 9; } - return FT_Set_Pixel_Sizes(m_pFace, iWidth, iHeight); + return FT_Set_Pixel_Sizes(font_face, iWidth, iHeight); } -void THFreeTypeFont::getTextSize(const char* sMessage, size_t iMessageLength, - int* pX, int* pY) const +text_layout freetype_font::get_text_dimensions(const char* sMessage, size_t iMessageLength, int iMaxWidth) const { - int iY = drawTextWrapped(NULL, sMessage, iMessageLength, 0, 0, INT_MAX, pX); - if(pY) - *pY = iY; + return draw_text_wrapped(nullptr, sMessage, iMessageLength, 0, 0, iMaxWidth, INT_MAX, 0); } -void THFreeTypeFont::drawText(THRenderTarget* pCanvas, const char* sMessage, +void freetype_font::draw_text(render_target* pCanvas, const char* sMessage, size_t iMessageLength, int iX, int iY) const { - drawTextWrapped(pCanvas, sMessage, iMessageLength, iX, iY, INT_MAX); + draw_text_wrapped(pCanvas, sMessage, iMessageLength, iX, iY, INT_MAX); } -struct codepoint_glyph_t +struct codepoint_glyph { - FT_Glyph_Metrics oMetrics; - FT_Glyph pGlyph; - FT_UInt iGlyphIndex; + FT_Glyph_Metrics metrics; + FT_Glyph glyph; + FT_UInt index; }; -int THFreeTypeFont::drawTextWrapped(THRenderTarget* pCanvas, const char* sMessage, - size_t iMessageLength, int iX, int iY, - int iWidth, int *pResultingWidth, int *pLastX, - eTHAlign eAlign) const -{ +text_layout freetype_font::draw_text_wrapped(render_target* pCanvas, const char* sMessage, + size_t iMessageLength, int iX, int iY, + int iWidth, int iMaxRows, int iSkipRows, text_alignment eAlign) const +{ + text_layout oDrawArea = {}; + int iNumRows = 0; + int iHandledRows = 0; + // Calculate an index into the cache to use for this piece of text. size_t iHash = iMessageLength - + (static_cast(iWidth) << (ms_CacheSizeLog2 / 2)) - + (static_cast(eAlign) << ms_CacheSizeLog2); + + (static_cast(iMaxRows) << (cache_size_log2 / 8)) + + (static_cast(iSkipRows) << (cache_size_log2 / 4)) + + (static_cast(iWidth) << (cache_size_log2 / 2)) + + (static_cast(eAlign) << cache_size_log2); for(size_t i = 0; i < iMessageLength; ++i) iHash ^= (iHash << 5) + (iHash >> 2) + static_cast(sMessage[i]); - iHash &= (1 << ms_CacheSizeLog2) - 1; + iHash &= (1 << cache_size_log2) - 1; - cached_text_t* pEntry = m_aCache + iHash; - if(pEntry->iMessageLength != iMessageLength || pEntry->iWidth > iWidth - || (iWidth != INT_MAX && pEntry->iWidth < iWidth) - || pEntry->eAlign != eAlign || !pEntry->bIsValid - || memcmp(pEntry->sMessage, sMessage, iMessageLength) != 0) + cached_text* pEntry = cache + iHash; + if(pEntry->message_length != iMessageLength || pEntry->width > iWidth + || (iWidth != INT_MAX && pEntry->width < iWidth) + || pEntry->alignment != eAlign || !pEntry->is_valid + || std::memcmp(pEntry->message, sMessage, iMessageLength) != 0) { // Cache entry does not match the message being drawn, so discard the // cache entry. - _freeTexture(pEntry); - _setNullTexture(pEntry); - delete[] pEntry->pData; - pEntry->pData = NULL; - pEntry->bIsValid = false; + free_texture(pEntry); + delete[] pEntry->data; + pEntry->data = nullptr; + pEntry->is_valid = false; // Set the entry metadata to that of the new message. - if(iMessageLength > pEntry->iMessageBufferLength) + if(iMessageLength > pEntry->message_buffer_length) { - delete[] pEntry->sMessage; - pEntry->sMessage = new char[iMessageLength]; - pEntry->iMessageBufferLength = iMessageLength; - } - memcpy(pEntry->sMessage, sMessage, iMessageLength); - pEntry->iMessageLength = iMessageLength; - pEntry->iWidth = iWidth; - pEntry->eAlign = eAlign; + delete[] pEntry->message; + pEntry->message = new char[iMessageLength]; + pEntry->message_buffer_length = iMessageLength; + } + std::memcpy(pEntry->message, sMessage, iMessageLength); + pEntry->message_length = iMessageLength; + pEntry->width = iWidth; + pEntry->alignment = eAlign; // Split the message into lines, and determine the position within the // line for each character. std::vector > vLines; std::vector vCharPositions(iMessageLength); - std::map mapGlyphs; + std::map mapGlyphs; vLines.reserve(2); FT_Vector ftvPen = {0, 0}; - FT_Bool bUseKerning = FT_HAS_KERNING(m_pFace); + FT_Bool bUseKerning = FT_HAS_KERNING(font_face); FT_UInt iPreviousGlyphIndex = 0; const char* sMessageStart = sMessage; @@ -551,46 +567,87 @@ while(sMessage != sMessageEnd) { const char* sOldMessage = sMessage; - unsigned int iCode = utf8next(sMessage); - codepoint_glyph_t& oGlyph = mapGlyphs[iCode]; - if(oGlyph.pGlyph == NULL) - { - oGlyph.iGlyphIndex = FT_Get_Char_Index(m_pFace, iCode); - FT_Error iError = FT_Load_Glyph(m_pFace, oGlyph.iGlyphIndex, - FT_LOAD_DEFAULT); + unsigned int iCode = next_utf8_codepoint(sMessage); + unsigned int iNextCode = *reinterpret_cast(sMessage); + bool bIsNewLine = (iCode == '\n' && iNextCode == '\n') || (iCode == '/' && iNextCode == '/'); + // Just replace single line breaks with space. + if(!bIsNewLine && iCode == '\n') + { + iCode = ' '; + } + + codepoint_glyph& oGlyph = mapGlyphs[iCode]; + if(oGlyph.glyph == nullptr) + { + oGlyph.index = FT_Get_Char_Index(font_face, iCode); + + /* FT_Error iError = */ + FT_Load_Glyph(font_face, oGlyph.index, FT_LOAD_DEFAULT); // TODO: iError != FT_Err_Ok - iError = FT_Get_Glyph(m_pFace->glyph, &oGlyph.pGlyph); + + /* iError = */ + FT_Get_Glyph(font_face->glyph, &oGlyph.glyph); // TODO: iError != FT_Err_Ok - oGlyph.oMetrics = m_pFace->glyph->metrics; + + oGlyph.metrics = font_face->glyph->metrics; } // Apply kerning - if(bUseKerning && iPreviousGlyphIndex && oGlyph.iGlyphIndex) + if(bUseKerning && iPreviousGlyphIndex && oGlyph.index) { FT_Vector ftvKerning; - FT_Get_Kerning(m_pFace, iPreviousGlyphIndex, - oGlyph.iGlyphIndex, FT_KERNING_DEFAULT, &ftvKerning); + FT_Get_Kerning(font_face, iPreviousGlyphIndex, + oGlyph.index, FT_KERNING_DEFAULT, &ftvKerning); ftvPen.x += ftvKerning.x; ftvPen.y += ftvKerning.y; } // Make an automatic line break if one is needed. - if((ftvPen.x + oGlyph.oMetrics.horiBearingX + - oGlyph.oMetrics.width + 63) / 64 >= iWidth) + if((ftvPen.x + oGlyph.metrics.horiBearingX + + oGlyph.metrics.width + 63) / 64 >= iWidth || bIsNewLine) { + if(bIsNewLine) + { + sLineBreakPosition = sOldMessage; + } ftvPen.x = ftvPen.y = 0; iPreviousGlyphIndex = 0; if(sLineStart != sLineBreakPosition) { - vLines.push_back(std::make_pair(sLineStart, sLineBreakPosition)); - utf8next(sLineBreakPosition); - sMessage = sLineStart = sLineBreakPosition; + // Only really save if we have skipped enough lines + if(iHandledRows >= iSkipRows) + { + vLines.push_back(std::make_pair(sLineStart, sLineBreakPosition)); + } + if(bIsNewLine) + { + if(iHandledRows + 1 >= iSkipRows) + { + vLines.push_back(std::make_pair(sLineBreakPosition, sLineBreakPosition)); + } + next_utf8_codepoint(sLineBreakPosition); + iHandledRows++; + } + sMessage = sLineBreakPosition; + next_utf8_codepoint(sMessage); + sLineStart = sMessage; } else { - vLines.push_back(std::make_pair(sLineStart, sOldMessage)); - sMessage = sLineStart = sLineBreakPosition = sOldMessage; + if(iHandledRows >= iSkipRows) { + vLines.push_back(std::make_pair(sLineStart, sOldMessage)); + } + if(bIsNewLine) + { + next_utf8_codepoint(sMessage); + sLineStart = sLineBreakPosition = sMessage; + } + else + { + sMessage = sLineStart = sLineBreakPosition = sOldMessage; + } } + iHandledRows++; continue; } @@ -598,10 +655,14 @@ if(iCode == ' ') sLineBreakPosition = sOldMessage; - // Save and advance the pen. - vCharPositions[sOldMessage - sMessageStart] = ftvPen; - iPreviousGlyphIndex = oGlyph.iGlyphIndex; - ftvPen.x += oGlyph.oMetrics.horiAdvance; + // Save (unless we are skipping lines) and advance the pen. + if(iHandledRows >= iSkipRows) + { + vCharPositions[sOldMessage - sMessageStart] = ftvPen; + } + + iPreviousGlyphIndex = oGlyph.index; + ftvPen.x += oGlyph.metrics.horiAdvance; } if(sLineStart != sMessageEnd) vLines.push_back(std::make_pair(sLineStart, sMessageEnd)); @@ -613,19 +674,22 @@ FT_Pos iPriorLinesHeight = 0; FT_Pos iLineWidth = 0, iAlignDelta = 0, iWidestLine = 0; const FT_Pos iLineSpacing = 2 << 6; + codepoint_glyph& oGlyph = mapGlyphs['l']; + FT_Pos iBearingY = oGlyph.metrics.horiBearingY; + FT_Pos iNormalLineHeight = oGlyph.metrics.height - iBearingY; + iBearingY = ((iBearingY + 63) >> 6) << 6; // Pixel-align + iNormalLineHeight += iBearingY; + iNormalLineHeight += iLineSpacing; + iNormalLineHeight = ((iNormalLineHeight + 63) >> 6) << 6; // Pixel-align for(std::vector >::const_iterator - itr = vLines.begin(), itrEnd = vLines.end(); itr != itrEnd; ++itr) + itr = vLines.begin(), itrEnd = vLines.end(); itr != itrEnd && iNumRows < iMaxRows; ++itr) { - // Skip empty lines (shouldn't happen anyway?). - if(itr->first == itr->second) - continue; - // Calculate the X change resulting from alignment. - const char* sLastChar = utf8prev(itr->second); - codepoint_glyph_t& oLastGlyph = mapGlyphs[utf8decode(sLastChar)]; + const char* sLastChar = previous_utf8_codepoint(itr->second); + codepoint_glyph& oLastGlyph = mapGlyphs[decode_utf8(sLastChar)]; iLineWidth = vCharPositions[sLastChar - sMessage].x - + oLastGlyph.oMetrics.horiBearingX - + oLastGlyph.oMetrics.width; + + oLastGlyph.metrics.horiBearingX + + oLastGlyph.metrics.width; if((iLineWidth >> 6) < iWidth) { iAlignDelta = ((iWidth * 64 - iLineWidth) * @@ -639,9 +703,9 @@ FT_Pos iBaselinePos = 0; for(const char* s = itr->first; s != itr->second; ) { - codepoint_glyph_t& oGlyph = mapGlyphs[utf8next(s)]; - FT_Pos iBearingY = oGlyph.oMetrics.horiBearingY; - FT_Pos iCoBearingY = oGlyph.oMetrics.height - iBearingY; + codepoint_glyph& oGlyph = mapGlyphs[next_utf8_codepoint(s)]; + FT_Pos iBearingY = oGlyph.metrics.horiBearingY; + FT_Pos iCoBearingY = oGlyph.metrics.height - iBearingY; if(iBearingY > iBaselinePos) iBaselinePos = iBearingY; if(iCoBearingY > iLineHeight) @@ -652,46 +716,66 @@ iLineHeight += iLineSpacing; iLineHeight = ((iLineHeight + 63) >> 6) << 6; // Pixel-align + iNormalLineHeight = std::max(iNormalLineHeight, iLineHeight); + // Apply the character position changes. - for(const char* s = itr->first; s != itr->second; utf8next(s)) + for(const char* s = itr->first; s != itr->second; next_utf8_codepoint(s)) { FT_Vector& ftvPos = vCharPositions[s - sMessage]; ftvPos.x += iAlignDelta; ftvPos.y += iBaselinePos + iPriorLinesHeight; } - iPriorLinesHeight += iLineHeight; + // Empty lines is a special case + if(itr->first == itr->second) + { + iPriorLinesHeight += iNormalLineHeight; + } + else + { + iPriorLinesHeight += iLineHeight; + } + iNumRows++; } if(iPriorLinesHeight > 0) iPriorLinesHeight -= iLineSpacing; - pEntry->iHeight = 1 + (iPriorLinesHeight >> 6); - pEntry->iWidestLine = 1 + (iWidestLine >> 6); + pEntry->height = static_cast(1 + (iPriorLinesHeight >> 6)); + pEntry->widest_line_width = static_cast(1 + (iWidestLine >> 6)); + pEntry->row_count = iNumRows; if(iWidth == INT_MAX) - pEntry->iWidth = pEntry->iWidestLine; - pEntry->iLastX = 1 + (static_cast(iLineWidth + iAlignDelta) >> 6); + pEntry->width = pEntry->widest_line_width; + pEntry->last_x = 1 + (static_cast(iLineWidth + iAlignDelta) >> 6); // Get a bitmap for each glyph. - bool bIsMonochrome = _isMonochrome(); + bool bIsMonochrome = is_monochrome(); FT_Render_Mode eRenderMode = bIsMonochrome ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL; - for(std::map::iterator itr = + for(std::map::iterator itr = mapGlyphs.begin(), itrEnd = mapGlyphs.end(); itr != itrEnd; ++itr) { - FT_Glyph_To_Bitmap(&itr->second.pGlyph, eRenderMode, NULL, 1); + FT_Glyph_To_Bitmap(&itr->second.glyph, eRenderMode, nullptr, 1); } // Prepare a canvas for rendering. - pEntry->pData = new unsigned char[pEntry->iWidth * pEntry->iHeight]; - memset(pEntry->pData, 0, pEntry->iWidth * pEntry->iHeight); + pEntry->data = new uint8_t[pEntry->width * pEntry->height]; + std::memset(pEntry->data, 0, pEntry->width * pEntry->height); + int iDrawnLines = 0; // Render each character to the canvas. for(std::vector >::const_iterator - itr = vLines.begin(), itrEnd = vLines.end(); itr != itrEnd; ++itr) + itr = vLines.begin(), itrEnd = vLines.end(); + itr != itrEnd && iDrawnLines < iMaxRows + iSkipRows; ++itr) { + iDrawnLines++; for(const char* s = itr->first; s != itr->second; ) { FT_Vector& ftvPos = vCharPositions[s - sMessage]; + unsigned int iCode = next_utf8_codepoint(s); + if(iCode == '\n') + { + iCode = ' '; + } FT_BitmapGlyph pGlyph = reinterpret_cast( - mapGlyphs[utf8next(s)].pGlyph); + mapGlyphs[iCode].glyph); FT_Pos x = pGlyph->left + (ftvPos.x >> 6); FT_Pos y = (ftvPos.y >> 6) - pGlyph->top; // We may have asked for grayscale but been given monochrome, @@ -699,34 +783,36 @@ switch(pGlyph->bitmap.pixel_mode) { case FT_PIXEL_MODE_GRAY: - _renderGray(pEntry, &pGlyph->bitmap, x, y); + render_gray(pEntry, &pGlyph->bitmap, x, y); break; case FT_PIXEL_MODE_MONO: - _renderMono(pEntry, &pGlyph->bitmap, x, y); + render_mono(pEntry, &pGlyph->bitmap, x, y); break; } } } // Free all glyphs. - for(std::map::const_iterator itr = + for(std::map::const_iterator itr = mapGlyphs.begin(), itrEnd = mapGlyphs.end(); itr != itrEnd; ++itr) { - FT_Done_Glyph(itr->second.pGlyph); + FT_Done_Glyph(itr->second.glyph); } - // Convert the canvas to a texture - _makeTexture(pEntry); - pEntry->bIsValid = true; + pEntry->is_valid = true; } - if(pCanvas != NULL) - _drawTexture(pCanvas, pEntry, iX, iY); - if(pResultingWidth != NULL) - *pResultingWidth = pEntry->iWidestLine; - if(pLastX != NULL) - *pLastX = iX + pEntry->iLastX; - return iY + pEntry->iHeight; + if (pCanvas != nullptr) + { + if (pEntry->texture == nullptr) + make_texture(pCanvas, pEntry); + draw_texture(pCanvas, pEntry, iX, iY); + } + oDrawArea.width = pEntry->widest_line_width; + oDrawArea.end_x = iX + pEntry->last_x; + oDrawArea.end_y = iY + pEntry->height; + oDrawArea.row_count = pEntry->row_count; + return oDrawArea; } // In theory, the renderers should only be invoked with coordinates which end @@ -734,32 +820,32 @@ // at which point the following line can be removed. // #define TRUST_RENDER_COORDS -void THFreeTypeFont::_renderMono(cached_text_t *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const +void freetype_font::render_mono(cached_text *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const { - unsigned char* pOutRow = pCacheEntry->pData + y * pCacheEntry->iWidth + x; - unsigned char* pInRow = pBitmap->buffer; - for(int iY = 0; iY < pBitmap->rows; ++iY, pOutRow += pCacheEntry->iWidth, + uint8_t* pOutRow = pCacheEntry->data + y * pCacheEntry->width + x; + uint8_t* pInRow = pBitmap->buffer; + for(int iY = 0; iY < pBitmap->rows; ++iY, pOutRow += pCacheEntry->width, pInRow += pBitmap->pitch) { #ifndef TRUST_RENDER_COORDS if(y + iY < 0) continue; - if(y + iY >= pCacheEntry->iHeight) + if(y + iY >= pCacheEntry->height) break; #endif - unsigned char *pIn = pInRow, *pOut = pOutRow; - unsigned char iMask = 0x80; + uint8_t *pIn = pInRow, *pOut = pOutRow; + uint8_t iMask = 0x80; for(int iX = 0; iX < pBitmap->width; ++iX, ++pOut) { #ifndef TRUST_RENDER_COORDS if(x + iX < 0) continue; - if(x + iX >= pCacheEntry->iWidth) + if(x + iX >= pCacheEntry->width) break; #endif if(*pIn & iMask) *pOut = 0xFF; - iMask >>= 1; + iMask = static_cast(iMask / 2); if(iMask == 0) { iMask = 0x80; @@ -769,32 +855,31 @@ } } -void THFreeTypeFont::_renderGray(cached_text_t *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const +void freetype_font::render_gray(cached_text *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const { - unsigned char* pOutRow = pCacheEntry->pData + y * pCacheEntry->iWidth + x; - unsigned char* pInRow = pBitmap->buffer; - for(int iY = 0; iY < pBitmap->rows; ++iY, pOutRow += pCacheEntry->iWidth, + uint8_t* pOutRow = pCacheEntry->data + y * pCacheEntry->width + x; + uint8_t* pInRow = pBitmap->buffer; + for(int iY = 0; iY < pBitmap->rows; ++iY, pOutRow += pCacheEntry->width, pInRow += pBitmap->pitch) { #ifndef TRUST_RENDER_COORDS if(y + iY < 0) continue; - if(y + iY >= pCacheEntry->iHeight) + if(y + iY >= pCacheEntry->height) break; #endif - unsigned char *pIn = pInRow, *pOut = pOutRow; + uint8_t *pIn = pInRow, *pOut = pOutRow; for(int iX = 0; iX < pBitmap->width; ++iX, ++pIn, ++pOut) { #ifndef TRUST_RENDER_COORDS if(x + iX < 0) continue; - if(x + iX >= pCacheEntry->iWidth) + if(x + iX >= pCacheEntry->width) break; #endif unsigned int iIn = *pIn; unsigned int iOut = *pOut; - unsigned char cMerged = static_cast( - iIn + iOut - (iIn * iOut) / 255); + uint8_t cMerged = static_cast(iIn + iOut - (iIn * iOut) / 255); *pOut = cMerged; } } diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx_font.h corsix-th-0.62/CorsixTH/Src/th_gfx_font.h --- corsix-th-0.30/CorsixTH/Src/th_gfx_font.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx_font.h 2018-07-21 11:13:17.000000000 +0000 @@ -28,32 +28,52 @@ #include FT_FREETYPE_H #endif -enum eTHAlign +enum class text_alignment { + left = 0, + center = 1, + right = 2, +}; + +/** Structure for the bounds of a text string that is rendered to the screen. */ +struct text_layout { - Align_Left = 0, - Align_Center = 1, - Align_Right = 2, + //! Number of rows the rendered text spans + int row_count; + + //! Left X-coordinate for the start of the text + int start_x; + + //! Right X-coordinate for the right part of the last letter rendered + int end_x; + + //! Top Y-coordinate for the start of the text + int start_y; + + //! Bottom Y-coordinate for the end of the text + int end_y; + + //! Width of the widest line in the text + int width; }; -class THFont +class font { public: - THFont(); - virtual ~THFont(); + virtual ~font() = default; - //! Get the size of a single line of drawn text + //! Get the size of drawn text. /*! + If iMaxWidth is specified the text will wrap, so that the height can + span multiple rows. Otherwise gets the size of a single line of text. @param sMessage A UTF-8 encoded string containing a single line of text to measure the width and height of. @param iMessageLength The length, in bytes (not characters), of the string at sMessage. - @param pX If not NULL, the width (in pixels) of the drawn message will - be stored at this pointer. - @param pY If not NULL, the height (in pixels) of the drawn message will - be stored at this pointer. + @param iMaxWidth The maximum length, in pixels, that the text may + occupy. Default is INT_MAX. */ - virtual void getTextSize(const char* sMessage, size_t iMessageLength, - int* pX, int* pY) const = 0; + virtual text_layout get_text_dimensions(const char* sMessage, size_t iMessageLength, + int iMaxWidth = INT_MAX) const = 0; //! Draw a single line of text /*! @@ -67,41 +87,37 @@ @param iY The Y coordinate of the top-left corner of the bounding rectangle for the drawn text. */ - virtual void drawText(THRenderTarget* pCanvas, const char* sMessage, - size_t iMessageLength, int iX, int iY) const = 0; + virtual void draw_text(render_target* pCanvas, const char* sMessage, + size_t iMessageLength, int iX, int iY) const = 0; //! Draw a single line of text, splitting it at word boundaries /*! This function still only draws a single line of text (i.e. any line breaks like \r and \n in sMessage are ignored), but inserts line breaks between words so that no single line is wider than iWidth pixels. - @param pCanvas The canvas on which to draw. Can be NULL, in which case + If iMaxRows is specified it will simply cut after that many rows. + @param pCanvas The canvas on which to draw. Can be nullptr, in which case nothing is drawn, but other calculations are still made. @param sMessage The line of text to draw, encoded in CP437. @param iMessageLength The length (in bytes) of sMessage. @param iX The X position to start drawing on the canvas. @param iY The Y position to start drawing on the canvas. @param iWidth The maximum width of each line of text. - @param pResultingWidth If not NULL, the maximum width of a line will - be stored here (the resulting value should be similar to iWidth, - but a bit smaller). - @param pLastX If not NULL, iX plus the the width of the last printed - line will be stored here. + @param iMaxRows The maximum number of rows to draw. Default is INT_MAX. + @param iSkipRows Start rendering text after skipping this many rows. @param eAlign How to align each line of text if the width of the line of text is smaller than iWidth. - @return iY plus the height (in pixels) of the resulting text. */ - virtual int drawTextWrapped(THRenderTarget* pCanvas, const char* sMessage, - size_t iMessageLength, int iX, int iY, - int iWidth, int *pResultingWidth = NULL, - int *pLastX = NULL, - eTHAlign eAlign = Align_Left) const = 0; + virtual text_layout draw_text_wrapped(render_target* pCanvas, const char* sMessage, + size_t iMessageLength, int iX, int iY, + int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0, + text_alignment eAlign = text_alignment::left) const = 0; }; -class THBitmapFont : public THFont +class bitmap_font final : public font { public: - THBitmapFont(); + bitmap_font(); //! Set the character glyph sprite sheet /*! @@ -109,33 +125,32 @@ index 1, and other ASCII characters following on in simple order (i.e. '!' (ASCII 0x21) at index 2, 'A' (ASCII 0x41) at index 34, etc.) */ - void setSpriteSheet(THSpriteSheet* pSpriteSheet); + void set_sprite_sheet(sprite_sheet* pSpriteSheet); - THSpriteSheet* getSpriteSheet() {return m_pSpriteSheet;} + sprite_sheet* get_sprite_sheet() {return sheet;} - //! Set the seperation between characters and between lines + //! Set the separation between characters and between lines /*! Generally, the sprite sheet glyphs will already include separation, and thus no extra separation is required (set iCharSep and iLineSep to 0). */ - void setSeparation(int iCharSep, int iLineSep); + void set_separation(int iCharSep, int iLineSep); - virtual void getTextSize(const char* sMessage, size_t iMessageLength, - int* pX, int* pY) const; + text_layout get_text_dimensions(const char* sMessage, size_t iMessageLength, + int iMaxWidth = INT_MAX) const override; - virtual void drawText(THRenderTarget* pCanvas, const char* sMessage, - size_t iMessageLength, int iX, int iY) const; + void draw_text(render_target* pCanvas, const char* sMessage, + size_t iMessageLength, int iX, int iY) const override; - virtual int drawTextWrapped(THRenderTarget* pCanvas, const char* sMessage, - size_t iMessageLength, int iX, int iY, - int iWidth, int *pResultingWidth = NULL, - int *pLastX = NULL, - eTHAlign eAlign = Align_Left) const; - -protected: - THSpriteSheet* m_pSpriteSheet; - int m_iCharSep; - int m_iLineSep; + text_layout draw_text_wrapped(render_target* pCanvas, const char* sMessage, + size_t iMessageLength, int iX, int iY, + int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0, + text_alignment eAlign = text_alignment::left) const override; + +private: + sprite_sheet* sheet; + int letter_spacing; + int line_spacing; }; #ifdef CORSIX_TH_USE_FREETYPE2 @@ -152,11 +167,11 @@ THRawBitmap class, but with an alpha channel, and a single colour rather than a palette). */ -class THFreeTypeFont : public THFont +class freetype_font final : public font { public: - THFreeTypeFont(); - ~THFreeTypeFont(); + freetype_font(); + ~freetype_font(); //! Get the copyright notice which should be displayed for FreeType2. /*! @@ -164,7 +179,7 @@ function needs to be displayed at some point. @return A null-terminated UTF-8 encoded string. */ - static const char* getCopyrightNotice(); + static const char* get_copyright_notice(); //! Initialise the FreeType2 library. /*! @@ -172,6 +187,9 @@ */ FT_Error initialise(); + //! Remove all cached strings, as our graphics context has changed + void clear_cache(); + //! Set the font face to be used. /*! @param pData Pointer to the start of a font file loaded into memory. @@ -179,7 +197,7 @@ of the THFreeTypeFont objcect. @param iLength The size, in bytes, of the font file at pData. */ - FT_Error setFace(const unsigned char* pData, size_t iLength); + FT_Error set_face(const uint8_t* pData, size_t iLength); //! Set the font size and colour to match that of a bitmap font. /*! @@ -188,7 +206,7 @@ @param pBitmapFontSpriteSheet The sprite sheet of the bitmap font. */ - FT_Error matchBitmapFont(THSpriteSheet* pBitmapFontSpriteSheet); + FT_Error match_bitmap_font(sprite_sheet* pBitmapFontSpriteSheet); //! Set the ideal character size using pixel values. /*! @@ -196,52 +214,72 @@ would result in a much nicer rendered font. This must be called after setFace(). */ - FT_Error setPixelSize(int iWidth, int iHeight); + FT_Error set_ideal_character_size(int iWidth, int iHeight); - virtual void getTextSize(const char* sMessage, size_t iMessageLength, - int* pX, int* pY) const; + text_layout get_text_dimensions(const char* sMessage, size_t iMessageLength, + int iMaxWidth = INT_MAX) const override; - virtual void drawText(THRenderTarget* pCanvas, const char* sMessage, - size_t iMessageLength, int iX, int iY) const; + void draw_text(render_target* pCanvas, const char* sMessage, + size_t iMessageLength, int iX, int iY) const override; - virtual int drawTextWrapped(THRenderTarget* pCanvas, const char* sMessage, - size_t iMessageLength, int iX, int iY, - int iWidth, int *pResultingWidth = NULL, - int *pLastX = NULL, - eTHAlign eAlign = Align_Left) const; + text_layout draw_text_wrapped(render_target* pCanvas, const char* sMessage, + size_t iMessageLength, int iX, int iY, + int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0, + text_alignment eAlign = text_alignment::left) const override; -protected: - struct cached_text_t +private: + struct cached_text { - char* sMessage; - unsigned char* pData; - union { - void* pTexture; - int iTexture; - }; - size_t iMessageLength; - size_t iMessageBufferLength; - int iWidth; - int iHeight; - int iWidestLine; - int iLastX; - eTHAlign eAlign; - bool bIsValid; + //! The text being converted to pixels + char* message; + + //! Raw pixel data in row major 8-bit greyscale + uint8_t* data; + + //! Generated texture ready to be rendered + SDL_Texture* texture; + + //! The length of sMessage + size_t message_length; + + //! The size of the buffer allocated to store sMessage + size_t message_buffer_length; + + //! Width of the image to draw + int width; + + //! Height of the image to draw + int height; + + //! The width of the longest line of text in in the textbox in pixels + int widest_line_width; + + //! X Coordinate trailing the last character in canvas coordinates + int last_x; + + //! Number of rows required + int row_count; + + //! Alignment of the message in the box + text_alignment alignment; + + //! True when the data reflects the message given the size constraints + bool is_valid; }; //! Render a FreeType2 monochrome bitmap to a cache canvas. - void _renderMono(cached_text_t *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const; + void render_mono(cached_text *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const; //! Render a FreeType2 grayscale bitmap to a cache canvas. - void _renderGray(cached_text_t *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const; + void render_gray(cached_text *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const; - static FT_Library ms_pFreeType; - static int ms_iFreeTypeInitCount; - static const int ms_CacheSizeLog2 = 7; - FT_Face m_pFace; - THColour m_oColour; - bool m_bDoneFreeTypeInit; - mutable cached_text_t m_aCache[1 << ms_CacheSizeLog2]; + static FT_Library freetype_library; + static int freetype_init_count; + static const int cache_size_log2 = 7; + FT_Face font_face; + argb_colour colour; + bool is_done_freetype_init; + mutable cached_text cache[1 << cache_size_log2]; // The following five methods are implemented by the rendering engine. @@ -251,33 +289,27 @@ 8-bit grayscale rendering should be used (though in the latter case, 1-bit rendering might still get used). */ - bool _isMonochrome() const; - - //! Set the texture field of a cache entry to indicate no texture. - /*! - @param pCacheEntry A cache entry whose pTexture or iTexture field - should be set to a null value, whatever that means for the - rendering engine. - */ - void _setNullTexture(cached_text_t* pCacheEntry) const; + bool is_monochrome() const; //! Convert a cache canvas containing rendered text into a texture. /*! + @param pEventualCanvas A pointer to the rendertarget we'll be using to + draw this. @param pCacheEntry A cache entry whose pData field points to a pixmap of size iWidth by iHeight. This method will convert said pixmap to an object which can be used by the rendering engine, and store the result in the pTexture or iTexture field. */ - void _makeTexture(cached_text_t* pCacheEntry) const; + void make_texture(render_target *pEventualCanvas, cached_text* pCacheEntry) const; //! Free a previously-made texture of a cache entry. /*! This call should free all the resources previously allocated by a call - to _makeTexture(). + to _makeTexture() and set the texture field to indicate no texture. @param pCacheEntry A cache entry previously passed to _makeTexture(). */ - void _freeTexture(cached_text_t* pCacheEntry) const; + void free_texture(cached_text* pCacheEntry) const; //! Render a previously-made texture of a cache entry. /*! @@ -288,7 +320,7 @@ @param iX The X position at which to draw the texture on the canvas. @param iY The Y position at which to draw the texture on the canvas. */ - void _drawTexture(THRenderTarget* pCanvas, cached_text_t* pCacheEntry, + void draw_texture(render_target* pCanvas, cached_text* pCacheEntry, int iX, int iY) const; }; #endif // CORSIX_TH_USE_FREETYPE2 diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx.h corsix-th-0.62/CorsixTH/Src/th_gfx.h --- corsix-th-0.30/CorsixTH/Src/th_gfx.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx.h 2018-07-21 11:13:17.000000000 +0000 @@ -24,78 +24,77 @@ #define CORSIX_TH_TH_GFX_H_ #include "th.h" -class LuaPersistReader; -class LuaPersistWriter; +class lua_persist_reader; +class lua_persist_writer; -enum THScaledItems -{ - THSI_None = 0, - THSI_SpriteSheets = 1 << 0, - THSI_Bitmaps = 1 << 1, - THSI_All = 3, +enum class scaled_items { + none, + sprite_sheets, + bitmaps, + all }; -#include "th_gfx_dx9.h" -#include "th_gfx_ogl.h" #include "th_gfx_sdl.h" #include "th_gfx_font.h" -#include - -#ifndef CORSIX_TH_HAS_RENDERING_ENGINE -#error No rendering engine enabled in config file -#endif +#include +#include +#include -void IntersectTHClipRect(THClipRect& rcClip,const THClipRect& rcIntersect); +void clip_rect_intersection(clip_rect& rcClip, const clip_rect& rcIntersect); //! Bitflags for drawing operations -enum THDrawFlags +enum draw_flags : uint32_t { /** Sprite drawing flags **/ /* Where possible, designed to be the same values used by TH data files */ //! Draw with the left becoming the right and vice versa - THDF_FlipHorizontal = 1 << 0, + thdf_flip_horizontal = 1 << 0, //! Draw with the top becoming the bottom and vice versa - THDF_FlipVertical = 1 << 1, + thdf_flip_vertical = 1 << 1, //! Draw with 50% transparency - THDF_Alpha50 = 1 << 2, + thdf_alpha_50 = 1 << 2, //! Draw with 75% transparency - THDF_Alpha75 = 1 << 3, + thdf_alpha_75 = 1 << 3, //! Draw using a remapped palette - THDF_AltPalette = 1 << 4, + thdf_alt_palette = 1 << 4, + + /** How to draw alternative palette in 32bpp. */ + /* A 3 bit field (bits 5,6,7), currently 2 bits used. */ + + //! Lowest bit of the field. + thdf_alt32_start = 5, + //! Mask for the 32bpp alternative drawing values. + thdf_alt32_mask = 0x7 << thdf_alt32_start, + + //! Draw the sprite with the normal palette (fallback option). + thdf_alt32_plain = 0 << thdf_alt32_start, + //! Draw the sprite in grey scale. + thdf_alt32_grey_scale = 1 << thdf_alt32_start, + //! Draw the sprite with red and blue colours swapped. + thdf_alt32_blue_red_swap = 2 << thdf_alt32_start, /** Object attached to tile flags **/ /* (should be set prior to attaching to a tile) */ //! Attach to the early sprite list (right-to-left pass) - THDF_EarlyList = 1 << 10, + thdf_early_list = 1 << 10, //! Keep this sprite at the bottom of the attached list - THDF_ListBottom = 1 << 11, + thdf_list_bottom = 1 << 11, //! Hit-test using bounding-box precision rather than pixel-perfect - THDF_BoundBoxHitTest= 1 << 12, + thdf_bound_box_hit_test = 1 << 12, //! Apply a cropping operation prior to drawing - THDF_Crop = 1 << 13, -}; - -//! Bitflags for animation frames -enum THFrameFlags -{ - //! First frame of an animation - THFF_AnimationStart = 1 << 0, + thdf_crop = 1 << 13, }; -struct THRenderTargetCreationParams +/** Helper structure with parameters to create a #THRenderTarget. */ +struct render_target_creation_params { - int iWidth; - int iHeight; - int iBPP; - uint32_t iSDLFlags; - bool bHardware; - bool bDoubleBuffered; - bool bFullscreen; - bool bPresentImmediate; - bool bReuseContext; - bool bOpenGL; + int width; ///< Expected width of the render target. + int height; ///< Expected height of the render target. + int bpp; ///< Expected colour depth of the render target. + bool fullscreen; ///< Run full-screen. + bool present_immediate; ///< Whether to present immediately to the user (else wait for Vsync). }; /*! @@ -103,59 +102,63 @@ Note that "object" is used as a generic term, not in specific reference to game objects (though they are the most common thing in drawing lists). */ -struct THDrawable : public THLinkList +// TODO: Replace this struct with something cleaner +struct drawable : public link_list { //! Draw the object at a specific point on a render target /*! Can also "draw" the object to the speakers, i.e. play sounds. */ - void (*m_fnDraw)(THDrawable* pSelf, THRenderTarget* pCanvas, int iDestX, int iDestY); + void (*draw_fn)(drawable* pSelf, render_target* pCanvas, int iDestX, int iDestY); //! Perform a hit test against the object /*! Should return true if when the object is drawn at (iDestX, iDestY) on a canvas, the point (iTestX, iTestY) is within / on the object. */ - bool (*m_fnHitTest)(THDrawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY); + bool (*hit_test_fn)(drawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY); - //! Drawing flags (zero or more list flags from THDrawFlags) - unsigned long m_iFlags; + //! Drawing flags (zero or more list flags from #draw_flags). + uint32_t flags; /** Returns true if instance is a multiple frame animation. Should be overloaded in derived class. */ - bool (*m_fnIsMultipleFrameAnimation)(THDrawable *pSelf); + bool (*is_multiple_frame_animation_fn)(drawable *pSelf); }; /*! Utility class for decoding Theme Hospital "chunked" graphics files. - Generally used internally by THSpriteSheet. + Generally used internally by sprite_sheet. */ -class THChunkRenderer +class chunk_renderer { public: //! Initialise a renderer for a specific size result /*! @param width Pixel width of the resulting image @param height Pixel height of the resulting image - @param buffer If NULL, then a new buffer is created to render the image + @param buffer If nullptr, then a new buffer is created to render the image onto. Otherwise, should be an array at least width*height in size. Ownership of this pointer is assumed by the class - call takeData() to take ownership back again. */ - THChunkRenderer(int width, int height, unsigned char *buffer = NULL); + chunk_renderer(int width, int height, uint8_t *buffer = nullptr); - ~THChunkRenderer(); + ~chunk_renderer(); + // TODO: Should be function, not method of chunk_renderer //! Convert a stream of chunks into a raw bitmap /*! + @param pData Stream data. + @param iDataLen Length of \a pData. @param bComplex true if pData is a stream of "complex" chunks, false if pData is a stream of "simple" chunks. Passing the wrong value will usually result in a very visible wrong result. Use getData() or takeData() to obtain the resulting bitmap. */ - void decodeChunks(const unsigned char* pData, int iDataLen, bool bComplex); + void decode_chunks(const uint8_t* pData, int iDataLen, bool bComplex); //! Get the result buffer, and take ownership of it /*! @@ -163,99 +166,157 @@ the class will not have any buffer, and thus cannot be used for anything. */ - unsigned char* takeData(); + uint8_t* take_data(); //! Get the result buffer - inline const unsigned char* getData() const {return m_data;} + inline const uint8_t* get_data() const {return data;} //! Perform a "copy" chunk (normally called by decodeChunks) - void chunkCopy(int npixels, const unsigned char* data); + void chunk_copy(int npixels, const uint8_t* in_data); //! Perform a "fill" chunk (normally called by decodeChunks) - void chunkFill(int npixels, unsigned char value); + void chunk_fill(int npixels, uint8_t value); //! Perform a "fill to end of line" chunk (normally called by decodeChunks) - void chunkFillToEndOfLine(unsigned char value); + void chunk_fill_to_end_of_line(uint8_t value); //! Perform a "fill to end of file" chunk (normally called by decodeChunks) - void chunkFinish(unsigned char value); + void chunk_finish(uint8_t value); -protected: - inline bool _isDone() {return m_ptr == m_end;} - inline void _fixNpixels(int& npixels) const; - inline void _incrementPosition(int npixels); +private: + inline bool is_done() {return ptr == end;} + inline void fix_n_pixels(int& npixels) const; + inline void increment_position(int npixels); - unsigned char *m_data, *m_ptr, *m_end; - int m_x, m_y, m_width, m_height; - bool m_skip_eol; + uint8_t *data, *ptr, *end; + int x, y, width, height; + bool skip_eol; }; -//! Layer information (see THAnimationManager::drawFrame) -struct THLayers_t +//! Layer information (see animation_manager::draw_frame) +struct layers { - unsigned char iLayerContents[13]; + uint8_t layer_contents[13]; }; +class memory_reader; + +/** Key value for finding an animation. */ +struct animation_key +{ + std::string name; ///< Name of the animations. + int tile_size; ///< Size of a tile. +}; + +//! Less-than operator for map-sorting. +/*! + @param oK First key value. + @param oL Second key value. + @return Whether \a oK should be before \a oL. + */ +inline bool operator<(const animation_key &oK, const animation_key &oL) +{ + if (oK.tile_size != oL.tile_size) return oK.tile_size < oL.tile_size; + return oK.name < oL.name; +} + +/** + * Start frames of an animation, in each view direction. + * A negative number indicates there is no animation in that direction. + */ +struct animation_start_frames +{ + long north; ///< Animation start frame for the 'north' view. + long east; ///< Animation start frame for the 'east' view. + long south; ///< Animation start frame for the 'south' view. + long west; ///< Animation start frame for the 'west' view. +}; + +/** Map holding the custom animations. */ +typedef std::map named_animations_map; + +/** Insertion data structure. */ +typedef std::pair named_animation_pair; + //! Theme Hospital sprite animation manager /*! An animation manager takes a sprite sheet and four animation information files, and uses them to draw animation frames and provide information about the animations. */ -class THAnimationManager +class animation_manager { public: - THAnimationManager(); - ~THAnimationManager(); + animation_manager(); + ~animation_manager(); - void setSpriteSheet(THSpriteSheet* pSpriteSheet); + void set_sprite_sheet(sprite_sheet* pSpriteSheet); - //! Load animation information + //! Load original animations. /*! - setSpriteSheet() must be called before calling this. - @param pStartData Animation first frame indicies (e.g. VSTART-1.ANI) + set_sprite_sheet() must be called before calling this. + @param pStartData Animation first frame indices (e.g. VSTART-1.ANI) + @param iStartDataLength Length of \a pStartData. @param pFrameData Frame details (e.g. VFRA-1.ANI) - @param pListData Element indicies list (e.g. VLIST-1.ANI) + @param iFrameDataLength Length of \a pFrameData + @param pListData Element indices list (e.g. VLIST-1.ANI) + @param iListDataLength Length of \a pListData @param pElementData Element details (e.g. VELE-1.ANI) + @param iElementDataLength Length of \a pElementData + @return Loading was successful. + */ + bool load_from_th_file(const uint8_t* pStartData, size_t iStartDataLength, + const uint8_t* pFrameData, size_t iFrameDataLength, + const uint8_t* pListData, size_t iListDataLength, + const uint8_t* pElementData, size_t iElementDataLength); + + //! Set the video target. + /*! + @param pCanvas Video surface to use. + */ + void set_canvas(render_target *pCanvas); + + //! Load free animations. + /*! + @param pData Start of the loaded data. + @param iDataLength Length of the loaded data. + @return Loading was successful. */ - bool loadFromTHFile(const unsigned char* pStartData, size_t iStartDataLength, - const unsigned char* pFrameData, size_t iFrameDataLength, - const unsigned char* pListData, size_t iListDataLength, - const unsigned char* pElementData, size_t iElementDataLength); + bool load_custom_animations(const uint8_t* pData, size_t iDataLength); //! Get the total numer of animations - unsigned int getAnimationCount() const; + size_t get_animation_count() const; //! Get the total number of animation frames - unsigned int getFrameCount() const; + size_t get_frame_count() const; //! Get the index of the first frame of an animation - unsigned int getFirstFrame(unsigned int iAnimation) const; + size_t get_first_frame(size_t iAnimation) const; //! Get the index of the frame after a given frame /*! - To draw an animation frame by frame, call getFirstFrame() to get the - index of the first frame, and then keep on calling getNextFrame() using - the most recent return value from getNextFrame() or getFirstFrame(). + To draw an animation frame by frame, call get_first_frame() to get the + index of the first frame, and then keep on calling get_next_frame() using + the most recent return value from get_next_frame() or get_first_frame(). */ - unsigned int getNextFrame(unsigned int iFrame) const; + size_t get_next_frame(size_t iFrame) const; //! Set the palette remap data for an animation /*! This sets the palette remap data for every single sprite used by the given animation. If the animation (or any of its sprites) are drawn - using the THDF_AltPalette flag, then palette indicies will be mapped to - new palette indicies by the 256 byte array pMap. This is typically used + using the thdf_alt_palette flag, then palette indices will be mapped to + new palette indices by the 256 byte array pMap. This is typically used to draw things in different colours or in greyscale. */ - void setAnimationAltPaletteMap(unsigned int iAnimation, const unsigned char* pMap); + void set_animation_alt_palette_map(size_t iAnimation, const uint8_t* pMap, uint32_t iAlt32); //! Draw an animation frame /*! @param pCanvas The render target to draw onto. @param iFrame The frame index to draw (should be in range [0, getFrameCount() - 1]) @param oLayers Information to decide what to draw on each layer. - An animation is comprised of upto thirteen layers, numbered 0 + An animation is comprised of up to thirteen layers, numbered 0 through 12. Some animations will have different options for what to render on each layer. For example, patient animations generally have the different options on layer 1 as different clothes, so if @@ -268,32 +329,47 @@ @param iY The screen position to use as the animation Y origin. @param iFlags Zero or more THDrawFlags flags. */ - void drawFrame(THRenderTarget* pCanvas, unsigned int iFrame, const THLayers_t& oLayers, int iX, int iY, unsigned long iFlags) const; + void draw_frame(render_target* pCanvas, size_t iFrame, + const ::layers& oLayers, + int iX, int iY, uint32_t iFlags) const; + + void get_frame_extent(size_t iFrame, const ::layers& oLayers, + int* pMinX, int* pMaxX, int* pMinY, int* pMaxY, + uint32_t iFlags) const; + size_t get_frame_sound(size_t iFrame); + + bool hit_test(size_t iFrame, const ::layers& oLayers, + int iX, int iY, uint32_t iFlags, int iTestX, int iTestY) const; + + bool set_frame_marker(size_t iFrame, int iX, int iY); + bool set_frame_secondary_marker(size_t iFrame, int iX, int iY); + bool get_frame_marker(size_t iFrame, int* pX, int* pY); + bool get_frame_secondary_marker(size_t iFrame, int* pX, int* pY); - void getFrameExtent(unsigned int iFrame, const THLayers_t& oLayers, int* pMinX, int* pMaxX, int* pMinY, int* pMaxY, unsigned long iFlags) const; - unsigned int getFrameSound(unsigned int iFrame); - - bool hitTest(unsigned int iFrame, const THLayers_t& oLayers, int iX, int iY, unsigned long iFlags, int iTestX, int iTestY) const; - - bool setFrameMarker(unsigned int iFrame, int iX, int iY); - bool setFrameSecondaryMarker(unsigned int iFrame, int iX, int iY); - bool getFrameMarker(unsigned int iFrame, int* pX, int* pY); - bool getFrameSecondaryMarker(unsigned int iFrame, int* pX, int* pY); + //! Retrieve a custom animation by name and tile size. + /*! + @param sName Name of the animation. + @param iTilesize Tile size of the animation. + @return A set starting frames for the queried animation. + */ + const animation_start_frames &get_named_animations(const std::string &sName, int iTilesize) const; -protected: +private: #if CORSIX_TH_USE_PACK_PRAGMAS #pragma pack(push) #pragma pack(1) #endif - struct th_anim_t + // Animation information structure reinterpreted from Theme Hospital data. + struct th_animation_properties { - uint16_t frame; + uint16_t first_frame; // It could be that frame is a uint32_t rather than a uint16_t, which // would resolve the following unknown (which seems to always be zero). uint16_t unknown; } CORSIX_TH_PACKED_FLAGS; - struct th_frame_t + // Frame information structure reinterpreted from Theme Hospital data. + struct th_frame_properties { uint32_t list_index; // These fields have something to do with width and height, but it's @@ -302,18 +378,19 @@ uint8_t height; // If non-zero, index into sound.dat filetable. uint8_t sound; - // Combination of zero or more THFrameFlags values + // Combination of zero or more fame_flags values uint8_t flags; uint16_t next; } CORSIX_TH_PACKED_FLAGS; - struct th_element_t + // Structure reinterpreted from Theme Hospital data. + struct th_element_properties { uint16_t table_position; uint8_t offx; uint8_t offy; // High nibble: The layer which the element belongs to [0, 12] - // Low nibble: Zero or more THDrawFlags flags + // Low nibble: Zero or more draw_flags uint8_t flags; // The layer option / layer id uint8_t layerid; @@ -322,170 +399,219 @@ #pragma pack(pop) #endif - struct frame_t + struct frame { - unsigned int iListIndex; - unsigned int iNextFrame; - unsigned int iSound; - unsigned int iFlags; + size_t list_index; ///< First entry in #element_list (pointing to an element) for this frame. + size_t next_frame; ///< Number of the next frame. + unsigned int sound; ///< Sound to play, if non-zero. + unsigned int flags; ///< Flags of the frame. Bit 0=start of animation. + // Bounding rectangle is with all layers / options enabled - used as a // quick test prior to a full pixel perfect test. - int iBoundingLeft; - int iBoundingRight; - int iBoundingTop; - int iBoundingBottom; + int bounding_left; ///< Left edge of the bounding rectangle of this frame. + int bounding_right; ///< Right edge of the bounding rectangle of this frame. + int bounding_top; ///< Top edge of the bounding rectangle of this frame. + int bounding_bottom; ///< Bottom edge of the bounding rectangle of this frame. + // Markers are used to know where humanoids are on an frame. The // positions are pixels offsets from the centre of the frame's base // tile to the centre of the humanoid's feet. - int iMarkerX; - int iMarkerY; - int iSecondaryMarkerX; - int iSecondaryMarkerY; + int marker_x; ///< X position of the first center of a humanoids feet. + int marker_y; ///< Y position of the first center of a humanoids feet. + int secondary_marker_x; ///< X position of the second center of a humanoids feet. + int secondary_marker_y; ///< Y position of the second center of a humanoids feet. }; - struct element_t + struct element { - unsigned int iSprite; - unsigned int iFlags; - int iX; - int iY; - unsigned char iLayer; - unsigned char iLayerId; + size_t sprite; ///< Sprite number of the sprite sheet to display. + uint32_t flags; ///< Flags of the sprite. + ///< bit 0=flip vertically, bit 1=flip horizontally, + ///< bit 2=draw 50% alpha, bit 3=draw 75% alpha. + int x; ///< X offset of the sprite. + int y; ///< Y offset of the sprite. + uint8_t layer; ///< Layer class (0..12). + uint8_t layer_id; ///< Value of the layer class to match. + + sprite_sheet *element_sprite_sheet; ///< Sprite sheet to use for this element. }; - unsigned int* m_pFirstFrames; - frame_t* m_pFrames; - uint16_t* m_pElementList; - element_t* m_pElements; - THSpriteSheet* m_pSpriteSheet; - - unsigned int m_iAnimationCount; - unsigned int m_iFrameCount; - unsigned int m_iElementCount; + std::vector first_frames; ///< First frame number of an animation. + std::vector frames; ///< The loaded frames. + std::vector element_list; ///< List of elements for a frame. + std::vector elements; ///< Sprite Elements. + std::vector custom_sheets; ///< Sprite sheets with custom graphics. + named_animations_map named_animations; ///< Collected named animations. + + sprite_sheet* sheet; ///< Sprite sheet to use. + render_target *canvas; ///< Video surface to use. + + size_t animation_count; ///< Number of animations. + size_t frame_count; ///< Number of frames. + size_t element_list_count; ///< Number of list elements. + size_t element_count; ///< Number of sprite elements. + + //! Compute the bounding box of the frame. + /*! + @param oFrame Frame to inspect/set. + */ + void set_bounding_box(frame &oFrame); + + //! Load sprite elements from the input. + /*! + @param [inout] input Data to read. + @param pSpriteSheet Sprite sheet to use. + @param iNumElements Number of elements to read. + @param [inout] iLoadedElements Number of loaded elements so far. + @param iElementStart Offset of the first element. + @param iElementCount Number of elements to load. + @return Index of the first loaded element in #elements. Negative value means failure. + */ + size_t load_elements(memory_reader &input, sprite_sheet *pSpriteSheet, + size_t iNumElements, size_t &iLoadedElements, + size_t iElementStart, size_t iElementCount); + + //! Construct a list element for every element, and a 0xFFFF at the end. + /*! + @param iFirstElement Index of the first element in #elements. + @param iNumElements Number of elements to add. + @param [inout] iLoadedListElements Number of created list elements so far. + @param iListStart Offset of the first created list element. + @param iListCount Expected number of list elements to create. + @return Index of the list elements, or a negative value to indicate failure. + */ + size_t make_list_elements(size_t iFirstElement, size_t iNumElements, + size_t &iLoadedListElements, + size_t iListStart, size_t iListCount); + + //! Fix the flags of the first frame, and set the next frame of the last frame back to the first frame. + /*! + @param iFirst First frame of the animation, or 0xFFFFFFFFu. + @param iLength Number of frames in the animation. + */ + void fix_next_frame(uint32_t iFirst, size_t iLength); }; -struct THMapNode; -class THAnimationBase : public THDrawable +struct map_tile; +class animation_base : public drawable { public: - THAnimationBase(); + animation_base(); - void removeFromTile(); - void attachToTile(THMapNode *pMapNode, int layer); + void remove_from_tile(); + void attach_to_tile(map_tile *pMapNode, int layer); - unsigned long getFlags() const {return m_iFlags;} - int getX() const {return m_iX;} - int getY() const {return m_iY;} - - void setFlags(unsigned long iFlags) {m_iFlags = iFlags;} - void setPosition(int iX, int iY) {m_iX = iX, m_iY = iY;} - void setLayer(int iLayer, int iId); - void setLayersFrom(const THAnimationBase *pSrc) {m_oLayers = pSrc->m_oLayers;} + uint32_t get_flags() const {return flags;} + int get_x() const {return x_relative_to_tile;} + int get_y() const {return y_relative_to_tile;} + + void set_flags(uint32_t iFlags) {flags = iFlags;} + void set_position(int iX, int iY) {x_relative_to_tile = iX, y_relative_to_tile = iY;} + void set_layer(int iLayer, int iId); + void set_layers_from(const animation_base *pSrc) {layers = pSrc->layers;} // bool isMultipleFrameAnimation() { return false;} protected: - void _clear(); - //! X position on tile (not tile x-index) - int m_iX; + int x_relative_to_tile; //! Y position on tile (not tile y-index) - int m_iY; - - THLayers_t m_oLayers; + int y_relative_to_tile; + ::layers layers; }; -class THAnimation : public THAnimationBase +class animation : public animation_base { public: - THAnimation(); + animation(); - void setParent(THAnimation *pParent); + void set_parent(animation *pParent); void tick(); - void draw(THRenderTarget* pCanvas, int iDestX, int iDestY); - bool hitTest(int iDestX, int iDestY, int iTestX, int iTestY); - void drawMorph(THRenderTarget* pCanvas, int iDestX, int iDestY); - bool hitTestMorph(int iDestX, int iDestY, int iTestX, int iTestY); - void drawChild(THRenderTarget* pCanvas, int iDestX, int iDestY); - bool hitTestChild(int iDestX, int iDestY, int iTestX, int iTestY); - - THLinkList* getPrevious() {return m_pPrev;} - unsigned int getAnimation() const {return m_iAnimation;} - bool getMarker(int* pX, int* pY); - bool getSecondaryMarker(int* pX, int* pY); - unsigned int getFrame() const {return m_iFrame;} - int getCropColumn() const {return m_iCropColumn;} - - void setAnimation(THAnimationManager* pManager, unsigned int iAnimation); - void setMorphTarget(THAnimation *pMorphTarget, unsigned int iDurationFactor = 1); - void setFrame(unsigned int iFrame); - - void setSpeed(int iX, int iY) {m_iSpeedX = iX, m_iSpeedY = iY;} - void setCropColumn(int iColumn) {m_iCropColumn = iColumn;} - - void persist(LuaPersistWriter *pWriter) const; - void depersist(LuaPersistReader *pReader); - - THAnimationManager* getAnimationManager(){ return m_pManager;} -protected: - THAnimationManager *m_pManager; - THAnimation* m_pMorphTarget; - unsigned int m_iAnimation; - unsigned int m_iFrame; - union { struct { - //! Amount to change m_iX per tick - int m_iSpeedX; - //! Amount to change m_iY per tick - int m_iSpeedY; - }; + void draw(render_target* pCanvas, int iDestX, int iDestY); + bool hit_test(int iDestX, int iDestY, int iTestX, int iTestY); + void draw_morph(render_target* pCanvas, int iDestX, int iDestY); + bool hit_test_morph(int iDestX, int iDestY, int iTestX, int iTestY); + void draw_child(render_target* pCanvas, int iDestX, int iDestY); + bool hit_test_child(int iDestX, int iDestY, int iTestX, int iTestY); + + link_list* get_previous() {return prev;} + size_t get_animation() const {return animation_index;} + bool get_marker(int* pX, int* pY); + bool get_secondary_marker(int* pX, int* pY); + size_t get_frame() const {return frame_index;} + int get_crop_column() const {return crop_column;} + + void set_animation(animation_manager* pManager, size_t iAnimation); + void set_morph_target(animation *pMorphTarget, unsigned int iDurationFactor = 1); + void set_frame(size_t iFrame); + + void set_speed(int iX, int iY) {speed.dx = iX, speed.dy = iY;} + void set_crop_column(int iColumn) {crop_column = iColumn;} + + void persist(lua_persist_writer *pWriter) const; + void depersist(lua_persist_reader *pReader); + + animation_manager* get_animation_manager(){ return manager;} +private: + animation_manager *manager; + animation* morph_target; + size_t animation_index; ///< Animation number. + size_t frame_index; ///< Frame number. + union { + struct { + //! Amount to change x per tick + int dx; + //! Amount to change y per tick + int dy; + } speed; //! Some animations are tied to the marker of another animation and //! hence have a parent rather than a speed. - THAnimation* m_pParent; + animation* parent; }; - unsigned int m_iSoundToPlay; - int m_iCropColumn; + size_t sound_to_play; + int crop_column; }; -class THSpriteRenderList : public THAnimationBase +class sprite_render_list : public animation_base { public: - THSpriteRenderList(); - ~THSpriteRenderList(); + sprite_render_list(); + ~sprite_render_list(); void tick(); - void draw(THRenderTarget* pCanvas, int iDestX, int iDestY); - bool hitTest(int iDestX, int iDestY, int iTestX, int iTestY); + void draw(render_target* pCanvas, int iDestX, int iDestY); + bool hit_test(int iDestX, int iDestY, int iTestX, int iTestY); - void setSheet(THSpriteSheet* pSheet) {m_pSpriteSheet = pSheet;} - void setSpeed(int iX, int iY) {m_iSpeedX = iX, m_iSpeedY = iY;} - void setLifetime(int iLifetime); - void appendSprite(unsigned int iSprite, int iX, int iY); - bool isDead() const {return m_iLifetime == 0;} + void set_sheet(sprite_sheet* pSheet) {sheet = pSheet;} + void set_speed(int iX, int iY) {dx_per_tick = iX, dy_per_tick = iY;} + void set_lifetime(int iLifetime); + void append_sprite(size_t iSprite, int iX, int iY); + bool is_dead() const {return lifetime == 0;} - void persist(LuaPersistWriter *pWriter) const; - void depersist(LuaPersistReader *pReader); + void persist(lua_persist_writer *pWriter) const; + void depersist(lua_persist_reader *pReader); -protected: - struct _sprite_t +private: + struct sprite { - unsigned int iSprite; - int iX; - int iY; + size_t index; + int x; + int y; }; - THSpriteSheet* m_pSpriteSheet; - _sprite_t* m_pSprites; - int m_iNumSprites; - int m_iBufferSize; - - //! Amount to change m_iX per tick - int m_iSpeedX; - //! Amount to change m_iY per tick - int m_iSpeedY; + sprite_sheet* sheet; + sprite* sprites; + int sprite_count; + int buffer_size; + + //! Amount to change x per tick + int dx_per_tick; + //! Amount to change y per tick + int dy_per_tick; //! Number of ticks until reports as dead (-1 = never dies) - int m_iLifetime; + int lifetime; }; #endif // CORSIX_TH_TH_GFX_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx_ogl.cpp corsix-th-0.62/CorsixTH/Src/th_gfx_ogl.cpp --- corsix-th-0.30/CorsixTH/Src/th_gfx_ogl.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx_ogl.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1492 +0,0 @@ -/* -Copyright (c) 2009-2013 Peter "Corsix" Cawley and Edvin "Lego3" Linge - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "config.h" -#ifdef CORSIX_TH_USE_OGL_RENDERER - -#include "th_gfx.h" -#include -#include -#ifdef _MSC_VER -#pragma comment(lib, "OpenGL32") -#endif -#ifndef _WIN32 -struct RECT -{ - long top, bottom, left, right; -}; -#ifndef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#endif -#endif - -THRenderTarget::THRenderTarget() -{ - m_pSurface = NULL; - m_pVerticies = NULL; - setClipRect(NULL); - m_iVertexCount = 0; - m_iVertexLength = 0; - m_iNonOverlappingStart = 0; - m_iNonOverlapping = 0; - m_iWidth = 0; - m_iHeight = 0; -#ifdef CORSIX_TH_USE_OGL_RENDER_TO_TEXTURE - m_glGenFramebuffersEXT = NULL; - m_glBindFramebufferEXT = NULL; - m_glFramebufferTexture2DEXT = NULL; - m_glDeleteFramebuffersEXT = NULL; - m_glCheckFramebufferStatusEXT = NULL; - m_iZoomTexture = 0; - m_iZoomFrameBuffer = 0; - m_iZoomTextureSize = 0; - m_bUsingZoomBuffer = false; -#endif - m_bShouldScaleBitmaps = false; -} - -THRenderTarget::~THRenderTarget() -{ - if(m_pVerticies != NULL) - { - free(m_pVerticies); - m_pVerticies = NULL; - } -#ifdef CORSIX_TH_USE_OGL_RENDER_TO_TEXTURE - if(m_iZoomFrameBuffer != 0) - { - m_glDeleteFramebuffersEXT(1, &m_iZoomFrameBuffer); - m_iZoomFrameBuffer = 0; - } - if(m_iZoomTexture != 0) - { - glDeleteTextures(1, &m_iZoomTexture); - m_iZoomTexture = 0; - } -#endif -} - -bool THRenderTarget::create(const THRenderTargetCreationParams* pParams) -{ - int iBPP = pParams->iBPP; - if(!pParams->bReuseContext) - { - if(iBPP == 0) - iBPP = SDL_GetVideoInfo()->vfmt->BitsPerPixel; - switch(iBPP) - { - case 8: - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 3); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 3); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 2); - break; - case 15: - case 16: - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); - break; - default: - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - break; - } - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, pParams->bDoubleBuffered ? 1:0); - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, pParams->bPresentImmediate ? 0:1); - m_pSurface = SDL_SetVideoMode(pParams->iWidth, pParams->iHeight, iBPP, - pParams->iSDLFlags); - if(m_pSurface == NULL) - return false; - } - - m_bBlueFilterActive = false; - - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if(!pParams->bReuseContext) - glViewport(0, 0, pParams->iWidth, pParams->iHeight); - m_iWidth = pParams->iWidth; - m_iHeight = pParams->iHeight; - GLdouble fWidth = (GLdouble)pParams->iWidth; - GLdouble fHeight = (GLdouble)pParams->iHeight; - setGLProjection(fWidth, fHeight); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - if(getGLError() != GL_NO_ERROR) - { - m_pSurface = NULL; - return false; - } - -#ifdef CORSIX_TH_USE_OGL_RENDER_TO_TEXTURE - bool bFoundAll = true; - // TODO: SDL_GL_GetProcAddress doesn't work without a call to - // SDL_SetVideoMode, which isn't done when a context is being - // re-used. -#define FIND(name, typ) \ - m_ ## name ## EXT = NULL; \ - if(bFoundAll && !pParams->bReuseContext) \ - { \ - m_ ## name ## EXT = (typ) SDL_GL_GetProcAddress(#name "EXT"); \ - if(!m_ ## name ## EXT) \ - { \ - m_ ## name ## EXT = (typ) SDL_GL_GetProcAddress(#name "ARB"); \ - if(!m_ ## name ## EXT) \ - { \ - m_ ## name ## EXT = (typ) SDL_GL_GetProcAddress(#name); \ - if(!m_ ## name ## EXT) \ - bFoundAll = false; \ - } \ - } \ - } - FIND(glGenFramebuffers , PFNGLGENFRAMEBUFFERSEXTPROC); - FIND(glBindFramebuffer , PFNGLBINDFRAMEBUFFEREXTPROC); - FIND(glFramebufferTexture2D , PFNGLFRAMEBUFFERTEXTURE2DEXTPROC); - FIND(glDeleteFramebuffers , PFNGLDELETEFRAMEBUFFERSEXTPROC); - FIND(glCheckFramebufferStatus, PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC); -#undef FIND -#endif - - return true; -} - -void THRenderTarget::setGLProjection(GLdouble fWidth, GLdouble fHeight) -{ - // NB: The loaded matrix is the transpose of the visible matrix - const GLdouble mtxProjection[16] = { - 2.0 / fWidth , 0.0 , 0.0, 0.0, - 0.0 , -2.0 / fHeight , 0.0, 0.0, - 0.0 , 0.0 , 1.0, 0.0, - -1.0 - (1.0 / fWidth), 1.0 + (1.0 / fHeight), 0.0, 1.0 - }; - glMatrixMode(GL_PROJECTION); - glLoadMatrixd(mtxProjection); - glTranslated(0.5, 0.5, 0.0); -} - -bool THRenderTarget::shouldScaleBitmaps(float* pFactor) -{ - if(!m_bShouldScaleBitmaps) - return false; - if(pFactor) - *pFactor = m_fBitmapScaleFactor; - return true; -} - -bool THRenderTarget::setScaleFactor(float fScale, THScaledItems eWhatToScale) -{ - flushSprites(); - _flushZoomBuffer(); - m_bShouldScaleBitmaps = false; - - if(eWhatToScale == THSI_None || (0.999 <= fScale && fScale <= 1.001)) - { - // Effectively back to no scaling, so nothing more to do - return true; - } - if(eWhatToScale == THSI_Bitmaps) - { - m_bShouldScaleBitmaps = true; - m_fBitmapScaleFactor = fScale; - return true; - } - -#ifdef CORSIX_TH_USE_OGL_RENDER_TO_TEXTURE - if(eWhatToScale == THSI_All && m_glCheckFramebufferStatusEXT) - { - if(fScale <= 0.0f) - return false; - float fVirtualSize = static_cast(max(m_iWidth, m_iHeight)) / fScale; - unsigned int iZoomTextureSize = 1 << static_cast( - ceil(logf(fVirtualSize) / logf(2))); - if(iZoomTextureSize == 0) // Catch integer overflow - return false; - - // Create the render texture - if(m_iZoomTextureSize != iZoomTextureSize) - { - if(m_iZoomFrameBuffer != 0) - { - m_glDeleteFramebuffersEXT(1, &m_iZoomFrameBuffer); - m_iZoomFrameBuffer = 0; - } - if(m_iZoomTexture != 0) - { - glDeleteTextures(1, &m_iZoomTexture); - m_iZoomTexture = 0; - } - - m_iZoomTextureSize = 0; - - // Create texture - glGenTextures(1, &m_iZoomTexture); - if(getGLError() != GL_NO_ERROR) - return false; - glBindTexture(GL_TEXTURE_2D, m_iZoomTexture); - if(getGLError() != GL_NO_ERROR) - return false; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - float fMaximumAnistropy; - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fMaximumAnistropy); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fMaximumAnistropy); - - glTexImage2D(GL_TEXTURE_2D, 0, 4, iZoomTextureSize, iZoomTextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - if(getGLError() != GL_NO_ERROR) - return false; - - // Create and check frame buffer - m_glGenFramebuffersEXT(1, &m_iZoomFrameBuffer); - if(getGLError() != GL_NO_ERROR) - return false; - m_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_iZoomFrameBuffer); - if(getGLError() != GL_NO_ERROR) - return false; - m_glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_iZoomTexture, 0); - if(getGLError() != GL_NO_ERROR) - return false; - GLenum status = m_glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if(status != GL_FRAMEBUFFER_COMPLETE_EXT) - return false; - m_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - m_iZoomTextureSize = iZoomTextureSize; - } - m_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_iZoomFrameBuffer); - glViewport(0,0,m_iZoomTextureSize, m_iZoomTextureSize); - setGLProjection(m_iZoomTextureSize, m_iZoomTextureSize); - m_bUsingZoomBuffer = true; - m_fZoomScale = fScale; - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - return true; - } -#endif - return false; -} - -void THRenderTarget::_flushZoomBuffer() -{ -#ifdef CORSIX_TH_USE_OGL_RENDER_TO_TEXTURE - if(!m_bUsingZoomBuffer) - return; - m_bUsingZoomBuffer = false; - - m_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glViewport(0,0,m_iWidth, m_iHeight); - setGLProjection(m_iWidth, m_iHeight); - - float fFactor = m_fZoomScale * static_cast(m_iZoomTextureSize); -#define SetVertexData(n, x_, y_) \ - pVerticies[n].x = (float)x_; \ - pVerticies[n].y = (float)y_; \ - pVerticies[n].z = 0.0f; \ - pVerticies[n].colour = THPalette::packARGB(0xFF, 0xFF, 0xFF, 0xFF); \ - pVerticies[n].u = (float)x_ / fFactor; \ - pVerticies[n].v = 1.0f - (float)y_ / fFactor - - THOGL_Vertex *pVerticies = allocVerticies(4, m_iZoomTexture); - SetVertexData(0, 0, 0); - SetVertexData(1, m_iWidth, 0); - SetVertexData(2, m_iWidth, m_iHeight); - SetVertexData(3, 0, m_iHeight); -#undef SetVertexData - flushSprites(); -#endif -} - -const char* THRenderTarget::getLastError() -{ - return SDL_GetError(); -} - -bool THRenderTarget::startFrame() -{ - return true; -} - -bool THRenderTarget::endFrame() -{ - if(!flushSprites()) - return false; - _flushZoomBuffer(); - - // Possibly add a blue filter on top of everything - if (m_bBlueFilterActive) - { - // This particular quad will not have any texture on it. - glDisable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - glColor4f(0.0f,0.0f,1.0f, 0.3f); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f((GLfloat) (GLfloat) getWidth(), 0.0f, 0.0f); - glVertex3f((GLfloat) getWidth(), (GLfloat) getHeight(), 0.0f); - glVertex3f(0.0f, (GLfloat) getHeight(), 0.0f); - glEnd(); - glEnable(GL_TEXTURE_2D); - } - - if(m_pSurface) - SDL_GL_SwapBuffers(); - return true; -} - -bool THRenderTarget::flushSprites() -{ - if(m_iVertexCount == 0) - return true; - - GLuint iTexture = m_pVerticies[0].tex; - glBindTexture(GL_TEXTURE_2D, iTexture); - if(getGLError() != GL_NO_ERROR) - goto gl_err; - { - size_t iStart = 0; - for(size_t i = 4; i < m_iVertexCount; i += 4) - { - if(m_pVerticies[i].tex != iTexture) - { - _drawVerts(iStart, i); - if(getGLError() != GL_NO_ERROR) - goto gl_err; - iStart = i; - iTexture = m_pVerticies[i].tex; - glBindTexture(GL_TEXTURE_2D, iTexture); - if(getGLError() != GL_NO_ERROR) - goto gl_err; - } - } - _drawVerts(iStart, m_iVertexCount); - } - if(getGLError() != GL_NO_ERROR) - goto gl_err; - - m_iVertexCount = 0; - return true; -gl_err: - m_iVertexCount = 0; - return false; -} - -GLenum THRenderTarget::getGLError() -{ - GLenum eError = glGetError(); - if(eError != GL_NO_ERROR) - { - // Clear multiple error bits, if there are any - while(glGetError()) - ; - } - return eError; -} - -void THRenderTarget::_drawVerts(size_t iFirst, size_t iLast) -{ - glInterleavedArrays(GL_T2F_C4UB_V3F, sizeof(THOGL_Vertex), - m_pVerticies + iFirst); - glDrawArrays(GL_QUADS, 0, static_cast(iLast - iFirst)); -} - -bool THRenderTarget::fillBlack() -{ - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - return getGLError() == GL_NO_ERROR; -} - -void THRenderTarget::setBlueFilterActive(bool bActivate) -{ - m_bBlueFilterActive = bActivate; -} - -uint32_t THRenderTarget::mapColour(uint8_t iR, uint8_t iG, uint8_t iB) -{ - return THPalette::packARGB(0xFF, iR, iG, iB); -} - -bool THRenderTarget::fillRect(uint32_t iColour, int iX, int iY, int iW, int iH) -{ - draw(0, iW, iH, iX, iY, 0, 1, 1, 0, 0); - THOGL_Vertex* pVerts = m_pVerticies + m_iVertexCount; - for(int i = 1; i <= 4; ++i) - { - pVerts[-i].colour = iColour; - } - return true; -} - -void THRenderTarget::getClipRect(THClipRect* pRect) const -{ - *pRect = m_rcClip; -} - -int THRenderTarget::getWidth() const -{ - return m_iWidth; -} - -int THRenderTarget::getHeight() const -{ - return m_iHeight; -} - -void THRenderTarget::setClipRect(const THClipRect* pRect) -{ - if(pRect != NULL) - { - m_rcClip = *pRect; - } - else - { - m_rcClip.x = -1000; - m_rcClip.y = -1000; - m_rcClip.w = 0xFFFF; - m_rcClip.h = 0xFFFF; - } -} - -void THRenderTarget::startNonOverlapping() -{ - if(m_iNonOverlapping++ == 0) - m_iNonOverlappingStart = m_iVertexCount; -} - -static int sprite_tex_compare(const void* left, const void* right) -{ - const THOGL_Vertex *pLeft = reinterpret_cast(left); - const THOGL_Vertex *pRight = reinterpret_cast(right); - - if(pLeft->tex == pRight->tex) - return 0; - else if(pLeft->tex < pRight->tex) - return -1; - else - return 1; -} - -void THRenderTarget::finishNonOverlapping() -{ - if(--m_iNonOverlapping > 0) - return; - - // If more than one texture is used in the range of non-overlapping - // sprites, then sort the entire range by texture. - - size_t iStart = m_iNonOverlappingStart; - GLuint iTexture = m_pVerticies[iStart].tex; - for(size_t i = iStart + 4; i < m_iVertexCount; i += 4) - { - if(m_pVerticies[i].tex != iTexture) - { - qsort(m_pVerticies + iStart, (m_iVertexCount - iStart) / 4, - sizeof(THOGL_Vertex) * 4, sprite_tex_compare); - break; - } - } -} - -void THRenderTarget::setCursor(THCursor* pCursor) -{ - // TODO (low priority, as Lua will simulate a cursor) -} - -void THRenderTarget::setCursorPosition(int iX, int iY) -{ - // TODO (low priority, as Lua will simulate a cursor) -} - -SDL_Surface* flipSurface(SDL_Surface* pSurface) -{ - SDL_Surface *pSurfaceFlipped = SDL_CreateRGBSurface(pSurface->flags, pSurface->w, pSurface->h, pSurface->format->BitsPerPixel, - pSurface->format->Rmask, pSurface->format->Gmask, pSurface->format->Bmask, pSurface->format->Amask); - if (pSurfaceFlipped == NULL) return NULL; - - uint8_t* src = reinterpret_cast(pSurface->pixels); - uint8_t* dest = reinterpret_cast(pSurfaceFlipped->pixels); - - for(int iY = 0; iY < pSurface->h; ++iY) - { - memcpy(dest + pSurface->pitch * iY, src + pSurface->pitch * (pSurface->h - 1 - iY), pSurface->pitch); - } - return pSurfaceFlipped; -} - -bool THRenderTarget::takeScreenshot(const char* sFile) -{ - SDL_Surface *pSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, this->m_iWidth, this->m_iHeight, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); - if(pSurface == NULL) - { - SDL_SetError("Could not create screenshot buffer"); - return false; - } - - // Read from buffer onto SDL surface - glReadBuffer(GL_FRONT); - glReadPixels(0, 0, this->m_iWidth, this->m_iHeight, GL_RGB, GL_UNSIGNED_BYTE, pSurface->pixels); - - // Flip y - SDL_Surface *pSurfaceFlipped = flipSurface(pSurface); - if(pSurfaceFlipped == NULL) - { - SDL_SetError("Could not create inverted screenshot buffer"); - return false; - } - - // Save contents of SDL surface - bool bResult = SDL_SaveBMP(pSurfaceFlipped, sFile) == 0; - SDL_FreeSurface(pSurface); - SDL_FreeSurface(pSurfaceFlipped); - - return bResult; -} - -int roundUp2(int x) -{ - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 3; - x |= x >> 4; - x |= x >> 16; - x++; - return x; -} - -GLuint THRenderTarget::createTexture(int iWidth, int iHeight, - const unsigned char* pPixels, - const THPalette* pPalette, - int* pWidth2, int* pHeight2) -{ - int iWidth2 = roundUp2(iWidth); - int iHeight2 = roundUp2(iHeight); - if(pWidth2) - *pWidth2 = iWidth2; - if(pHeight2) - *pHeight2 = iHeight2; - - uint32_t *pRGBAPixels = new (std::nothrow) uint32_t[iWidth2 * iHeight2]; - if(pRGBAPixels == NULL) - return 0; - const uint32_t iTransparent = THPalette::packARGB(0x00, 0x00, 0x00, 0x00); - const uint32_t* pColours = pPalette->getARGBData(); - - uint32_t *pRow = pRGBAPixels; - for(int y = 0; y < iHeight; ++y) - { - for(int x = 0; x < iWidth; ++x, ++pPixels, ++pRow) - { - *pRow = pColours[*pPixels]; - } - for(int x = iWidth; x < iWidth2; ++x, ++pRow) - { - *pRow = iTransparent; - } - } - for(int y = iHeight; y < iHeight2; ++y) - { - for(int x = 0; x < iWidth2; ++x, ++pRow) - { - *pRow = iTransparent; - } - } - - GLuint iTextureID = createTexture(iWidth2, iHeight2, pRGBAPixels); - delete[] pRGBAPixels; - return iTextureID; -} - -GLuint THRenderTarget::createTexture(int iWidth2, int iHeight2, const uint32_t* pPixels) -{ - GLuint iTextureID; - glGenTextures(1, &iTextureID); - glBindTexture(GL_TEXTURE_2D, iTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iWidth2, iHeight2, 0, GL_RGBA, - GL_UNSIGNED_BYTE, pPixels); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if(getGLError() != GL_NO_ERROR) - { - glDeleteTextures(1, &iTextureID); - return 0; - } - return iTextureID; -} - -THOGL_Vertex* THRenderTarget::allocVerticies(size_t iCount, - GLuint iTexture) -{ - if(m_iVertexCount + iCount > m_iVertexLength) - { - m_iVertexLength = (m_iVertexLength * 2) + iCount; - m_pVerticies = (THOGL_Vertex*)realloc(m_pVerticies, - sizeof(THOGL_Vertex) * m_iVertexLength); - } - THOGL_Vertex *pResult = m_pVerticies + m_iVertexCount; - pResult[0].tex = iTexture; - m_iVertexCount += iCount; - return pResult; -} - -void THRenderTarget::draw(GLuint iTexture, unsigned int iWidth, - unsigned int iHeight, int iX, int iY, - unsigned long iFlags, unsigned int iWidth2, - unsigned int iHeight2, unsigned int iTexX, - unsigned int iTexY) -{ - // Crop to clip rectangle - RECT rcSource; - rcSource.left = 0; - rcSource.top = 0; - rcSource.right = iWidth; - rcSource.bottom = iHeight; - if(iX + rcSource.right > m_rcClip.x + m_rcClip.w) - { - rcSource.right = m_rcClip.x + m_rcClip.w - iX; - } - if(iY + rcSource.bottom > m_rcClip.y + m_rcClip.h) - { - rcSource.bottom = m_rcClip.y + m_rcClip.h - iY; - } - if(iX + rcSource.left < m_rcClip.x) - { - rcSource.left = m_rcClip.x - iX; - iX = m_rcClip.x; - } - if(iY + rcSource.top < m_rcClip.y) - { - rcSource.top = m_rcClip.y - iY; - iY = m_rcClip.y; - } - if(rcSource.right < rcSource.left) - rcSource.right = rcSource.left; - if(rcSource.bottom < rcSource.top) - rcSource.bottom = rcSource.top; - - rcSource.left += iTexX; - rcSource.right += iTexX; - rcSource.bottom += iTexY; - rcSource.top += iTexY; - - // Set alpha blending options - uint32_t cColour; - switch(iFlags & (THDF_Alpha50 | THDF_Alpha75)) - { - case 0: - cColour = THPalette::packARGB(0xFF, 0xFF, 0xFF, 0xFF); - break; - case THDF_Alpha50: - cColour = THPalette::packARGB(0x80, 0xFF, 0xFF, 0xFF); - break; - default: - cColour = THPalette::packARGB(0x40, 0xFF, 0xFF, 0xFF); - break; - } - float fX = (float)iX; - float fY = (float)iY; - float fWidth = (float)(rcSource.right - rcSource.left); - float fHeight = (float)(rcSource.bottom - rcSource.top); - float fSprWidth = (float)iWidth2; - float fSprHeight = (float)iHeight2; - if(iFlags & THDF_FlipHorizontal) - { - rcSource.left = iTexX * 2 + iWidth - rcSource.left; - rcSource.right = iTexX * 2 + iWidth - rcSource.right; - } - if(iFlags & THDF_FlipVertical) - { - rcSource.top = iTexY * 2 + iHeight - rcSource.top; - rcSource.bottom = iTexY * 2 + iHeight - rcSource.bottom; - } - -#define SetVertexData(n, x_, y_, u_, v_) \ - pVerticies[n].x = fX + (float) x_; \ - pVerticies[n].y = fY + (float) y_; \ - pVerticies[n].z = 0.0f; \ - pVerticies[n].colour = cColour; \ - pVerticies[n].u = (float) u_; \ - pVerticies[n].v = (float) v_ - - THOGL_Vertex *pVerticies = allocVerticies(4, iTexture); - SetVertexData(0, 0, 0, rcSource.left / fSprWidth, rcSource.top / fSprHeight); - SetVertexData(1, fWidth, 0, rcSource.right / fSprWidth, pVerticies[0].v); - SetVertexData(2, fWidth, fHeight, pVerticies[1].u, rcSource.bottom / fSprHeight); - SetVertexData(3, 0, fHeight, pVerticies[0].u, pVerticies[2].v); -#undef SetVertexData -} - -THPalette::THPalette() -{ - m_iNumColours = 0; -} - -static const unsigned char gs_iTHColourLUT[0x40] = { - // Maps 0-63 to 0-255 - 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, - 0x20, 0x24, 0x28, 0x2D, 0x31, 0x35, 0x39, 0x3D, - 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, - 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, - 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, - 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, - 0xC2, 0xC6, 0xCA, 0xCE, 0xD2, 0xD7, 0xDB, 0xDF, - 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF, -}; - -bool THPalette::loadFromTHFile(const unsigned char* pData, size_t iDataLength) -{ - if(iDataLength != 256 * 3) - return false; - - m_iNumColours = static_cast(iDataLength / 3); - for(int i = 0; i < m_iNumColours; ++i, pData += 3) - { - unsigned char iR = gs_iTHColourLUT[pData[0] & 0x3F]; - unsigned char iG = gs_iTHColourLUT[pData[1] & 0x3F]; - unsigned char iB = gs_iTHColourLUT[pData[2] & 0x3F]; - uint32_t iColour = packARGB(0xFF, iR, iG, iB); - // Remap magenta to transparent - if(iColour == packARGB(0xFF, 0xFF, 0x00, 0xFF)) - iColour = packARGB(0x00, 0x00, 0x00, 0x00); - m_aColoursARGB[i] = iColour; - } - - return true; -} - -bool THPalette::setEntry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB) -{ - if(iEntry < 0 || iEntry >= m_iNumColours) - return false; - uint32_t iColour = packARGB(0xFF, iR, iG, iB); - // Remap magenta to transparent - if(iColour == packARGB(0xFF, 0xFF, 0x00, 0xFF)) - iColour = packARGB(0x00, 0x00, 0x00, 0x00); - m_aColoursARGB[iEntry] = iColour; - return true; -} - -int THPalette::getColourCount() const -{ - return m_iNumColours; -} - -const uint32_t* THPalette::getARGBData() const -{ - return m_aColoursARGB; -} - -THRawBitmap::THRawBitmap() -{ - m_iTexture = 0; - m_pPalette = NULL; - m_pTarget = NULL; - m_iWidth = 0; - m_iWidth2 = 0; - m_iHeight = 0; - m_iHeight2 = 0; -} - -THRawBitmap::~THRawBitmap() -{ - glDeleteTextures(1, &m_iTexture); -} - -void THRawBitmap::setPalette(const THPalette* pPalette) -{ - m_pPalette = pPalette; -} - -bool THRawBitmap::loadFromTHFile(const unsigned char* pPixelData, - size_t iPixelDataLength, int iWidth, - THRenderTarget *pEventualCanvas) -{ - if(pEventualCanvas == NULL) - return false; - if(!(m_iTexture = pEventualCanvas->createTexture(iWidth, - static_cast(iPixelDataLength)/iWidth, pPixelData, m_pPalette, - &m_iWidth2, &m_iHeight2))) - { - return false; - } - m_iWidth = iWidth; - m_iHeight = static_cast(iPixelDataLength) / iWidth; - m_pTarget = pEventualCanvas; - - return true; -} - -void THRawBitmap::draw(THRenderTarget* pCanvas, int iX, int iY) -{ - draw(pCanvas, iX, iY, 0, 0, m_iWidth, m_iHeight); -} - -void THRawBitmap::draw(THRenderTarget* pCanvas, int iX, int iY, int iSrcX, - int iSrcY, int iWidth, int iHeight) -{ - if(pCanvas == NULL || pCanvas != m_pTarget) - return; - - float fScaleFactor; - bool bShouldScale = pCanvas->shouldScaleBitmaps(&fScaleFactor); - if(bShouldScale) - { - pCanvas->flushSprites(); - glMatrixMode(GL_MODELVIEW); - glScalef(fScaleFactor, fScaleFactor, 1.0f); - } - - pCanvas->draw(m_iTexture, iWidth, iHeight, iX, iY, 0, m_iWidth2, - m_iHeight2, iSrcX, iSrcY); - - if(bShouldScale) - { - pCanvas->flushSprites(); - glLoadIdentity(); - } -} - -THSpriteSheet::THSpriteSheet() -{ - m_pSprites = NULL; - m_pPalette = NULL; - m_pTarget = NULL; - m_iMegaTexture = 0; - m_iMegaTextureSize = 0; - m_iSpriteCount = 0; -} - -THSpriteSheet::~THSpriteSheet() -{ - _freeSprites(); -} - -void THSpriteSheet::_freeSprites() -{ - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - glDeleteTextures(1, &m_pSprites[i].iTexture); - glDeleteTextures(1, &m_pSprites[i].iAltTexture); - if(m_pSprites[i].pData) - delete[] m_pSprites[i].pData; - } - delete[] m_pSprites; - m_pSprites = NULL; - m_iSpriteCount = 0; - glDeleteTextures(1, &m_iMegaTexture); - m_iMegaTexture = 0; - m_iMegaTextureSize = 0; -} - -void THSpriteSheet::setPalette(const THPalette* pPalette) -{ - m_pPalette = pPalette; -} - -bool THSpriteSheet::loadFromTHFile( - const unsigned char* pTableData, size_t iTableDataLength, - const unsigned char* pChunkData, size_t iChunkDataLength, - bool bComplexChunks, THRenderTarget* pCanvas) -{ - _freeSprites(); - if(pCanvas == NULL) - return false; - - m_iSpriteCount = (unsigned int)(iTableDataLength / sizeof(th_sprite_t)); - m_pSprites = new (std::nothrow) sprite_t[m_iSpriteCount]; - if(m_pSprites == NULL) - { - m_iSpriteCount = 0; - return false; - } - m_pTarget = pCanvas; - - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - sprite_t *pSprite = m_pSprites + i; - const th_sprite_t *pTHSprite = reinterpret_cast(pTableData) + i; - - pSprite->iTexture = 0; - pSprite->iAltTexture = 0; - pSprite->pData = NULL; - pSprite->pAltPaletteMap = NULL; - pSprite->iWidth = pTHSprite->width; - pSprite->iHeight = pTHSprite->height; - pSprite->iWidth2 = roundUp2(pSprite->iWidth); - pSprite->iHeight2 = roundUp2(pSprite->iHeight); - - if(pSprite->iWidth == 0 || pSprite->iHeight == 0) - continue; - - { - unsigned char *pData = new unsigned char[pSprite->iWidth * pSprite->iHeight]; - THChunkRenderer oRenderer(pSprite->iWidth, pSprite->iHeight, pData); - int iDataLen = static_cast(iChunkDataLength) - static_cast(pTHSprite->position); - if(iDataLen < 0) - iDataLen = 0; - oRenderer.decodeChunks(pChunkData + pTHSprite->position, iDataLen, bComplexChunks); - pSprite->pData = oRenderer.takeData(); - } - } - - sprite_t **ppSortedSprites = new sprite_t*[m_iSpriteCount]; - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - ppSortedSprites[i] = m_pSprites + i; - } - qsort(ppSortedSprites, m_iSpriteCount, sizeof(sprite_t*), _sortSpritesHeight); - - unsigned int iSize; - if(_tryFitSingleTex(ppSortedSprites, 2048)) - { - iSize = 2048; - if(_tryFitSingleTex(ppSortedSprites, 1024)) - { - iSize = 1024; - if(_tryFitSingleTex(ppSortedSprites, 512)) - { - iSize = 512; - if(_tryFitSingleTex(ppSortedSprites, 256)) - { - iSize = 256; - if(_tryFitSingleTex(ppSortedSprites, 128)) - iSize = 128; - } - } - } - } - else - { - delete[] ppSortedSprites; - return true; - } - - _makeSingleTex(ppSortedSprites, iSize); - delete[] ppSortedSprites; - return true; -} - -int THSpriteSheet::_sortSpritesHeight(const void* left, const void* right) -{ - const sprite_t *pLeft = *reinterpret_cast(left); - const sprite_t *pRight = *reinterpret_cast(right); - - // Move all NULL datas to the end - if(pLeft->pData == NULL || pRight->pData == NULL) - { - if(pLeft->pData == NULL && pRight->pData == NULL) - return 0; - if(pLeft->pData == NULL) - return 1; - else - return -1; - } - - // Sort from tallest to shortest - return static_cast(pRight->iHeight) - static_cast(pLeft->iHeight); -} - -bool THSpriteSheet::_tryFitSingleTex(sprite_t** ppSortedSprites, unsigned int iSize) -{ - // There are probably better algorithms for trying to fit lots of small - // rectangular sprites onto a single square sheet, but sorting them by - // height and then filling up one row at a time is simple and yields a good - // enough result. - - unsigned int iX = 0; - unsigned int iY = 0; - unsigned int iTallest = ppSortedSprites[0]->iHeight; - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - sprite_t *pSprite = ppSortedSprites[i]; - if(pSprite->pData == NULL) - break; - if(pSprite->iWidth > iSize || pSprite->iHeight > iSize) - return false; - if(iX + pSprite->iWidth > iSize) - { - iX = 0; - iY += iTallest; - iTallest = pSprite->iHeight; - } - iX += pSprite->iWidth; - } - - iY += iTallest; - return iY <= iSize; -} - -void THSpriteSheet::_makeSingleTex(sprite_t** ppSortedSprites, unsigned int iSize) -{ - uint32_t *pData = new (std::nothrow) uint32_t[iSize * iSize]; - if(pData == NULL) - return; - - // Pass 1: Fill entirely transparent - uint32_t* pRow = pData; - uint32_t iTransparent = THPalette::packARGB(0x00, 0x00, 0x00, 0x00); - for(unsigned int y = 0; y < iSize; ++y) - { - for(unsigned int x = 0; x < iSize; ++x, ++pRow) - { - *pRow = iTransparent; - } - } - - // Pass 2: Blit sprites onto sheet - const uint32_t* pColours = m_pPalette->getARGBData(); - unsigned int iX = 0; - unsigned int iY = 0; - unsigned int iTallest = ppSortedSprites[0]->iHeight; - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - sprite_t *pSprite = ppSortedSprites[i]; - if(pSprite->pData == NULL) - break; - - pSprite->iTexture = m_iMegaTexture; - if(iX + pSprite->iWidth > iSize) - { - iX = 0; - iY += iTallest; - iTallest = pSprite->iHeight; - } - pSprite->iSheetX = iX; - pSprite->iSheetY = iY; - iX += pSprite->iWidth; - - const unsigned char *pPixels = pSprite->pData; - pRow = pData + pSprite->iSheetY * iSize + pSprite->iSheetX; - for(unsigned int y = 0; y < pSprite->iHeight; ++y) - { - for(unsigned int x = 0; x < pSprite->iWidth; ++x, ++pRow, ++pPixels) - { - *pRow = pColours[*pPixels]; - } - } - } - - m_iMegaTexture = m_pTarget->createTexture(iSize, iSize, pData); - delete[] pData; - if(m_iMegaTexture != 0) - m_iMegaTextureSize = iSize; -} - -void THSpriteSheet::setSpriteAltPaletteMap(unsigned int iSprite, const unsigned char* pMap) -{ - if(iSprite >= m_iSpriteCount) - return; - - sprite_t *pSprite = m_pSprites + iSprite; - if(pSprite->pAltPaletteMap != pMap) - { - pSprite->pAltPaletteMap = pMap; - if(pSprite->iAltTexture) - { - glDeleteTextures(1, &pSprite->iAltTexture); - pSprite->iAltTexture = 0; - } - } -} - -unsigned int THSpriteSheet::getSpriteCount() const -{ - return m_iSpriteCount; -} - -bool THSpriteSheet::getSpriteSize(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const -{ - if(iSprite >= m_iSpriteCount) - return false; - if(pX != NULL) - *pX = m_pSprites[iSprite].iWidth; - if(pY != NULL) - *pY = m_pSprites[iSprite].iHeight; - return true; -} - -void THSpriteSheet::getSpriteSizeUnchecked(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const -{ - *pX = m_pSprites[iSprite].iWidth; - *pY = m_pSprites[iSprite].iHeight; -} - -bool THSpriteSheet::getSpriteAverageColour(unsigned int iSprite, THColour* pColour) const -{ - if(iSprite >= m_iSpriteCount) - return false; - const sprite_t *pSprite = m_pSprites + iSprite; - int iCountTotal = 0; - int iUsageCounts[256] = {0}; - for(unsigned int i = 0; i < pSprite->iWidth * pSprite->iHeight; ++i) - { - unsigned char cPalIndex = pSprite->pData[i]; - uint32_t iColour = m_pPalette->getARGBData()[cPalIndex]; - if((iColour >> 24) == 0) - continue; - // Grant higher score to pixels with high or low intensity (helps avoid grey fonts) - unsigned char iR = static_cast ((iColour >> 0) & 0xFF); - unsigned char iG = static_cast ((iColour >> 8) & 0xFF); - unsigned char iB = static_cast ((iColour >> 16) & 0xFF); - unsigned char cIntensity = (unsigned char)(((int)iR + (int)iG + (int)iB) / 3); - int iScore = 1 + max(0, 3 - ((255 - cIntensity) / 32)) + max(0, 3 - (cIntensity / 32)); - iUsageCounts[cPalIndex] += iScore; - iCountTotal += iScore; - } - if(iCountTotal == 0) - return false; - int iHighestCountIndex = 0; - for(int i = 0; i < 256; ++i) - { - if(iUsageCounts[i] > iUsageCounts[iHighestCountIndex]) - iHighestCountIndex = i; - } - *pColour = m_pPalette->getARGBData()[iHighestCountIndex]; - return true; -} - -void THSpriteSheet::drawSprite(THRenderTarget* pCanvas, unsigned int iSprite, int iX, int iY, unsigned long iFlags) -{ - if(iSprite >= m_iSpriteCount || pCanvas == NULL || pCanvas != m_pTarget) - return; - sprite_t *pSprite = m_pSprites + iSprite; - - // Find or create the texture - GLuint iTexture = pSprite->iTexture; - if(iTexture == 0) - { - if(pSprite->pData == NULL) - return; - - iTexture = m_pTarget->createTexture(pSprite->iWidth, pSprite->iHeight, - pSprite->pData, m_pPalette); - pSprite->iTexture = iTexture; - } - if(iFlags & THDF_AltPalette) - { - iTexture = pSprite->iAltTexture; - if(iTexture == 0) - { - iTexture = _makeAltBitmap(pSprite); - if(iTexture == 0) - return; - } - } - - if(iTexture == m_iMegaTexture) - { - pCanvas->draw(iTexture, m_pSprites[iSprite].iWidth, - m_pSprites[iSprite].iHeight, iX, iY, iFlags, m_iMegaTextureSize, - m_iMegaTextureSize, m_pSprites[iSprite].iSheetX, - m_pSprites[iSprite].iSheetY); - } - else - { - pCanvas->draw(iTexture, m_pSprites[iSprite].iWidth, - m_pSprites[iSprite].iHeight, iX, iY, iFlags, - m_pSprites[iSprite].iWidth2, m_pSprites[iSprite].iHeight2, 0, 0); - } -} - -void THSpriteSheet::wxDrawSprite(unsigned int iSprite, unsigned char* pRGBData, unsigned char* pAData) -{ - if(iSprite >= m_iSpriteCount || pRGBData == NULL || pAData == NULL) - return; - sprite_t *pSprite = m_pSprites + iSprite; - const uint32_t* pColours = m_pPalette->getARGBData(); - - const unsigned char *pPixels = pSprite->pData; - for(unsigned int y = 0; y < pSprite->iHeight; ++y) - { - for(unsigned int x = 0; x < pSprite->iWidth; ++x, ++pPixels, ++pAData, pRGBData += 3) - { - pRGBData[0] = (pColours[*pPixels] >> 0) & 0xFF; - pRGBData[1] = (pColours[*pPixels] >> 8) & 0xFF; - pRGBData[2] = (pColours[*pPixels] >> 16) & 0xFF; - pAData [0] = (pColours[*pPixels] >> 24) & 0xFF; - } - } -} - -GLuint THSpriteSheet::_makeAltBitmap(sprite_t *pSprite) -{ - int iPixelCount = pSprite->iHeight * pSprite->iWidth; - unsigned char *pData = new unsigned char[iPixelCount]; - for(int i = 0; i < iPixelCount; ++i) - { - unsigned char iPixel = pSprite->pData[i]; - if(iPixel != 0xFF && pSprite->pAltPaletteMap) - iPixel = pSprite->pAltPaletteMap[iPixel]; - pData[i] = iPixel; - } - pSprite->iAltTexture = m_pTarget->createTexture(pSprite->iWidth, - pSprite->iHeight, pData, m_pPalette); - delete[] pData; - return pSprite->iAltTexture; -} - -bool THSpriteSheet::hitTestSprite(unsigned int iSprite, int iX, int iY, unsigned long iFlags) const -{ - if(iX < 0 || iY < 0 || iSprite >= m_iSpriteCount) - return false; - int iWidth = m_pSprites[iSprite].iWidth; - int iHeight = m_pSprites[iSprite].iHeight; - if(iX >= iWidth || iY >= iHeight) - return false; - if(iFlags & THDF_FlipHorizontal) - iX = iWidth - iX - 1; - if(iFlags & THDF_FlipVertical) - iY = iHeight - iY - 1; - return (m_pPalette->getARGBData() - [m_pSprites[iSprite].pData[iY * iWidth + iX]] >> 24) != 0; -} - -THCursor::THCursor() -{ - // TODO (low priority, as Lua will simulate a cursor) -} - -THCursor::~THCursor() -{ - // TODO (low priority, as Lua will simulate a cursor) -} - -bool THCursor::createFromSprite(THSpriteSheet* pSheet, unsigned int iSprite, - int iHotspotX, int iHotspotY) -{ - // TODO (low priority, as Lua will simulate a cursor) - return false; -} - -void THCursor::use(THRenderTarget* pTarget) -{ - // TODO (low priority, as Lua will simulate a cursor) -} - -bool THCursor::setPosition(THRenderTarget* pTarget, int iX, int iY) -{ - // TODO (low priority, as Lua will simulate a cursor) - return false; -} - -THLine::THLine() -{ - initialize(); -} - -THLine::~THLine() -{ - THLineOperation* op = m_pFirstOp; - while (op) { - THLineOperation* next = (THLineOperation*)(op->m_pNext); - delete(op); - op = next; - } -} - -void THLine::initialize() -{ - m_fWidth = 1; - m_iR = 0; - m_iG = 0; - m_iB = 0; - m_iA = 255; - - // We start at 0,0 - m_pFirstOp = new THLineOperation(THLOP_MOVE, 0, 0); - m_pCurrentOp = m_pFirstOp; -} - -void THLine::moveTo(double fX, double fY) -{ - THLineOperation* previous = m_pCurrentOp; - m_pCurrentOp = new THLineOperation(THLOP_MOVE, fX, fY); - previous->m_pNext = m_pCurrentOp; -} - -void THLine::lineTo(double fX, double fY) -{ - THLineOperation* previous = m_pCurrentOp; - m_pCurrentOp = new THLineOperation(THLOP_LINE, fX, fY); - previous->m_pNext = m_pCurrentOp; -} - -void THLine::setWidth(double pLineWidth) -{ - m_fWidth = pLineWidth; -} - -void THLine::setColour(uint8_t iR, uint8_t iG, uint8_t iB, uint8_t iA) -{ - m_iR = iR; - m_iG = iG; - m_iB = iB; - m_iA = iA; -} - -void THLine::draw(THRenderTarget* pCanvas, int iX, int iY) -{ - pCanvas->flushSprites(); // Without this the lines are draw behind sprites/textures - - // Strangely drawing at 0,0 would draw outside of the screen - // so we start at 1,0. This makes OpenGl behave like DirectX. - iX++; - - glDisable(GL_TEXTURE_2D); - glColor4ub(m_iR, m_iG, m_iB, m_iA); - glLineWidth(m_fWidth); - - double lastX, lastY; - lastX = m_pFirstOp->m_fX; - lastY = m_pFirstOp->m_fY; - - THLineOperation* op = (THLineOperation*)(m_pFirstOp->m_pNext); - while (op) { - if (op->type == THLOP_LINE) { - glBegin(GL_LINES); - glVertex3f(lastX + iX, lastY + iY, 0.0f); - glVertex3f(op->m_fX + iX, op->m_fY + iY, 0.0f); - glEnd(); - } - - lastX = op->m_fX; - lastY = op->m_fY; - - op = (THLineOperation*)(op->m_pNext); - } - glEnable(GL_TEXTURE_2D); -} - -void THLine::persist(LuaPersistWriter *pWriter) const -{ - pWriter->writeVUInt((uint32_t)m_iR); - pWriter->writeVUInt((uint32_t)m_iG); - pWriter->writeVUInt((uint32_t)m_iB); - pWriter->writeVUInt((uint32_t)m_iA); - pWriter->writeVFloat(m_fWidth); - - THLineOperation* op = (THLineOperation*)(m_pFirstOp->m_pNext); - uint32_t numOps = 0; - for (; op; numOps++) { - op = (THLineOperation*)(op->m_pNext); - } - - pWriter->writeVUInt(numOps); - - op = (THLineOperation*)(m_pFirstOp->m_pNext); - while (op) { - pWriter->writeVUInt((uint32_t)op->type); - pWriter->writeVFloat(op->m_fX); - pWriter->writeVFloat(op->m_fY); - - op = (THLineOperation*)(op->m_pNext); - } -} - -void THLine::depersist(LuaPersistReader *pReader) -{ - initialize(); - - pReader->readVUInt(m_iR); - pReader->readVUInt(m_iG); - pReader->readVUInt(m_iB); - pReader->readVUInt(m_iA); - pReader->readVFloat(m_fWidth); - - uint32_t numOps = 0; - pReader->readVUInt(numOps); - for (uint32_t i = 0; i < numOps; i++) { - THLineOpType type; - double fX, fY; - pReader->readVUInt((uint32_t&)type); - pReader->readVFloat(fX); - pReader->readVFloat(fY); - - if (type == THLOP_MOVE) { - moveTo(fX, fY); - } else if (type == THLOP_LINE) { - lineTo(fX, fY); - } - } -} - -#ifdef CORSIX_TH_USE_FREETYPE2 -bool THFreeTypeFont::_isMonochrome() const -{ - return false; -} - -void THFreeTypeFont::_setNullTexture(cached_text_t* pCacheEntry) const -{ - pCacheEntry->iTexture = 0; -} - -void THFreeTypeFont::_freeTexture(cached_text_t* pCacheEntry) const -{ - if(pCacheEntry->iTexture != 0) - { - GLuint iTexture = static_cast(pCacheEntry->iTexture); - glDeleteTextures(1, &iTexture); - } -} - -void THFreeTypeFont::_makeTexture(cached_text_t* pCacheEntry) const -{ - int iWidth2 = roundUp2(pCacheEntry->iWidth); - int iHeight2 = roundUp2(pCacheEntry->iHeight); - uint32_t* pPixels = new uint32_t[iWidth2 * iHeight2]; - memset(pPixels, 0, iWidth2 * iHeight2 * sizeof(uint32_t)); - unsigned char* pInRow = pCacheEntry->pData; - uint32_t* pOutRow = pPixels; - uint32_t iColBase = m_oColour & 0xFFFFFF; - for(int iY = 0; iY < pCacheEntry->iHeight; ++iY, pOutRow += iWidth2, - pInRow += pCacheEntry->iWidth) - { - for(int iX = 0; iX < pCacheEntry->iWidth; ++iX) - { - pOutRow[iX] = (static_cast(pInRow[iX]) << 24) | iColBase; - } - } - pCacheEntry->iTexture = static_cast(THRenderTarget::createTexture(iWidth2, iHeight2, pPixels)); - delete[] pPixels; -} - -void THFreeTypeFont::_drawTexture(THRenderTarget* pCanvas, cached_text_t* pCacheEntry, int iX, int iY) const -{ - if(pCacheEntry->iTexture == 0) - return; - - pCanvas->draw(static_cast(pCacheEntry->iTexture), - pCacheEntry->iWidth, pCacheEntry->iHeight, iX, iY, 0, - roundUp2(pCacheEntry->iWidth), roundUp2(pCacheEntry->iHeight), 0, 0); - // As the cache entry might get re-used, flush sprites now. - pCanvas->flushSprites(); -} -#endif // CORSIX_TH_USE_FREETYPE2 - -#endif // CORSIX_TH_USE_OGL_RENDERER diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx_ogl.h corsix-th-0.62/CorsixTH/Src/th_gfx_ogl.h --- corsix-th-0.30/CorsixTH/Src/th_gfx_ogl.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx_ogl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,345 +0,0 @@ -/* -Copyright (c) 2009-2013 Peter "Corsix" Cawley and Edvin "Lego3" Linge - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef CORSIX_TH_TH_GFX_OGL_H_ -#define CORSIX_TH_TH_GFX_OGL_H_ -#include "config.h" -#ifdef CORSIX_TH_USE_OGL_RENDERER -#ifdef CORSIX_TH_HAS_RENDERING_ENGINE -#error More than one rendering engine enabled in config file -#endif -#define CORSIX_TH_HAS_RENDERING_ENGINE -#ifdef _WIN32 -#ifndef CORSIX_TH_USE_WIN32_SDK -#error Windows Platform SDK usage must be enabled to use OGL renderer on Win32 -#endif -#include -#endif -#include -#ifdef CORSIX_TH_USE_OGL_RENDER_TO_TEXTURE -#define GL_GLEXT_PROTOTYPES -#else -#define NO_SDL_GLEXT -#endif - -#include -#include "persist_lua.h" - -//Darrell: The wxWindows OGL includes can stop these from being defined in -//SDL_opengl.h so as a temporary solution I'm defining them here. -#ifdef __APPLE__ -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); -#endif - -class THCursor; -struct THRenderTargetCreationParams; - -struct THClipRect -{ - typedef int16_t xy_t; - typedef uint16_t wh_t; - xy_t x, y; - wh_t w, h; -}; - -struct THOGL_Vertex -{ - float u, v; - uint32_t colour; - float x, y, z; - // The texture is not part of the GL vertex, but is included with the - // vertex data to make it simpler to sort verticies by texture. - GLuint tex; -}; - -typedef uint32_t THColour; - -class THPalette -{ -public: // External API - THPalette(); - - bool loadFromTHFile(const unsigned char* pData, size_t iDataLength); - bool setEntry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB); - -public: // Internal (this rendering engine only) API - inline static uint32_t packARGB(uint8_t iA, uint8_t iR, uint8_t iG, uint8_t iB) - { - return (static_cast(iR) << 0) | - (static_cast(iG) << 8) | - (static_cast(iB) << 16) | - (static_cast(iA) << 24) ; - } - int getColourCount() const; - const uint32_t* getARGBData() const; - -protected: - uint32_t m_aColoursARGB[256]; - int m_iNumColours; -}; - -class THRenderTarget -{ -public: // External API - THRenderTarget(); - ~THRenderTarget(); - - bool create(const THRenderTargetCreationParams* pParams); - const char* getLastError(); - - bool startFrame(); - bool endFrame(); - bool fillBlack(); - void setBlueFilterActive(bool bActivate); - uint32_t mapColour(uint8_t iR, uint8_t iG, uint8_t iB); - bool fillRect(uint32_t iColour, int iX, int iY, int iW, int iH); - void getClipRect(THClipRect* pRect) const; - int getWidth() const; - int getHeight() const; - void setClipRect(const THClipRect* pRect); - void startNonOverlapping(); - void finishNonOverlapping(); - void setCursor(THCursor* pCursor); - void setCursorPosition(int iX, int iY); - bool takeScreenshot(const char* sFile); - bool setScaleFactor(float fScale, THScaledItems eWhatToScale); - // If you add any extra methods here which are called from outside the - // rendering engine, then be sure to at least add dummy implementations - // to the other rendering engines. - -public: // Internal (this rendering engine only) API - THOGL_Vertex* allocVerticies(size_t iCount, GLuint iTexture); - void draw(GLuint iTexture, unsigned int iWidth, unsigned int iHeight, - int iX, int iY, unsigned long iFlags, unsigned int iWidth2, - unsigned int iHeight2, unsigned int iTexX, unsigned int iTexY); - bool flushSprites(); - GLuint createTexture(int iWidth, int iHeight, const unsigned char* pPixels, - const THPalette* pPalette, int* pWidth2 = NULL, - int* pHeight2 = NULL); - static GLuint createTexture(int iWidth2, int iHeight2, const uint32_t* pPixels); - static GLenum getGLError(); - static void setGLProjection(GLdouble fWidth, GLdouble fHeight); - bool shouldScaleBitmaps(float* pFactor); - -protected: - SDL_Surface* m_pSurface; - THOGL_Vertex *m_pVerticies; -#ifdef CORSIX_TH_USE_OGL_RENDER_TO_TEXTURE - PFNGLGENFRAMEBUFFERSEXTPROC m_glGenFramebuffersEXT; - PFNGLBINDFRAMEBUFFEREXTPROC m_glBindFramebufferEXT; - PFNGLFRAMEBUFFERTEXTURE2DEXTPROC m_glFramebufferTexture2DEXT; - PFNGLDELETEFRAMEBUFFERSEXTPROC m_glDeleteFramebuffersEXT; - PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC m_glCheckFramebufferStatusEXT; - float m_fZoomScale; - GLuint m_iZoomTexture; - GLuint m_iZoomFrameBuffer; - int m_iZoomTextureSize; - bool m_bUsingZoomBuffer; -#endif - - THClipRect m_rcClip; - float m_fBitmapScaleFactor; - size_t m_iVertexCount; - size_t m_iVertexLength; - size_t m_iNonOverlappingStart; - int m_iNonOverlapping; - int m_iWidth; - int m_iHeight; - bool m_bShouldScaleBitmaps; - - bool m_bBlueFilterActive; - - void _drawVerts(size_t iFirst, size_t iLast); - void _flushZoomBuffer(); -}; - -class THRawBitmap -{ -public: // External API - THRawBitmap(); - ~THRawBitmap(); - - void setPalette(const THPalette* pPalette); - - bool loadFromTHFile(const unsigned char* pPixelData, size_t iPixelDataLength, - int iWidth, THRenderTarget *pEventualCanvas); - - void draw(THRenderTarget* pCanvas, int iX, int iY); - void draw(THRenderTarget* pCanvas, int iX, int iY, int iSrcX, int iSrcY, - int iWidth, int iHeight); - -protected: - GLuint m_iTexture; - const THPalette* m_pPalette; - THRenderTarget* m_pTarget; - int m_iWidth; - int m_iWidth2; - int m_iHeight; - int m_iHeight2; -}; - -class THSpriteSheet -{ -public: // External API - THSpriteSheet(); - ~THSpriteSheet(); - - void setPalette(const THPalette* pPalette); - - bool loadFromTHFile(const unsigned char* pTableData, size_t iTableDataLength, - const unsigned char* pChunkData, size_t iChunkDataLength, - bool bComplexChunks, THRenderTarget* pEventualCanvas); - - void setSpriteAltPaletteMap(unsigned int iSprite, const unsigned char* pMap); - - unsigned int getSpriteCount() const; - bool getSpriteSize(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const; - void getSpriteSizeUnchecked(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const; - - bool getSpriteAverageColour(unsigned int iSprite, THColour* pColour) const; - - void drawSprite(THRenderTarget* pCanvas, unsigned int iSprite, int iX, int iY, unsigned long iFlags); - bool hitTestSprite(unsigned int iSprite, int iX, int iY, unsigned long iFlags) const; - -public: // Internal (this rendering engine only) API - //! Draw a sprite into wxImage data arrays (for the Map Editor) - void wxDrawSprite(unsigned int iSprite, unsigned char* pRGBData, unsigned char* pAData); - -protected: - friend class THCursor; -#if CORSIX_TH_USE_PACK_PRAGMAS -#pragma pack(push) -#pragma pack(1) -#endif - struct th_sprite_t - { - uint32_t position; - unsigned char width; - unsigned char height; - } CORSIX_TH_PACKED_FLAGS; -#if CORSIX_TH_USE_PACK_PRAGMAS -#pragma pack(pop) -#endif - - struct sprite_t - { - GLuint iTexture; - GLuint iAltTexture; - unsigned char *pData; - const unsigned char *pAltPaletteMap; - unsigned int iSheetX; - unsigned int iSheetY; - unsigned int iWidth; - unsigned int iHeight; - unsigned int iWidth2; - unsigned int iHeight2; - } *m_pSprites; - const THPalette* m_pPalette; - THRenderTarget* m_pTarget; - GLuint m_iMegaTexture; - unsigned int m_iMegaTextureSize; - unsigned int m_iSpriteCount; - - void _freeSprites(); - bool _tryFitSingleTex(sprite_t** ppSortedSprites, unsigned int iSize); - void _makeSingleTex(sprite_t** ppSortedSprites, unsigned int iSize); - GLuint _makeAltBitmap(sprite_t *pSprite); - static int _sortSpritesHeight(const void*, const void*); -}; - -class THCursor -{ -public: // External API - THCursor(); - ~THCursor(); - - bool createFromSprite(THSpriteSheet* pSheet, unsigned int iSprite, - int iHotspotX = 0, int iHotspotY = 0); - - void use(THRenderTarget* pTarget); - - static bool setPosition(THRenderTarget* pTarget, int iX, int iY); - -protected: - friend class THRenderTarget; -}; - -class THLine -{ -public: - THLine(); - ~THLine(); - - void moveTo(double fX, double fY); - - void lineTo(double fX, double fY); - - void setWidth(double lineWidth); - - void draw(THRenderTarget* pCanvas, int iX, int iY); - - void setColour(uint8_t iR, uint8_t iG, uint8_t iB, uint8_t iA = 255); - - void persist(LuaPersistWriter *pWriter) const; - void depersist(LuaPersistReader *pReader); - -protected: - void initialize(); - - enum THLineOpType { - THLOP_MOVE, - THLOP_LINE - }; - - struct THLineOperation : public THLinkList - { - THLineOpType type; - double m_fX, m_fY; - THLineOperation(THLineOpType type, double m_fX, double m_fY) : type(type), m_fX(m_fX), m_fY(m_fY) { - m_pNext = NULL; - } - }; - - THLineOperation* m_pFirstOp; - THLineOperation* m_pCurrentOp; - double m_fWidth; - uint8_t m_iR, m_iG, m_iB, m_iA; -}; - -#endif // CORSIX_TH_USE_OGL_RENDERER -#endif // CORSIX_TH_TH_GFX_OGL_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx_sdl.cpp corsix-th-0.62/CorsixTH/Src/th_gfx_sdl.cpp --- corsix-th-0.30/CorsixTH/Src/th_gfx_sdl.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx_sdl.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -21,621 +21,1104 @@ */ #include "config.h" -#ifdef CORSIX_TH_USE_SDL_RENDERER + #include "th_gfx.h" #ifdef CORSIX_TH_USE_FREETYPE2 #include "th_gfx_font.h" #endif #include "th_map.h" -#include "agg_rendering_buffer.h" -#include "agg_pixfmt_rgb.h" -#include "agg_pixfmt_rgba.h" -#include "agg_renderer_base.h" -#include "agg_span_interpolator_linear.h" -#include "agg_span_image_filter_rgb.h" -#include "agg_scanline_p.h" -#include "agg_renderer_scanline.h" -#include "agg_span_allocator.h" -#include "agg_rasterizer_scanline_aa.h" -#include "agg_conv_stroke.h" -#include "agg_vcgen_stroke.cpp" #include -#ifndef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#endif +#include +#include +#include +#include + +full_colour_renderer::full_colour_renderer(int iWidth, int iHeight) : width(iWidth), height(iHeight) +{ + x = 0; + y = 0; +} + +//! Convert a colour to an equivalent grey scale level. +/*! + @param iOpacity Opacity of the pixel. + @param iR Red colour intensity. + @param iG Green colour intensity. + @param iB Blue colour intensity. + @return 32bpp colour pixel in grey scale. + */ +static inline uint32_t makeGreyScale(uint8_t iOpacity, uint8_t iR, uint8_t iG, uint8_t iB) +{ + // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale + // 0.2126*R + 0.7152*G + 0.0722*B + // 0.2126 * 65536 = 13932.9536 -> 1393 + // 0.7152 * 65536 = 46871.3472 + // 0.0722 * 65536 = 4731.6992 -> 4732 + // 13933 + 46871 + 4732 = 65536 = 2**16 + uint8_t iGrey = static_cast((13933 * iR + 46871 * iG + 4732 * iB) >> 16); + return palette::pack_argb(iOpacity, iGrey, iGrey, iGrey); +} + +//! Convert a colour by swapping red and blue channel. +/*! + @param iOpacity Opacity of the pixel. + @param iR Red colour intensity. + @param iG Green colour intensity. + @param iB Blue colour intensity. + @return 32bpp colour pixel with red and blue swapped. + */ +static inline uint32_t makeSwapRedBlue(uint8_t iOpacity, uint8_t iR, uint8_t iG, uint8_t iB) +{ + // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale + // The Y factor for red is 0.2126, and for blue 0.0722. This means red is about 3 times stronger than blue. + // Simple swapping channels will thus distort the balance. This code compensates for that by computing + // red = blue * 0.0722 / 0.2126 = blue * 1083 / 3189 + // blue = red * 0.2126 / 0.0722 = red * 1063 / 361 (clipped at max blue, 255) + uint8_t iNewRed = static_cast(iB * 1083 / 3189); + int iNewBlue = iR * 1063 / 361; + if (iNewBlue > 255) + iNewBlue = 255; + return palette::pack_argb(iOpacity, iNewRed, iG, static_cast(iNewBlue)); +} + +bool full_colour_renderer::decode_image(const uint8_t* pImg, const palette *pPalette, uint32_t iSpriteFlags) +{ + if (width <= 0 || height <= 0) + return false; + + iSpriteFlags &= thdf_alt32_mask; + + const uint32_t* pColours = pPalette->get_argb_data(); + for (;;) { + uint8_t iType = *pImg++; + size_t iLength = iType & 63; + switch (iType >> 6) + { + case 0: // Fixed fully opaque 32bpp pixels + while (iLength > 0) + { + uint32_t iColour; + if (iSpriteFlags == thdf_alt32_blue_red_swap) + iColour = makeSwapRedBlue(0xFF, pImg[0], pImg[1], pImg[2]); + else if (iSpriteFlags == thdf_alt32_grey_scale) + iColour = makeGreyScale(0xFF, pImg[0], pImg[1], pImg[2]); + else + iColour = palette::pack_argb(0xFF, pImg[0], pImg[1], pImg[2]); + push_pixel(iColour); + pImg += 3; + iLength--; + } + break; + + case 1: // Fixed partially transparent 32bpp pixels + { + uint8_t iOpacity = *pImg++; + while (iLength > 0) + { + uint32_t iColour; + if (iSpriteFlags == thdf_alt32_blue_red_swap) + iColour = makeSwapRedBlue(0xFF, pImg[0], pImg[1], pImg[2]); + else if (iSpriteFlags == thdf_alt32_grey_scale) + iColour = makeGreyScale(iOpacity, pImg[0], pImg[1], pImg[2]); + else + iColour = palette::pack_argb(iOpacity, pImg[0], pImg[1], pImg[2]); + push_pixel(iColour); + pImg += 3; + iLength--; + } + break; + } + + case 2: // Fixed fully transparent pixels + { + static const uint32_t iTransparent = palette::pack_argb(0, 0, 0, 0); + while (iLength > 0) + { + push_pixel(iTransparent); + iLength--; + } + break; + } + + case 3: // Recolour layer + { + uint8_t iTable = *pImg++; + pImg++; // Skip reading the opacity for now. + if (iTable == 0xFF) + { + // Legacy sprite data. Use the palette to recolour the layer. + // Note that the iOpacity is ignored here. + while (iLength > 0) + { + push_pixel(pColours[*pImg++]); + iLength--; + } + } + else + { + // TODO: Add proper recolour layers, where RGB comes from + // table 'iTable' at index *pImg (iLength times), and + // opacity comes from the byte after the iTable byte. + // + // For now just draw black pixels, so it won't go unnoticed. + while (iLength > 0) + { + uint32_t iColour = palette::pack_argb(0xFF, 0, 0, 0); + push_pixel(iColour); + iLength--; + } + } + break; + } + } -THRenderTarget::THRenderTarget() + if (y >= height) + break; + } + return x == 0; +} + +full_colour_storing::full_colour_storing(uint32_t *pDest, int iWidth, int iHeight) : full_colour_renderer(iWidth, iHeight) { - m_pSurface = NULL; - m_pDummySurface = NULL; - m_pCursor = NULL; - m_bShouldScaleBitmaps = false; + destination = pDest; } -THRenderTarget::~THRenderTarget() +void full_colour_storing::store_argb(uint32_t pixel) { + *destination++ = pixel; } -bool THRenderTarget::create(const THRenderTargetCreationParams* pParams) +wx_storing::wx_storing(uint8_t* pRGBData, uint8_t* pAData, int iWidth, int iHeight) : full_colour_renderer(iWidth, iHeight) { - if(m_pSurface != NULL) - return false; - m_pSurface = SDL_SetVideoMode(pParams->iWidth, pParams->iHeight, - pParams->iBPP, pParams->iSDLFlags); + rgb_data = pRGBData; + alpha_data = pAData; +} - // Create another surface that's simply blue. This is used as an overlay - // when the game is paused to create a blue filter. - m_bBlueFilterActive = false; - const SDL_PixelFormat& fmt = *(m_pSurface->format); - m_pDummySurface = SDL_CreateRGBSurface(SDL_HWSURFACE, pParams->iWidth, pParams->iHeight, - fmt.BitsPerPixel, fmt.Rmask,fmt.Gmask,fmt.Bmask,fmt.Amask ); - SDL_FillRect(m_pDummySurface, NULL, mapColour(50, 50, 200)); - SDL_SetAlpha(m_pDummySurface, SDL_SRCALPHA, 128); +void wx_storing::store_argb(uint32_t pixel) +{ + rgb_data[0] = palette::get_red(pixel); + rgb_data[1] = palette::get_green(pixel); + rgb_data[2] = palette::get_blue(pixel); + rgb_data += 3; - return m_pSurface != NULL; + *alpha_data++ = palette::get_alpha(pixel); } -bool THRenderTarget::setScaleFactor(float fScale, THScaledItems eWhatToScale) +render_target::render_target() { - m_bShouldScaleBitmaps = false; - if(0.999 <= fScale && fScale <= 1.001) - return true; + window = nullptr; + renderer = nullptr; + pixel_format = nullptr; + game_cursor = nullptr; + zoom_texture = nullptr; + scale_bitmaps = false; + blue_filter_active = false; + apply_opengl_clip_fix = false; + width = -1; + height = -1; +} - if(eWhatToScale & ~THSI_Bitmaps) +render_target::~render_target() +{ + destroy(); +} + +bool render_target::create(const render_target_creation_params* pParams) +{ + if (renderer != nullptr) return false; - if(((eWhatToScale & THSI_Bitmaps) != 0) && (fScale != 1.0)) + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888); + window = SDL_CreateWindow("CorsixTH", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + pParams->width, pParams->height, + SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); + if (!window) { - m_bShouldScaleBitmaps = true; - m_fBitmapScaleFactor = fScale; + return false; } - return true; + + Uint32 iRendererFlags = (pParams->present_immediate ? 0 : SDL_RENDERER_PRESENTVSYNC); + renderer = SDL_CreateRenderer(window, -1, iRendererFlags); + + SDL_RendererInfo info; + SDL_GetRendererInfo(renderer, &info); + supports_target_textures = (info.flags & SDL_RENDERER_TARGETTEXTURE) != 0; + + SDL_version sdlVersion; + SDL_GetVersion(&sdlVersion); + apply_opengl_clip_fix = std::strncmp(info.name, "opengl", 6) == 0 && sdlVersion.major == 2 && sdlVersion.minor == 0 && sdlVersion.patch < 4; + + return update(pParams); } -bool THRenderTarget::shouldScaleBitmaps(float* pFactor) +bool render_target::update(const render_target_creation_params* pParams) { - if(!m_bShouldScaleBitmaps) + if (window == nullptr) + { return false; - if(pFactor) - *pFactor = m_fBitmapScaleFactor; + } + + bool bUpdateSize = (width != pParams->width) || (height != pParams->height); + width = pParams->width; + height = pParams->height; + + bool bIsFullscreen = ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP); + if (bIsFullscreen != pParams->fullscreen) + { + SDL_SetWindowFullscreen(window, (pParams->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)); + } + + if (bUpdateSize || bIsFullscreen != pParams->fullscreen) + { + SDL_SetWindowSize(window, width, height); + } + + if (bUpdateSize) + { + SDL_RenderSetLogicalSize(renderer, width, height); + } + return true; } -const char* THRenderTarget::getLastError() +void render_target::destroy() +{ + if (pixel_format) + { + SDL_FreeFormat(pixel_format); + pixel_format = nullptr; + } + + if (zoom_texture) + { + SDL_DestroyTexture(zoom_texture); + zoom_texture = nullptr; + } + + if (renderer) + { + SDL_DestroyRenderer(renderer); + renderer = nullptr; + } + + if (window) + { + SDL_DestroyWindow(window); + window = nullptr; + } +} + +bool render_target::set_scale_factor(double fScale, scaled_items eWhatToScale) +{ + flush_zoom_buffer(); + scale_bitmaps = false; + + if(fScale <= 0.000) + { + return false; + } + else if(eWhatToScale == scaled_items::all && supports_target_textures) + { + //Draw everything from now until the next scale to zoom_texture + //with the appropriate virtual size, which will be copied scaled to + //fit the window. + int virtWidth = static_cast(width / fScale); + int virtHeight = static_cast(height / fScale); + + zoom_texture = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_ABGR8888, + SDL_TEXTUREACCESS_TARGET, + virtWidth, + virtHeight + ); + + SDL_RenderSetLogicalSize(renderer, virtWidth, virtHeight); + if(SDL_SetRenderTarget(renderer, zoom_texture) != 0) + { + std::cout << "Warning: Could not render to zoom texture - " << SDL_GetError() << std::endl; + + SDL_RenderSetLogicalSize(renderer, width, height); + SDL_DestroyTexture(zoom_texture); + zoom_texture = nullptr; + return false; + } + + // Clear the new texture to transparent/black. + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_TRANSPARENT); + SDL_RenderClear(renderer); + + return true; + } + else if(0.999 <= fScale && fScale <= 1.001) + { + return true; + } + else if(eWhatToScale == scaled_items::bitmaps) + { + scale_bitmaps = true; + bitmap_scale_factor = fScale; + + return true; + } + else + { + return false; + } +} + +void render_target::set_caption(const char* sCaption) +{ + SDL_SetWindowTitle(window, sCaption); +} + +const char *render_target::get_renderer_details() const +{ + SDL_RendererInfo info = {}; + SDL_GetRendererInfo(renderer, &info); + return info.name; +} + +const char* render_target::get_last_error() { return SDL_GetError(); } -bool THRenderTarget::startFrame() +bool render_target::start_frame() { + fill_black(); return true; } -bool THRenderTarget::endFrame() +bool render_target::end_frame() { + flush_zoom_buffer(); + // End the frame by adding the cursor and possibly a filter. - if(m_pCursor) + if(game_cursor) { - m_pCursor->draw(this, m_iCursorX, m_iCursorY); + game_cursor->draw(this, cursor_x, cursor_y); } - if(m_bBlueFilterActive) + if(blue_filter_active) { - SDL_BlitSurface(m_pDummySurface, NULL, this->getRawSurface(), NULL); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, 51, 51, 255, 128); // r=0.2, g=0.2, b=1, a=0.5 . + SDL_RenderFillRect(renderer, nullptr); } - return SDL_Flip(m_pSurface) == 0; + + SDL_RenderPresent(renderer); + return true; } -bool THRenderTarget::fillBlack() +bool render_target::fill_black() { - return SDL_FillRect(m_pSurface, NULL, mapColour(0, 0, 0)) == 0; + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); + + return true; } -void THRenderTarget::setBlueFilterActive(bool bActivate) +void render_target::set_blue_filter_active(bool bActivate) { - m_bBlueFilterActive = bActivate; + blue_filter_active = bActivate; } -uint32_t THRenderTarget::mapColour(uint8_t iR, uint8_t iG, uint8_t iB) +// Actiate and Deactivate SDL function to capture mouse to window +void render_target::set_window_grab(bool bActivate) { - return SDL_MapRGB(m_pSurface->format, iR, iG, iB); + SDL_SetWindowGrab(window, bActivate ? SDL_TRUE : SDL_FALSE); } -bool THRenderTarget::fillRect(uint32_t iColour, int iX, int iY, int iW, int iH) +uint32_t render_target::map_colour(uint8_t iR, uint8_t iG, uint8_t iB) { - SDL_Rect rcDest; - rcDest.x = iX; - rcDest.y = iY; - rcDest.w = iW; - rcDest.h = iH; - return SDL_FillRect(m_pSurface, &rcDest, iColour) == 0; + return palette::pack_argb(0xFF, iR, iG, iB); } -void THRenderTarget::getClipRect(THClipRect* pRect) const +bool render_target::fill_rect(uint32_t iColour, int iX, int iY, int iW, int iH) { - SDL_GetClipRect(m_pSurface, reinterpret_cast(pRect)); + SDL_Rect rcDest = { iX, iY, iW, iH }; + + Uint8 r, g, b, a; + SDL_GetRGBA(iColour, pixel_format, &r, &g, &b, &a); + + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, r, g, b, a); + SDL_RenderFillRect(renderer, &rcDest); + + return true; } -int THRenderTarget::getWidth() const +void render_target::get_clip_rect(clip_rect* pRect) const { - return static_cast(m_pSurface->w); + SDL_RenderGetClipRect(renderer, reinterpret_cast(pRect)); + // SDL returns empty rect when clipping is disabled -> return full rect for CTH + if (SDL_RectEmpty(pRect)) + { + pRect->x = pRect->y = 0; + pRect->w = width; + pRect->h = height; + } + + if(apply_opengl_clip_fix) + { + int renderWidth, renderHeight; + SDL_RenderGetLogicalSize(renderer, &renderWidth, &renderHeight); + pRect->y = renderHeight - pRect->y - pRect->h; + } } -int THRenderTarget::getHeight() const +void render_target::set_clip_rect(const clip_rect* pRect) { - return static_cast(m_pSurface->h); + // Full clip rect for CTH means clipping disabled + if (pRect == nullptr || (pRect->w == width && pRect->h == height)) + { + SDL_RenderSetClipRect(renderer, nullptr); + return; + } + + SDL_Rect SDLRect = { + pRect->x, + pRect->y, + pRect->w, + pRect->h + }; + + // For some reason, SDL treats an empty rect (h or w <= 0) as if you turned + // off clipping, so we replace it with a rect that's outside our viewport. + const SDL_Rect rcBogus = { -2, -2, 1, 1 }; + if (SDL_RectEmpty(&SDLRect)) + { + SDLRect = rcBogus; + } + + if(apply_opengl_clip_fix) + { + int renderWidth, renderHeight; + SDL_RenderGetLogicalSize(renderer, &renderWidth, &renderHeight); + SDLRect.y = renderHeight - SDLRect.y - SDLRect.h; + } + + SDL_RenderSetClipRect(renderer, &SDLRect); } -void THRenderTarget::setClipRect(const THClipRect* pRect) +int render_target::get_width() const { - SDL_SetClipRect(m_pSurface, reinterpret_cast(pRect)); + int w; + SDL_RenderGetLogicalSize(renderer, &w, nullptr); + return w; } -void THRenderTarget::startNonOverlapping() +int render_target::get_height() const { - // SDL has no optimisations for drawing lots of non-overlapping sprites + int h; + SDL_RenderGetLogicalSize(renderer, nullptr, &h); + return h; } -void THRenderTarget::finishNonOverlapping() +void render_target::start_nonoverlapping_draws() { // SDL has no optimisations for drawing lots of non-overlapping sprites } -void THRenderTarget::setCursor(THCursor* pCursor) +void render_target::finish_nonoverlapping_draws() { - m_pCursor = pCursor; + // SDL has no optimisations for drawing lots of non-overlapping sprites } -void THRenderTarget::setCursorPosition(int iX, int iY) +void render_target::set_cursor(cursor* pCursor) { - m_iCursorX = iX; - m_iCursorY = iY; + game_cursor = pCursor; } -bool THRenderTarget::takeScreenshot(const char* sFile) +void render_target::set_cursor_position(int iX, int iY) { - return SDL_SaveBMP(m_pSurface, sFile) == 0; + cursor_x = iX; + cursor_y = iY; } -THPalette::THPalette() +bool render_target::take_screenshot(const char* sFile) { - m_iNumColours = 0; - m_iTransparentIndex = -1; -} - -static const unsigned char gs_iTHColourLUT[0x40] = { - // Maps 0-63 to 0-255 - 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, - 0x20, 0x24, 0x28, 0x2D, 0x31, 0x35, 0x39, 0x3D, - 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, - 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, - 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, - 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, - 0xC2, 0xC6, 0xCA, 0xCE, 0xD2, 0xD7, 0xDB, 0xDF, - 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF, -}; + int width = 0, height = 0; + if (SDL_GetRendererOutputSize(renderer, &width, &height) == -1) + return false; -bool THPalette::loadFromTHFile(const unsigned char* pData, size_t iDataLength) -{ - if(iDataLength != 256 * 3) + // Create a window-sized surface, RGB format (0 Rmask means RGB.) + SDL_Surface* pRgbSurface = SDL_CreateRGBSurface(0, width, height, 24, 0, 0, 0, 0); + if (pRgbSurface == nullptr) return false; - m_iNumColours = static_cast(iDataLength) / 3; - m_iTransparentIndex = -1; - colour_t* pColour = m_aColours; - for(int i = 0; i < m_iNumColours; ++i, pData += 3, ++pColour) - { - pColour->r = gs_iTHColourLUT[pData[0] & 0x3F]; - pColour->g = gs_iTHColourLUT[pData[1] & 0x3F]; - pColour->b = gs_iTHColourLUT[pData[2] & 0x3F]; - if(pColour->r == 0xFF && pColour->g == 0 && pColour->b == 0xFF) - m_iTransparentIndex = i; - pColour->unused = 0; + int readStatus = -1; + if (SDL_LockSurface(pRgbSurface) != -1) + { + // Ask the renderer to (slowly) fill the surface with renderer + // output data. + readStatus = SDL_RenderReadPixels(renderer, + nullptr, + pRgbSurface->format->format, + pRgbSurface->pixels, + pRgbSurface->pitch); + SDL_UnlockSurface(pRgbSurface); + + if (readStatus != -1) + SDL_SaveBMP(pRgbSurface, sFile); } - return true; + SDL_FreeSurface(pRgbSurface); + + return (readStatus != -1); } -bool THPalette::setEntry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB) + +bool render_target::should_scale_bitmaps(double* pFactor) { - if(iEntry < 0 || iEntry >= m_iNumColours) + if(!scale_bitmaps) return false; - colour_t* pColour = m_aColours + iEntry; - pColour->r = iR; - pColour->g = iG; - pColour->b = iB; - if(iR == 0xFF && iG == 0 && iB == 0xFF) - m_iTransparentIndex = iEntry; + if(pFactor) + *pFactor = bitmap_scale_factor; return true; } -void THPalette::_assign(THRenderTarget* pTarget) const +void render_target::flush_zoom_buffer() { - _assign(pTarget->getRawSurface()); + if(zoom_texture == nullptr) { return; } + + SDL_SetRenderTarget(renderer, nullptr); + SDL_RenderSetLogicalSize(renderer, width, height); + SDL_SetTextureBlendMode(zoom_texture, SDL_BLENDMODE_BLEND); + SDL_RenderCopy(renderer, zoom_texture, nullptr, nullptr); + SDL_DestroyTexture(zoom_texture); + zoom_texture = nullptr; } -void THPalette::_assign(SDL_Surface *pSurface) const +//! Convert legacy 8bpp sprite data to recoloured 32bpp data, using special recolour table 0xFF. +/*! + @param pPixelData Legacy 8bpp pixels. + @param iPixelDataLength Number of pixels in the \a pPixelData. + @return Converted 32bpp pixel data, if succeeded else nullptr is returned. Caller should free the returned memory. + */ +static uint8_t *convertLegacySprite(const uint8_t* pPixelData, size_t iPixelDataLength) { - SDL_SetPalette(pSurface, SDL_PHYSPAL | SDL_LOGPAL, - const_cast(m_aColours), 0, m_iNumColours); - if(m_iTransparentIndex != -1) + // Recolour blocks are 63 pixels long. + // XXX To reduce the size of the 32bpp data, transparent pixels can be stored more compactly. + size_t iNumFilled = iPixelDataLength / 63; + size_t iRemaining = iPixelDataLength - iNumFilled * 63; + size_t iNewSize = iNumFilled * (3 + 63) + ((iRemaining > 0) ? 3 + iRemaining : 0); + + uint8_t *pData = new (std::nothrow) uint8_t[iNewSize]; + if (pData == nullptr) + return nullptr; + + uint8_t *pDest = pData; + while (iPixelDataLength > 0) { - SDL_SetColorKey(pSurface, SDL_SRCCOLORKEY | SDL_RLEACCEL, - static_cast(m_iTransparentIndex)); + size_t iLength = (iPixelDataLength >= 63) ? 63 : iPixelDataLength; + *pDest++ = static_cast(iLength + 0xC0); // Recolour layer type of block. + *pDest++ = 0xFF; // Use special table 0xFF (which uses the palette as table). + *pDest++ = 0xFF; // Non-transparent. + std::memcpy(pDest, pPixelData, iLength); + pDest += iLength; + pPixelData += iLength; + iPixelDataLength -= iLength; } - else - SDL_SetColorKey(pSurface, 0, 0); + return pData; } -THRawBitmap::THRawBitmap() +SDL_Texture* render_target::create_palettized_texture( + int iWidth, int iHeight, const uint8_t* pPixels, + const palette* pPalette, uint32_t iSpriteFlags) const { - m_pBitmap = NULL; - m_pCachedScaledBitmap = NULL; - m_pPalette = NULL; - m_pData = NULL; -} + uint32_t *pARGBPixels = new (std::nothrow) uint32_t[iWidth * iHeight]; + if(pARGBPixels == nullptr) + return 0; -THRawBitmap::~THRawBitmap() -{ - SDL_FreeSurface(m_pBitmap); - SDL_FreeSurface(m_pCachedScaledBitmap); - delete[] m_pData; -} + full_colour_storing oRenderer(pARGBPixels, iWidth, iHeight); + bool bOk = oRenderer.decode_image(pPixels, pPalette, iSpriteFlags); + if (!bOk) + return 0; -void THRawBitmap::setPalette(const THPalette* pPalette) -{ - m_pPalette = pPalette; + SDL_Texture *pTexture = create_texture(iWidth, iHeight, pARGBPixels); + delete [] pARGBPixels; + return pTexture; } -template -class image_accessor_clip_rgb24_pal8 +SDL_Texture* render_target::create_texture(int iWidth, int iHeight, + const uint32_t* pPixels) const { -public: - typedef PixFmt pixfmt_type; - typedef typename pixfmt_type::color_type color_type; - typedef typename pixfmt_type::order_type order_type; - typedef typename pixfmt_type::value_type value_type; - enum pix_width_e { pix_width = pixfmt_type::pix_width }; + SDL_Texture *pTexture = SDL_CreateTexture(renderer, pixel_format->format, SDL_TEXTUREACCESS_STATIC, iWidth, iHeight); + SDL_UpdateTexture(pTexture, nullptr, pPixels, static_cast(sizeof(*pPixels) * iWidth)); + SDL_SetTextureBlendMode(pTexture, SDL_BLENDMODE_BLEND); + SDL_SetTextureColorMod(pTexture, 0xFF, 0xFF, 0xFF); + SDL_SetTextureAlphaMod(pTexture, 0xFF); - typedef agg::rendering_buffer palbuf_type; - typedef THPalette pal_type; - typedef pal_type::colour_t palcol_type; + return pTexture; +} - image_accessor_clip_rgb24_pal8() {} - explicit image_accessor_clip_rgb24_pal8(const palbuf_type& buf, - const pal_type& pal, - const color_type& bk) : - m_pixf(&buf), m_pal(&pal) +void render_target::draw(SDL_Texture *pTexture, const SDL_Rect *prcSrcRect, const SDL_Rect *prcDstRect, int iFlags) +{ + SDL_SetTextureAlphaMod(pTexture, 0xFF); + if (iFlags & thdf_alpha_50) { - pixfmt_type::make_pix(m_bk_buf, bk); + SDL_SetTextureAlphaMod(pTexture, 0x80); } - - void background_color(const color_type& bk) + else if (iFlags & thdf_alpha_75) { - pixfmt_type::make_pix(m_bk_buf, bk); + SDL_SetTextureAlphaMod(pTexture, 0x40); } -private: - AGG_INLINE const agg::int8u* pixel() - { - if(m_y >= 0 && m_y < (int)m_pixf->height() && - m_x >= 0 && m_x < (int)m_pixf->width()) - { - palcol_type c = (*m_pal)[m_pixf->row_ptr(m_y)[m_x]]; - m_fg_buf[order_type::R] = c.r; - m_fg_buf[order_type::G] = c.g; - m_fg_buf[order_type::B] = c.b; - return m_fg_buf; - } - return m_bk_buf; - } + int iSDLFlip = SDL_FLIP_NONE; + if(iFlags & thdf_flip_horizontal) + iSDLFlip |= SDL_FLIP_HORIZONTAL; + if (iFlags & thdf_flip_vertical) + iSDLFlip |= SDL_FLIP_VERTICAL; -public: - AGG_INLINE const agg::int8u* span(int x, int y, unsigned len) - { - m_x = m_x0 = x; - m_y = y; - return pixel(); + if (iSDLFlip != 0) { + SDL_RenderCopyEx(renderer, pTexture, prcSrcRect, prcDstRect, 0, nullptr, (SDL_RendererFlip)iSDLFlip); + } else { + SDL_RenderCopy(renderer, pTexture, prcSrcRect, prcDstRect); } +} - AGG_INLINE const agg::int8u* next_x() - { - ++m_x; - return pixel(); - } - AGG_INLINE const agg::int8u* next_y() - { - ++m_y; - m_x = m_x0; - return pixel(); +void render_target::draw_line(line *pLine, int iX, int iY) +{ + SDL_SetRenderDrawColor(renderer, pLine->red, pLine->green, pLine->blue, pLine->alpha); + + double lastX, lastY; + lastX = pLine->first_operation->x; + lastY = pLine->first_operation->y; + + line::line_operation* op = (line::line_operation*)(pLine->first_operation->next); + while (op) { + if (op->type == line::line_operation_type::line) { + SDL_RenderDrawLine(renderer, static_cast(lastX + iX), + static_cast(lastY + iY), + static_cast(op->x + iX), + static_cast(op->y + iY)); + } + + lastX = op->x; + lastY = op->y; + + op = (line::line_operation*)(op->next); } +} + +palette::palette() +{ + colour_count = 0; +} -private: - const palbuf_type* m_pixf; - const pal_type* m_pal; - agg::int8u m_bk_buf[4]; - agg::int8u m_fg_buf[4]; - int m_x, m_x0, m_y; +static const uint8_t gs_iTHColourLUT[0x40] = { + // Maps 0-63 to 0-255 + 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, + 0x20, 0x24, 0x28, 0x2D, 0x31, 0x35, 0x39, 0x3D, + 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, + 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, + 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, + 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, + 0xC2, 0xC6, 0xCA, 0xCE, 0xD2, 0xD7, 0xDB, 0xDF, + 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF, }; -class rasterizer_scanline_rect +bool palette::load_from_th_file(const uint8_t* pData, size_t iDataLength) { -public: - rasterizer_scanline_rect(int x, int y, unsigned int width, unsigned int height) + if(iDataLength != 256 * 3) + return false; + + colour_count = static_cast(iDataLength / 3); + for(int i = 0; i < colour_count; ++i, pData += 3) { - m_x = x; - m_y = y; - m_width = width; - m_height = height; + uint8_t iR = gs_iTHColourLUT[pData[0] & 0x3F]; + uint8_t iG = gs_iTHColourLUT[pData[1] & 0x3F]; + uint8_t iB = gs_iTHColourLUT[pData[2] & 0x3F]; + uint32_t iColour = pack_argb(0xFF, iR, iG, iB); + // Remap magenta to transparent + if(iColour == pack_argb(0xFF, 0xFF, 0x00, 0xFF)) + iColour = pack_argb(0x00, 0x00, 0x00, 0x00); + colour_index_to_argb_map[i] = iColour; } - bool rewind_scanlines() - { - if(m_width > 0 && m_height > 0) - { - m_ycurr = m_y - 1; - return true; - } + return true; +} + +bool palette::set_entry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB) +{ + if(iEntry < 0 || iEntry >= colour_count) return false; - } + uint32_t iColour = pack_argb(0xFF, iR, iG, iB); + // Remap magenta to transparent + if(iColour == pack_argb(0xFF, 0xFF, 0x00, 0xFF)) + iColour = pack_argb(0x00, 0x00, 0x00, 0x00); + colour_index_to_argb_map[iEntry] = iColour; + return true; +} - int min_x() - { - return m_x; - } +int palette::get_colour_count() const +{ + return colour_count; +} - int max_x() - { - return m_x + m_width - 1; - } +const uint32_t* palette::get_argb_data() const +{ + return colour_index_to_argb_map; +} - template bool sweep_scanline(Scanline& sl) +raw_bitmap::raw_bitmap() +{ + texture = nullptr; + bitmap_palette = nullptr; + target = nullptr; + width = 0; + height = 0; +} + +raw_bitmap::~raw_bitmap() +{ + if (texture) { - if(static_cast(++m_ycurr) >= static_cast(m_y + m_height)) - return false; - sl.reset_spans(); - sl.add_span(m_x, m_width, agg::cover_full); - sl.finalize(m_ycurr); - return true; + SDL_DestroyTexture(texture); } +} -protected: - int m_x, m_y; - unsigned int m_width, m_height; - int m_ycurr; -}; +void raw_bitmap::set_palette(const palette* pPalette) +{ + bitmap_palette = pPalette; +} -bool THRawBitmap::loadFromTHFile(const unsigned char* pPixelData, - size_t iPixelDataLength, - int iWidth, THRenderTarget *pUnused) +bool raw_bitmap::load_from_th_file(const uint8_t* pPixelData, + size_t iPixelDataLength, int iWidth, + render_target *pEventualCanvas) { - if(m_pPalette == NULL) + if(pEventualCanvas == nullptr) return false; - SDL_FreeSurface(m_pBitmap); - m_pBitmap = NULL; - delete[] m_pData; - m_pData = NULL; - - m_pData = new (std::nothrow) unsigned char[iPixelDataLength]; - if(m_pData == NULL) + uint8_t* converted_sprite = convertLegacySprite(pPixelData, iPixelDataLength); + if (converted_sprite == nullptr) return false; - memcpy(m_pData, pPixelData, iPixelDataLength); int iHeight = static_cast(iPixelDataLength) / iWidth; + texture = pEventualCanvas->create_palettized_texture(iWidth, iHeight, converted_sprite, bitmap_palette, thdf_alt32_plain); + delete[] converted_sprite; - m_pBitmap = SDL_CreateRGBSurfaceFrom(m_pData, iWidth, iHeight, 8, iWidth, 0, 0, 0, 0); - if(m_pBitmap == NULL) + if(!texture) return false; - m_pPalette->_assign(m_pBitmap); + width = iWidth; + height = iHeight; + target = pEventualCanvas; return true; } -bool THRawBitmap::_checkScaled(THRenderTarget* pCanvas, SDL_Rect& rcDest) +/** + * Test whether the loaded full colour sprite loads correctly. + * @param pData Data of the sprite. + * @param iDataLength Length of the sprite data. + * @param iWidth Width of the sprite. + * @param iHeight Height of the sprite. + * @return Whether the sprite loads correctly (at the end of the sprite, all data is used). + */ +static bool testSprite(const uint8_t* pData, size_t iDataLength, int iWidth, int iHeight) { - float fFactor; - if(!pCanvas->shouldScaleBitmaps(&fFactor)) - return false; - int iScaledWidth = (int)((float)m_pBitmap->w * fFactor); - if(!m_pCachedScaledBitmap || m_pCachedScaledBitmap->w != iScaledWidth) - { - SDL_FreeSurface(m_pCachedScaledBitmap); - Uint32 iRMask, iGMask, iBMask; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - iRMask = 0xff000000; - iGMask = 0x00ff0000; - iBMask = 0x0000ff00; -#else - iRMask = 0x000000ff; - iGMask = 0x0000ff00; - iBMask = 0x00ff0000; -#endif + if (iWidth <= 0 || iHeight <= 0) + return true; - m_pCachedScaledBitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, iScaledWidth, (int)((float)m_pBitmap->h * fFactor), 24, iRMask, iGMask, iBMask, 0); - SDL_LockSurface(m_pCachedScaledBitmap); - SDL_LockSurface(m_pBitmap); - - typedef agg::pixfmt_rgb24_pre pixfmt_pre_t; - typedef agg::renderer_base renbase_pre_t; - typedef image_accessor_clip_rgb24_pal8 imgsrc_t; - typedef agg::span_interpolator_linear<> interpolator_t; - typedef agg::span_image_filter_rgb_2x2 span_gen_type; - agg::scanline_p8 sl; - agg::span_allocator sa; - agg::image_filter filter; - agg::trans_affine_scaling img_mtx(1.0 / fFactor); - agg::rendering_buffer rbuf_src(m_pData, m_pBitmap->w, m_pBitmap->h, m_pBitmap->pitch); - imgsrc_t img_src(rbuf_src, *m_pPalette, agg::rgba(0.0, 0.0, 0.0)); - interpolator_t interpolator(img_mtx); - span_gen_type sg(img_src, interpolator, filter); - agg::rendering_buffer rbuf(reinterpret_cast(m_pCachedScaledBitmap->pixels), m_pCachedScaledBitmap->w, m_pCachedScaledBitmap->h, m_pCachedScaledBitmap->pitch); - pixfmt_pre_t pixf_pre(rbuf); - renbase_pre_t rbase_pre(pixf_pre); - rasterizer_scanline_rect ras(0, 0, rbuf.width(), rbuf.height()); - rbase_pre.clear(agg::rgba(1.0,0,0,0)); - agg::render_scanlines_aa(ras, sl, rbase_pre, sa, sg); + size_t iCount = iWidth * iHeight; + while (iCount > 0) + { + if (iDataLength < 1) + return false; + iDataLength--; + uint8_t iType = *pData++; - SDL_UnlockSurface(m_pBitmap); - SDL_UnlockSurface(m_pCachedScaledBitmap); + size_t iLength = iType & 63; + switch (iType >> 6) + { + case 0: // Fixed fully opaque 32bpp pixels + if (iCount < iLength || iDataLength < iLength * 3) + return false; + iCount -= iLength; + iDataLength -= iLength * 3; + pData += iLength * 3; + break; + + case 1: // Fixed partially transparent 32bpp pixels + if (iDataLength < 1) + return false; + iDataLength--; + pData++; // Opacity byte. + + if (iCount < iLength || iDataLength < iLength * 3) + return false; + iCount -= iLength; + iDataLength -= iLength * 3; + pData += iLength * 3; + break; + + case 2: // Fixed fully transparent pixels + if (iCount < iLength) + return false; + iCount -= iLength; + break; + + case 3: // Recolour layer + if (iDataLength < 2) + return false; + iDataLength -= 2; + pData += 2; // Table number, opacity byte. + + if (iCount < iLength || iDataLength < iLength) + return false; + iCount -= iLength; + iDataLength -= iLength; + pData += iLength; + break; + } } - rcDest.x = (Sint16)((float)rcDest.x * fFactor); - rcDest.y = (Sint16)((float)rcDest.y * fFactor); - return true; + return iDataLength == 0; } -void THRawBitmap::draw(THRenderTarget* pCanvas, int iX, int iY) +void raw_bitmap::draw(render_target* pCanvas, int iX, int iY) { - if(m_pBitmap == NULL) - return; - - SDL_Rect rcDest; - rcDest.x = iX; - rcDest.y = iY; - SDL_BlitSurface(_checkScaled(pCanvas, rcDest) ? m_pCachedScaledBitmap : - m_pBitmap, NULL, pCanvas->getRawSurface(), &rcDest); + draw(pCanvas, iX, iY, 0, 0, width, height); } -void THRawBitmap::draw(THRenderTarget* pCanvas, int iX, int iY, - int iSrcX, int iSrcY, int iWidth, int iHeight) +void raw_bitmap::draw(render_target* pCanvas, int iX, int iY, + int iSrcX, int iSrcY, int iWidth, int iHeight) { - if(m_pBitmap == NULL) + double fScaleFactor; + if (texture == nullptr) return; - SDL_Rect rcSrc; - rcSrc.x = iSrcX; - rcSrc.y = iSrcY; - rcSrc.w = iWidth; - rcSrc.h = iHeight; - SDL_Rect rcDest; - rcDest.x = iX; - rcDest.y = iY; - SDL_BlitSurface(_checkScaled(pCanvas, rcDest) ? m_pCachedScaledBitmap : - m_pBitmap, &rcSrc, pCanvas->getRawSurface(), &rcDest); + if(!pCanvas->should_scale_bitmaps(&fScaleFactor)) + { + fScaleFactor = 1; + } + + const SDL_Rect rcSrc = { iSrcX, iSrcY, iWidth, iHeight }; + const SDL_Rect rcDest = { iX, + iY, + static_cast(iWidth * fScaleFactor), + static_cast(iHeight * fScaleFactor) }; + + pCanvas->draw(texture, &rcSrc, &rcDest, 0); } -THSpriteSheet::THSpriteSheet() +sprite_sheet::sprite_sheet() { - m_pSprites = NULL; - m_pPalette = NULL; - m_iSpriteCount = 0; - m_bHasAnyFlaggedBitmaps = false; + sprites = nullptr; + palette = nullptr; + target = nullptr; + sprite_count = 0; } -THSpriteSheet::~THSpriteSheet() +sprite_sheet::~sprite_sheet() { _freeSprites(); } -void THSpriteSheet::_freeSprites() +void sprite_sheet::_freeSingleSprite(size_t iNumber) { - if(m_bHasAnyFlaggedBitmaps) + if (iNumber >= sprite_count) + return; + + if (sprites[iNumber].texture != nullptr) { - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - for(unsigned int j = 0; j < 32; ++j) - SDL_FreeSurface(m_pSprites[i].pBitmap[j]); - delete[] m_pSprites[i].pData; - } + SDL_DestroyTexture(sprites[iNumber].texture); + sprites[iNumber].texture = nullptr; } - else + if (sprites[iNumber].alt_texture != nullptr) { - for(unsigned int i = 0; i < m_iSpriteCount; ++i) - { - SDL_FreeSurface(m_pSprites[i].pBitmap[0]); - delete[] m_pSprites[i].pData; - } + SDL_DestroyTexture(sprites[iNumber].alt_texture); + sprites[iNumber].alt_texture = nullptr; + } + if(sprites[iNumber].data != nullptr) + { + delete[] sprites[iNumber].data; + sprites[iNumber].data = nullptr; } - delete[] m_pSprites; - m_pSprites = NULL; - m_iSpriteCount = 0; - m_bHasAnyFlaggedBitmaps = false; } -void THSpriteSheet::setPalette(const THPalette* pPalette) +void sprite_sheet::_freeSprites() { - m_pPalette = pPalette; + for(size_t i = 0; i < sprite_count; ++i) + _freeSingleSprite(i); + + delete[] sprites; + sprites = nullptr; + sprite_count = 0; } -bool THSpriteSheet::loadFromTHFile( - const unsigned char* pTableData, size_t iTableDataLength, - const unsigned char* pChunkData, size_t iChunkDataLength, - bool bComplexChunks, THRenderTarget*) +void sprite_sheet::set_palette(const ::palette* pPalette) +{ + palette = pPalette; +} + +bool sprite_sheet::set_sprite_count(size_t iCount, render_target* pCanvas) { _freeSprites(); - m_iSpriteCount = (unsigned int)(iTableDataLength / sizeof(th_sprite_t)); - m_pSprites = new (std::nothrow) sprite_t[m_iSpriteCount]; - if(m_pSprites == NULL) + + if(pCanvas == nullptr) + return false; + target = pCanvas; + + sprite_count = iCount; + sprites = new (std::nothrow) sprite[sprite_count]; + if(sprites == nullptr) { - m_iSpriteCount = 0; + sprite_count = 0; return false; } - for(unsigned int i = 0; i < m_iSpriteCount; ++i) + for (size_t i = 0; i < sprite_count; i++) + { + sprite &spr = sprites[i]; + spr.texture = nullptr; + spr.alt_texture = nullptr; + spr.data = nullptr; + spr.alt_palette_map = nullptr; + spr.sprite_flags = thdf_alt32_plain; + spr.width = 0; + spr.height = 0; + } + + return true; +} + +bool sprite_sheet::load_from_th_file(const uint8_t* pTableData, size_t iTableDataLength, + const uint8_t* pChunkData, size_t iChunkDataLength, + bool bComplexChunks, render_target* pCanvas) +{ + _freeSprites(); + if(pCanvas == nullptr) + return false; + + size_t iCount = iTableDataLength / sizeof(th_sprite_properties); + if (!set_sprite_count(iCount, pCanvas)) + return false; + + for(size_t i = 0; i < sprite_count; ++i) { - sprite_t *pSprite = m_pSprites + i; - const th_sprite_t *pTHSprite = reinterpret_cast(pTableData) + i; - for(unsigned int j = 0; j < 32; ++j) - m_pSprites[i].pBitmap[j] = NULL; - pSprite->pData = NULL; - pSprite->pAltPaletteMap = NULL; - pSprite->iWidth = pTHSprite->width; - pSprite->iHeight = pTHSprite->height; + sprite *pSprite = sprites + i; + const th_sprite_properties *pTHSprite = reinterpret_cast(pTableData) + i; - if(pSprite->iWidth == 0 || pSprite->iHeight == 0) + pSprite->texture = nullptr; + pSprite->alt_texture = nullptr; + pSprite->data = nullptr; + pSprite->alt_palette_map = nullptr; + pSprite->width = pTHSprite->width; + pSprite->height = pTHSprite->height; + + if(pSprite->width == 0 || pSprite->height == 0) continue; { - THChunkRenderer oRenderer(pSprite->iWidth, pSprite->iHeight, NULL); + uint8_t *pData = new uint8_t[pSprite->width * pSprite->height]; + chunk_renderer oRenderer(pSprite->width, pSprite->height, pData); int iDataLen = static_cast(iChunkDataLength) - static_cast(pTHSprite->position); if(iDataLen < 0) iDataLen = 0; - oRenderer.decodeChunks(pChunkData + pTHSprite->position, iDataLen, bComplexChunks); - pSprite->pData = oRenderer.takeData(); + oRenderer.decode_chunks(pChunkData + pTHSprite->position, iDataLen, bComplexChunks); + pData = oRenderer.take_data(); + pSprite->data = convertLegacySprite(pData, pSprite->width * pSprite->height); + delete[] pData; } + } + return true; +} - pSprite->pBitmap[0] = SDL_CreateRGBSurfaceFrom(pSprite->pData, - pSprite->iWidth, pSprite->iHeight, 8, pSprite->iWidth, 0, 0, 0, 0); +bool sprite_sheet::set_sprite_data(size_t iSprite, const uint8_t *pData, bool bTakeData, + size_t iDataLength, int iWidth, int iHeight) +{ + if (iSprite >= sprite_count) + return false; - if(pSprite->pBitmap[0] != NULL) - m_pPalette->_assign(pSprite->pBitmap[0]); + if (!testSprite(pData, iDataLength, iWidth, iHeight)) + { + std::printf("Sprite number %zu has a bad encoding, skipping", iSprite); + return false; + } + + _freeSingleSprite(iSprite); + sprite *pSprite = sprites + iSprite; + if (bTakeData) + { + pSprite->data = pData; } + else + { + uint8_t *pNewData = new (std::nothrow) uint8_t[iDataLength]; + if (pNewData == nullptr) + return false; + std::memcpy(pNewData, pData, iDataLength); + pSprite->data = pNewData; + } + + pSprite->width = iWidth; + pSprite->height = iHeight; return true; } -unsigned int THSpriteSheet::getSpriteCount() const +void sprite_sheet::set_sprite_alt_palette_map(size_t iSprite, const uint8_t* pMap, uint32_t iAlt32) +{ + if(iSprite >= sprite_count) + return; + + sprite *pSprite = sprites + iSprite; + if(pSprite->alt_palette_map != pMap) + { + pSprite->alt_palette_map = pMap; + pSprite->sprite_flags = iAlt32; + if(pSprite->alt_texture) + { + SDL_DestroyTexture(pSprite->alt_texture); + pSprite->alt_texture = nullptr; + } + } +} + +size_t sprite_sheet::get_sprite_count() const { - return m_iSpriteCount; + return sprite_count; } -bool THSpriteSheet::getSpriteSize(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const +bool sprite_sheet::get_sprite_size(size_t iSprite, unsigned int* pWidth, unsigned int* pHeight) const { - if(iSprite >= m_iSpriteCount) + if(iSprite >= sprite_count) return false; - if(pX != NULL) - *pX = m_pSprites[iSprite].iWidth; - if(pY != NULL) - *pY = m_pSprites[iSprite].iHeight; + if(pWidth != nullptr) + *pWidth = sprites[iSprite].width; + if(pHeight != nullptr) + *pHeight = sprites[iSprite].height; return true; } -bool THSpriteSheet::getSpriteAverageColour(unsigned int iSprite, THColour* pColour) const +void sprite_sheet::get_sprite_size_unchecked(size_t iSprite, unsigned int* pWidth, unsigned int* pHeight) const +{ + *pWidth = sprites[iSprite].width; + *pHeight = sprites[iSprite].height; +} + +bool sprite_sheet::get_sprite_average_colour(size_t iSprite, argb_colour* pColour) const { - if(iSprite >= m_iSpriteCount) + if(iSprite >= sprite_count) return false; - const sprite_t *pSprite = m_pSprites + iSprite; + const sprite *pSprite = sprites + iSprite; int iCountTotal = 0; int iUsageCounts[256] = {0}; - for(unsigned int i = 0; i < pSprite->iWidth * pSprite->iHeight; ++i) + for(long i = 0; i < pSprite->width * pSprite->height; ++i) { - unsigned char cPalIndex = pSprite->pData[i]; - if(cPalIndex == m_pPalette->m_iTransparentIndex) + uint8_t cPalIndex = pSprite->data[i]; + uint32_t iColour = palette->get_argb_data()[cPalIndex]; + if((iColour >> 24) == 0) continue; // Grant higher score to pixels with high or low intensity (helps avoid grey fonts) - THColour col = ((*m_pPalette)[cPalIndex]); - unsigned char cIntensity = (unsigned char)(((int)col.r + (int)col.b + (int)col.g) / 3); - int iScore = 1 + max(0, 3 - ((255 - cIntensity) / 32)) + max(0, 3 - (cIntensity / 32)); + int iR = palette::get_red(iColour); + int iG = palette::get_green(iColour); + int iB = palette::get_blue(iColour); + uint8_t cIntensity = static_cast((iR + iG + iB) / 3); + int iScore = 1 + std::max(0, 3 - ((255 - cIntensity) / 32)) + std::max(0, 3 - (cIntensity / 32)); iUsageCounts[cPalIndex] += iScore; iCountTotal += iScore; } @@ -647,438 +1130,433 @@ if(iUsageCounts[i] > iUsageCounts[iHighestCountIndex]) iHighestCountIndex = i; } - *pColour = (*m_pPalette)[iHighestCountIndex]; + *pColour = palette->get_argb_data()[iHighestCountIndex]; return true; } -void THSpriteSheet::getSpriteSizeUnchecked(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const -{ - *pX = m_pSprites[iSprite].iWidth; - *pY = m_pSprites[iSprite].iHeight; -} - -void THSpriteSheet::drawSprite(THRenderTarget* pCanvas, unsigned int iSprite, int iX, int iY, unsigned long iFlags) +void sprite_sheet::draw_sprite(render_target* pCanvas, size_t iSprite, int iX, int iY, uint32_t iFlags) { - if(iSprite >= m_iSpriteCount) + if(iSprite >= sprite_count || pCanvas == nullptr || pCanvas != target) return; + sprite &sprite = sprites[iSprite]; - SDL_Surface *pSprite = _getSpriteBitmap(iSprite, iFlags & 0x1F); - if(pSprite == NULL) - return; + // Find or create the texture + SDL_Texture *pTexture = sprite.texture; + if(!pTexture) + { + if(sprite.data == nullptr) + return; - SDL_Rect rctDest; - rctDest.x = iX; - rctDest.y = iY; - SDL_BlitSurface(pSprite, NULL, pCanvas->getRawSurface(), &rctDest); -} + uint32_t iSprFlags = (sprite.sprite_flags & ~thdf_alt32_mask) | thdf_alt32_plain; + pTexture = target->create_palettized_texture(sprite.width, sprite.height, + sprite.data, palette, iSprFlags); + sprite.texture = pTexture; + } + if(iFlags & thdf_alt_palette) + { + pTexture = sprite.alt_texture; + if(!pTexture) + { + pTexture = _makeAltBitmap(&sprite); + if(!pTexture) + return; + } + } -bool THSpriteSheet::hitTestSprite(unsigned int iSprite, int iX, int iY, unsigned long iFlags) const -{ - if(iX < 0 || iY < 0 || iSprite >= m_iSpriteCount) - return false; - int iWidth = (int)m_pSprites[iSprite].iWidth; - int iHeight = (int)m_pSprites[iSprite].iHeight; - if(iX >= iWidth || iY >= iHeight) - return false; - if(iFlags & THDF_FlipHorizontal) - iX = iWidth - iX - 1; - if(iFlags & THDF_FlipVertical) - iY = iHeight - iY - 1; - return (int)m_pSprites[iSprite].pData[iY * iWidth + iX] != m_pPalette->m_iTransparentIndex; + SDL_Rect rcSrc = { 0, 0, sprite.width, sprite.height }; + SDL_Rect rcDest = { iX, iY, sprite.width, sprite.height }; + + pCanvas->draw(pTexture, &rcSrc, &rcDest, iFlags); } -void THSpriteSheet::setSpriteAltPaletteMap(unsigned int iSprite, const unsigned char* pMap) +void sprite_sheet::wx_draw_sprite(size_t iSprite, uint8_t* pRGBData, uint8_t* pAData) { - if(iSprite >= m_iSpriteCount) + if(iSprite >= sprite_count || pRGBData == nullptr || pAData == nullptr) return; + sprite *pSprite = sprites + iSprite; - sprite_t *pSprite = m_pSprites + iSprite; - if(pSprite->pAltPaletteMap != pMap) - { - pSprite->pAltPaletteMap = pMap; - for(int i = 16; i < 32; ++i) - { - SDL_FreeSurface(pSprite->pBitmap[i]); - pSprite->pBitmap[i] = NULL; - } - } + wx_storing oRenderer(pRGBData, pAData, pSprite->width, pSprite->height); + oRenderer.decode_image(pSprite->data, palette, pSprite->sprite_flags); } -SDL_Surface* THSpriteSheet::_getSpriteBitmap(unsigned int iSprite, unsigned long iFlags) +SDL_Texture* sprite_sheet::_makeAltBitmap(sprite *pSprite) { - SDL_Surface* pBitmap = m_pSprites[iSprite].pBitmap[iFlags]; - if(pBitmap != NULL) - return pBitmap; - if(m_pSprites[iSprite].pData == NULL) - return NULL; - - m_bHasAnyFlaggedBitmaps = true; + const uint32_t *pPalette = palette->get_argb_data(); - THDrawFlags eTask; - SDL_Surface* pBaseBitmap; - if(iFlags & THDF_AltPalette) + if (!pSprite->alt_palette_map) // Use normal palette. { - pBaseBitmap = _getSpriteBitmap(iSprite, iFlags & ~THDF_AltPalette); - eTask = THDF_AltPalette; + uint32_t iSprFlags = (pSprite->sprite_flags & ~thdf_alt32_mask) | thdf_alt32_plain; + pSprite->alt_texture = target->create_palettized_texture(pSprite->width, pSprite->height, + pSprite->data, palette, iSprFlags); } - else if(iFlags & (THDF_Alpha75 | THDF_Alpha50)) + else if (!pPalette) // Draw alternative palette, but no palette set (ie 32bpp image). { - pBaseBitmap = _getSpriteBitmap(iSprite, iFlags & 0x3); - eTask = (iFlags & THDF_Alpha75) ? THDF_Alpha75 : THDF_Alpha50; + pSprite->alt_texture = target->create_palettized_texture(pSprite->width, pSprite->height, + pSprite->data, palette, pSprite->sprite_flags); } - else if(iFlags == (THDF_FlipHorizontal | THDF_FlipVertical)) + else // Paletted image, build recolour palette. { - pBaseBitmap = _getSpriteBitmap(iSprite, THDF_FlipHorizontal); - eTask = THDF_FlipVertical; - } - else // iFlags == THDF_FlipHorizontal or THDF_FlipVertical - { - pBaseBitmap = _getSpriteBitmap(iSprite, 0); - eTask = (THDrawFlags)iFlags; + ::palette oPalette; + for (int iColour = 0; iColour < 255; iColour++) + { + oPalette.set_argb(iColour, pPalette[pSprite->alt_palette_map[iColour]]); + } + oPalette.set_argb(255, pPalette[255]); // Colour 0xFF doesn't get remapped. + + pSprite->alt_texture = target->create_palettized_texture(pSprite->width, pSprite->height, + pSprite->data, &oPalette, pSprite->sprite_flags); } - if(pBaseBitmap == NULL) - return NULL; - pBitmap = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCCOLORKEY, - pBaseBitmap->w, pBaseBitmap->h, 8, 0, 0, 0, 0); - m_pPalette->_assign(pBitmap); + return pSprite->alt_texture; +} - if(eTask == THDF_AltPalette) +/** + * Get the colour data of pixel \a iPixelNumber (\a iWidth * y + x) + * @param pImg 32bpp image data. + * @param iWidth Width of the image. + * @param iHeight Height of the image. + * @param pPalette Palette of the image, or \c nullptr. + * @param iPixelNumber Number of the pixel to retrieve. + */ +static uint32_t get32BppPixel(const uint8_t* pImg, int iWidth, int iHeight, + const ::palette *pPalette, size_t iPixelNumber) +{ + if (iWidth <= 0 || iHeight <= 0 || iPixelNumber < 0 || + iPixelNumber >= static_cast(iWidth) * iHeight) { - SDL_LockSurface(pBitmap); - SDL_LockSurface(pBaseBitmap); - unsigned char *pDestPixels = (unsigned char*)pBitmap->pixels; - const unsigned char *pSrcPixels = (const unsigned char*)pBaseBitmap->pixels; - const unsigned char *pMap = m_pSprites[iSprite].pAltPaletteMap; - for(int iY = 0; iY < pBitmap->h; ++iY) + return palette::pack_argb(0, 0, 0,0); + } + + for (;;) { + uint8_t iType = *pImg++; + size_t iLength = iType & 63; + switch (iType >> 6) { - if(pMap) + case 0: // Fixed fully opaque 32bpp pixels + if (iPixelNumber >= iLength) + { + pImg += 3 * iLength; + iPixelNumber -= iLength; + break; + } + + while (iLength > 0) + { + if (iPixelNumber == 0) + return palette::pack_argb(0xFF, pImg[0], pImg[1], pImg[2]); + + iPixelNumber--; + pImg += 3; + iLength--; + } + break; + + case 1: // Fixed partially transparent 32bpp pixels { - for(int iX = 0; iX < pBitmap->w; ++iX) + uint8_t iOpacity = *pImg++; + if (iPixelNumber >= iLength) { - unsigned char iPixel = pSrcPixels[iX]; - if(iPixel != 0xFF) - iPixel = pMap[iPixel]; - pDestPixels[iX] = iPixel; + pImg += 3 * iLength; + iPixelNumber -= iLength; + break; } - } - else - memcpy(pDestPixels, pSrcPixels, pBitmap->w); - pDestPixels += pBitmap->pitch; - pSrcPixels += pBaseBitmap->pitch; - } - SDL_UnlockSurface(pBaseBitmap); - SDL_UnlockSurface(pBitmap); - } - else if(eTask == THDF_Alpha50 || eTask == THDF_Alpha75) - { - SDL_LockSurface(pBitmap); - SDL_LockSurface(pBaseBitmap); - unsigned char *pDestPixels = (unsigned char*)pBitmap->pixels; - const unsigned char *pSrcPixels = (const unsigned char*)pBaseBitmap->pixels; - for(int iY = 0; iY < pBitmap->h; ++iY) - { - memcpy(pDestPixels, pSrcPixels, pBitmap->w); - pDestPixels += pBitmap->pitch; - pSrcPixels += pBaseBitmap->pitch; - } - SDL_UnlockSurface(pBaseBitmap); - SDL_UnlockSurface(pBitmap); - SDL_SetAlpha(pBitmap, SDL_SRCALPHA | SDL_RLEACCEL, eTask == THDF_Alpha50 ? 128 : 64); - } - else - { - SDL_LockSurface(pBitmap); - SDL_LockSurface(pBaseBitmap); - unsigned char *pDestPixels = (unsigned char*)pBitmap->pixels; - const unsigned char *pSrcPixels = (const unsigned char*)pBaseBitmap->pixels; + while (iLength > 0) + { + if (iPixelNumber == 0) + return palette::pack_argb(iOpacity, pImg[0], pImg[1], pImg[2]); - if(eTask == THDF_FlipHorizontal) - { - for(int iY = 0; iY < pBitmap->h; ++iY) + iPixelNumber--; + pImg += 3; + iLength--; + } + break; + } + + case 2: // Fixed fully transparent pixels { - for(int iX = 0; iX < pBitmap->w; ++iX) + if (iPixelNumber >= iLength) { - pDestPixels[iX] = pSrcPixels[pBitmap->w - iX - 1]; + iPixelNumber -= iLength; + break; } - pDestPixels += pBitmap->pitch; - pSrcPixels += pBaseBitmap->pitch; + + return palette::pack_argb(0, 0, 0, 0); } - } - else - { - pSrcPixels += pBaseBitmap->pitch * (pBaseBitmap->h - 1); - for(int iY = 0; iY < pBitmap->h; ++iY) + + case 3: // Recolour layer { - memcpy(pDestPixels, pSrcPixels, pBitmap->w); - pDestPixels += pBitmap->pitch; - pSrcPixels -= pBaseBitmap->pitch; + uint8_t iTable = *pImg++; + pImg++; // Skip reading the opacity for now. + if (iPixelNumber >= iLength) + { + pImg += iLength; + iPixelNumber -= iLength; + break; + } + + if (iTable == 0xFF && pPalette != nullptr) + { + // Legacy sprite data. Use the palette to recolour the layer. + // Note that the iOpacity is ignored here. + const uint32_t* pColours = pPalette->get_argb_data(); + return pColours[pImg[iPixelNumber]]; + } + else + { + // TODO: Add proper recolour layers, where RGB comes from + // table 'iTable' at index *pImg (iLength times), and + // opacity comes from the byte after the iTable byte. + // + // For now just draw black pixels, so it won't go unnoticed. + return palette::pack_argb(0xFF, 0, 0, 0); + } } } - - SDL_UnlockSurface(pBaseBitmap); - SDL_UnlockSurface(pBitmap); } +} - m_pSprites[iSprite].pBitmap[iFlags] = pBitmap; - return pBitmap; +bool sprite_sheet::hit_test_sprite(size_t iSprite, int iX, int iY, uint32_t iFlags) const +{ + if(iX < 0 || iY < 0 || iSprite >= sprite_count) + return false; + + sprite &sprite = sprites[iSprite]; + int iWidth = sprite.width; + int iHeight = sprite.height; + if(iX >= iWidth || iY >= iHeight) + return false; + if(iFlags & thdf_flip_horizontal) + iX = iWidth - iX - 1; + if(iFlags & thdf_flip_vertical) + iY = iHeight - iY - 1; + + uint32_t iCol = get32BppPixel(sprite.data, iWidth, iHeight, palette, iY * iWidth + iX); + return palette::get_alpha(iCol) != 0; } -THCursor::THCursor() +cursor::cursor() { - m_pBitmap = NULL; - m_iHotspotX = 0; - m_iHotspotY = 0; - m_pCursorHidden = NULL; + bitmap = nullptr; + hotspot_x = 0; + hotspot_y = 0; + hidden_cursor = nullptr; } -THCursor::~THCursor() +cursor::~cursor() { - SDL_FreeSurface(m_pBitmap); - SDL_FreeCursor(m_pCursorHidden); + SDL_FreeSurface(bitmap); + SDL_FreeCursor(hidden_cursor); } -bool THCursor::createFromSprite(THSpriteSheet* pSheet, unsigned int iSprite, +bool cursor::create_from_sprite(sprite_sheet* pSheet, size_t iSprite, int iHotspotX, int iHotspotY) { +#if 0 SDL_FreeSurface(m_pBitmap); - m_pBitmap = NULL; + m_pBitmap = nullptr; - if(pSheet == NULL || iSprite >= pSheet->getSpriteCount()) + if(pSheet == nullptr || iSprite >= pSheet->getSpriteCount()) return false; SDL_Surface *pSprite = pSheet->_getSpriteBitmap(iSprite, 0); - if(pSprite == NULL || (m_pBitmap = SDL_DisplayFormat(pSprite)) == NULL) + if(pSprite == nullptr || (m_pBitmap = SDL_DisplayFormat(pSprite)) == nullptr) return false; m_iHotspotX = iHotspotX; m_iHotspotY = iHotspotY; return true; +#else + return false; +#endif } -void THCursor::use(THRenderTarget* pTarget) +void cursor::use(render_target* pTarget) { +#if 0 //SDL_ShowCursor(0) is buggy in fullscreen until 1.3 (they say) // use transparent cursor for same effect uint8_t uData = 0; m_pCursorHidden = SDL_CreateCursor(&uData, &uData, 8, 1, 0, 0); SDL_SetCursor(m_pCursorHidden); pTarget->setCursor(this); +#endif } -bool THCursor::setPosition(THRenderTarget* pTarget, int iX, int iY) +bool cursor::set_position(render_target* pTarget, int iX, int iY) { +#if 0 pTarget->setCursorPosition(iX, iY); return true; +#else + return false; +#endif } -void THCursor::draw(THRenderTarget* pCanvas, int iX, int iY) +void cursor::draw(render_target* pCanvas, int iX, int iY) { +#if 0 SDL_Rect rcDest; rcDest.x = (Sint16)(iX - m_iHotspotX); rcDest.y = (Sint16)(iY - m_iHotspotY); - SDL_BlitSurface(m_pBitmap, NULL, pCanvas->getRawSurface(), &rcDest); + SDL_BlitSurface(m_pBitmap, nullptr, pCanvas->getRawSurface(), &rcDest); +#endif } -THLine::THLine() +line::line() { initialize(); } -void THLine::initialize() +line::~line() { - m_fWidth = 1; - m_iR = 0; - m_iG = 0; - m_iB = 0; - m_iA = 255; - m_pBitmap = NULL; - m_fMaxX = 0; - m_fMaxY = 0; - m_oPath = new agg::path_storage(); + line_operation* op = first_operation; + while (op) { + line_operation* next = (line_operation*)(op->next); + delete(op); + op = next; + } } -THLine::~THLine() +void line::initialize() { - SDL_FreeSurface(m_pBitmap); - delete(m_oPath); + width = 1; + red = 0; + green = 0; + blue = 0; + alpha = 255; + + // We start at 0,0 + first_operation = new line_operation(line_operation_type::move, 0, 0); + current_operation = first_operation; } -void THLine::moveTo(double fX, double fY) +void line::move_to(double fX, double fY) { - m_oPath->move_to(fX, fY); - - m_fMaxX = fX > m_fMaxX ? fX : m_fMaxX; - m_fMaxY = fY > m_fMaxY ? fY : m_fMaxY; - - SDL_FreeSurface(m_pBitmap); - m_pBitmap = NULL; + line_operation* previous = current_operation; + current_operation = new line_operation(line_operation_type::move, fX, fY); + previous->next = current_operation; } -void THLine::lineTo(double fX, double fY) +void line::line_to(double fX, double fY) { - m_oPath->line_to(fX, fY); - - m_fMaxX = fX > m_fMaxX ? fX : m_fMaxX; - m_fMaxY = fY > m_fMaxY ? fY : m_fMaxY; - - SDL_FreeSurface(m_pBitmap); - m_pBitmap = NULL; + line_operation* previous = current_operation; + current_operation = new line_operation(line_operation_type::line, fX, fY); + previous->next = current_operation; } -void THLine::setWidth(double pLineWidth) +void line::set_width(double pLineWidth) { - m_fWidth = pLineWidth; - - SDL_FreeSurface(m_pBitmap); - m_pBitmap = NULL; + width = pLineWidth; } -void THLine::setColour(uint8_t iR, uint8_t iG, uint8_t iB, uint8_t iA) +void line::set_colour(uint8_t iR, uint8_t iG, uint8_t iB, uint8_t iA) { - m_iR = iR; - m_iG = iG; - m_iB = iB; - m_iA = iA; - - SDL_FreeSurface(m_pBitmap); - m_pBitmap = NULL; + red = iR; + green = iG; + blue = iB; + alpha = iA; } -void THLine::draw(THRenderTarget* pCanvas, int iX, int iY) +void line::draw(render_target* pCanvas, int iX, int iY) { - // Strangely drawing at 0,0 would draw outside of the screen - // so we start at 1,0. This makes SDL behave like DirectX. - SDL_Rect rcDest; - rcDest.x = iX + 1; - rcDest.y = iY; - - // Try to get a cached line surface - if (m_pBitmap) { - SDL_BlitSurface(m_pBitmap, NULL, pCanvas->getRawSurface(), &rcDest); - return; - } - - // No cache, let's build a new one - SDL_FreeSurface(m_pBitmap); - - Uint32 amask; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - amask = 0x000000ff; -#else - amask = 0xff000000; -#endif - - const SDL_PixelFormat& fmt = *(pCanvas->getRawSurface()->format); - m_pBitmap = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, (int)ceil(m_fMaxX), (int)ceil(m_fMaxY), fmt.BitsPerPixel, fmt.Rmask, fmt.Gmask, fmt.Bmask, amask); - - agg::rendering_buffer rbuf(reinterpret_cast(m_pBitmap->pixels), m_pBitmap->w, m_pBitmap->h, m_pBitmap->pitch); - agg::pixfmt_rgba32 pixf(rbuf); - agg::renderer_base renb(pixf); - - agg::conv_stroke stroke(*m_oPath); - stroke.width(m_fWidth); - - agg::rasterizer_scanline_aa<> ras; - ras.add_path(stroke); - - agg::scanline_p8 sl; - agg::render_scanlines_aa_solid(ras, sl, renb, agg::rgba8(m_iB, m_iG, m_iR, m_iA)); - - SDL_BlitSurface(m_pBitmap, NULL, pCanvas->getRawSurface(), &rcDest); + pCanvas->draw_line(this, iX, iY); } -void THLine::persist(LuaPersistWriter *pWriter) const +void line::persist(lua_persist_writer *pWriter) const { - pWriter->writeVUInt((uint32_t)m_iR); - pWriter->writeVUInt((uint32_t)m_iG); - pWriter->writeVUInt((uint32_t)m_iB); - pWriter->writeVUInt((uint32_t)m_iA); - pWriter->writeVFloat(m_fWidth); - - unsigned numOps = m_oPath->total_vertices(); - pWriter->writeVUInt(numOps); + pWriter->write_uint((uint32_t)red); + pWriter->write_uint((uint32_t)green); + pWriter->write_uint((uint32_t)blue); + pWriter->write_uint((uint32_t)alpha); + pWriter->write_float(width); - for (unsigned i = 0; i < numOps; i++) { - unsigned command = m_oPath->command(i); + line_operation* op = (line_operation*)(first_operation->next); + uint32_t numOps = 0; + for (; op; numOps++) { + op = (line_operation*)(op->next); + } - double fX, fY; - m_oPath->vertex(i, &fX, &fY); + pWriter->write_uint(numOps); - if (command == agg::path_cmd_move_to) { - command = (unsigned)THLOP_MOVE; - } else if (command == agg::path_cmd_line_to) { - command = (unsigned)THLOP_LINE; - } + op = (line_operation*)(first_operation->next); + while (op) { + pWriter->write_uint((uint32_t)op->type); + pWriter->write_float(op->x); + pWriter->write_float(op->y); - pWriter->writeVUInt(command); - pWriter->writeVFloat(fX); - pWriter->writeVFloat(fY); + op = (line_operation*)(op->next); } } -void THLine::depersist(LuaPersistReader *pReader) +void line::depersist(lua_persist_reader *pReader) { initialize(); - pReader->readVUInt(m_iR); - pReader->readVUInt(m_iG); - pReader->readVUInt(m_iB); - pReader->readVUInt(m_iA); - pReader->readVFloat(m_fWidth); + pReader->read_uint(red); + pReader->read_uint(green); + pReader->read_uint(blue); + pReader->read_uint(alpha); + pReader->read_float(width); uint32_t numOps = 0; - pReader->readVUInt(numOps); + pReader->read_uint(numOps); for (uint32_t i = 0; i < numOps; i++) { - unsigned type; + line_operation_type type; double fX, fY; - - pReader->readVUInt((uint32_t&)type); - pReader->readVFloat(fX); - pReader->readVFloat(fY); - - if (type == THLOP_MOVE) { - moveTo(fX, fY); - } else if (type == THLOP_LINE) { - lineTo(fX, fY); + pReader->read_uint((uint32_t&)type); + pReader->read_float(fX); + pReader->read_float(fY); + + if (type == line_operation_type::move) { + move_to(fX, fY); + } else if (type == line_operation_type::line) { + line_to(fX, fY); } } } #ifdef CORSIX_TH_USE_FREETYPE2 -bool THFreeTypeFont::_isMonochrome() const +bool freetype_font::is_monochrome() const { return true; } -void THFreeTypeFont::_setNullTexture(cached_text_t* pCacheEntry) const +void freetype_font::free_texture(cached_text* pCacheEntry) const { - pCacheEntry->pTexture = NULL; + if(pCacheEntry->texture != nullptr) + { + SDL_DestroyTexture(pCacheEntry->texture); + pCacheEntry->texture = nullptr; + } } -void THFreeTypeFont::_freeTexture(cached_text_t* pCacheEntry) const + +void freetype_font::make_texture(render_target *pEventualCanvas, cached_text* pCacheEntry) const { - if(pCacheEntry->pTexture != NULL) + uint32_t* pPixels = new uint32_t[pCacheEntry->width * pCacheEntry->height]; + std::memset(pPixels, 0, pCacheEntry->width * pCacheEntry->height * sizeof(uint32_t)); + uint8_t* pInRow = pCacheEntry->data; + uint32_t* pOutRow = pPixels; + uint32_t iColBase = colour & 0xFFFFFF; + for(int iY = 0; iY < pCacheEntry->height; ++iY, pOutRow += pCacheEntry->width, + pInRow += pCacheEntry->width) { - SDL_FreeSurface(reinterpret_cast(pCacheEntry->pTexture)); + for(int iX = 0; iX < pCacheEntry->width; ++iX) + { + pOutRow[iX] = (static_cast(pInRow[iX]) << 24) | iColBase; + } } -} -void THFreeTypeFont::_makeTexture(cached_text_t* pCacheEntry) const -{ - SDL_Surface *pSurface = SDL_CreateRGBSurfaceFrom(pCacheEntry->pData, - pCacheEntry->iWidth, pCacheEntry->iHeight, 8, pCacheEntry->iWidth, 0, - 0, 0, 0); - SDL_SetColors(pSurface, const_cast(&m_oColour), 0xFF, 1); - SDL_SetColorKey(pSurface, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0); - pCacheEntry->pTexture = reinterpret_cast(pSurface); + pCacheEntry->texture = pEventualCanvas->create_texture(pCacheEntry->width, pCacheEntry->height, pPixels); + delete[] pPixels; } -void THFreeTypeFont::_drawTexture(THRenderTarget* pCanvas, cached_text_t* pCacheEntry, int iX, int iY) const +void freetype_font::draw_texture(render_target* pCanvas, cached_text* pCacheEntry, int iX, int iY) const { - SDL_Rect rcDest = {iX, iY, 0, 0}; - SDL_BlitSurface(reinterpret_cast(pCacheEntry->pTexture), - NULL, pCanvas->getRawSurface(), &rcDest); + if(pCacheEntry->texture == nullptr) + return; + + SDL_Rect rcDest = { iX, iY, pCacheEntry->width, pCacheEntry->height }; + pCanvas->draw(pCacheEntry->texture, nullptr, &rcDest, 0); } -#endif // CORSIX_TH_USE_FREETYPE2 -#endif // CORSIX_TH_USE_SDL_RENDERER +#endif // CORSIX_TH_USE_FREETYPE2 diff -Nru corsix-th-0.30/CorsixTH/Src/th_gfx_sdl.h corsix-th-0.62/CorsixTH/Src/th_gfx_sdl.h --- corsix-th-0.30/CorsixTH/Src/th_gfx_sdl.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_gfx_sdl.h 2018-07-21 11:13:17.000000000 +0000 @@ -23,303 +23,660 @@ #ifndef CORSIX_TH_TH_GFX_SDL_H_ #define CORSIX_TH_TH_GFX_SDL_H_ #include "config.h" -#ifdef CORSIX_TH_USE_SDL_RENDERER -#ifdef CORSIX_TH_HAS_RENDERING_ENGINE -#error More than one rendering engine enabled in config file -#endif -#define CORSIX_TH_HAS_RENDERING_ENGINE + #include -#include "agg_path_storage.h" #include "persist_lua.h" -class THCursor; -struct THClipRect : public SDL_Rect +class cursor; +struct clip_rect : public SDL_Rect { + typedef Sint16 x_y_type; + typedef Uint16 w_h_type; +}; +struct render_target_creation_params; + +/*! + Utility class for decoding 32bpp images. +*/ +class full_colour_renderer +{ +public: + //! Initialize the renderer for a specific render. + /*! + @param iWidth Pixel width of the resulting image + @param iHeight Pixel height of the resulting image + */ + full_colour_renderer(int iWidth, int iHeight); + virtual ~full_colour_renderer() = default; + + //! Decode a 32bpp image, and push it to the storage backend. + /*! + @param pImg Encoded 32bpp image. + @param pPalette Palette of a legacy sprite. + @param iSpriteFlags Flags how to render the sprite. + @return Decoding was successful. + */ + bool decode_image(const uint8_t* pImg, const ::palette *pPalette, uint32_t iSpriteFlags); + +private: + //! Store a decoded pixel. Use x and y if necessary. + /*! + @param pixel Pixel to store. + */ + virtual void store_argb(uint32_t pixel) = 0; + + const int width; + const int height; + int x; + int y; + + //! Push a pixel to the storage. + /*! + @param iValue Pixel value to store. + */ + inline void push_pixel(uint32_t iValue) + { + if (y < height) + { + store_argb(iValue); + x++; + if (x >= width) + { + x = 0; + y++; + } + } + else + { + x = 1; // Will return 'failed'. + } + } +}; + +class full_colour_storing : public full_colour_renderer +{ +public: + full_colour_storing(uint32_t *pDest, int iWidth, int iHeight); + +private: + void store_argb(uint32_t pixel) override; + + //! Pointer to the storage (not owned by this class). + uint32_t *destination; +}; + +class wx_storing : public full_colour_renderer { - typedef Sint16 xy_t; - typedef Uint16 wh_t; +public: + wx_storing(uint8_t* pRGBData, uint8_t* pAData, int iWidth, int iHeight); + +private: + void store_argb(uint32_t pixel) override; + + //! Pointer to the RGB storage (not owned by this class). + uint8_t *rgb_data; + + //! Pointer to the Alpha channel storage (not owned by this class). + uint8_t *alpha_data; }; -struct THRenderTargetCreationParams; -class THRenderTarget +class render_target { public: // External API - THRenderTarget(); - ~THRenderTarget(); + render_target(); + ~render_target(); //! Initialise the render target - bool create(const THRenderTargetCreationParams* pParams); + bool create(const render_target_creation_params* pParams); + + //! Update the parameters for the render target + bool update(const render_target_creation_params* pParams); + + //! Shut down the render target + void destroy(); //! Get the reason for the last operation failing - const char* getLastError(); + const char* get_last_error(); //! Begin rendering a new frame - bool startFrame(); + bool start_frame(); //! Finish rendering the current frame and present it - bool endFrame(); + bool end_frame(); //! Paint the entire render target black - bool fillBlack(); + bool fill_black(); //! Sets a blue filter on the current surface. // Used to add the blue effect when the game is paused. - void setBlueFilterActive(bool bActivate); + void set_blue_filter_active(bool bActivate); //! Encode an RGB triplet for fillRect() - uint32_t mapColour(uint8_t iR, uint8_t iG, uint8_t iB); + uint32_t map_colour(uint8_t iR, uint8_t iG, uint8_t iB); //! Fill a rectangle of the render target with a solid colour - bool fillRect(uint32_t iColour, int iX, int iY, int iW, int iH); + bool fill_rect(uint32_t iColour, int iX, int iY, int iW, int iH); //! Get the current clip rectangle - void getClipRect(THClipRect* pRect) const; + void get_clip_rect(clip_rect* pRect) const; //! Get the width of the render target (in pixels) - int getWidth() const; + int get_width() const; //! Get the height of the render target (in pixels) - int getHeight() const; + int get_height() const; //! Set the new clip rectangle - void setClipRect(const THClipRect* pRect); + void set_clip_rect(const clip_rect* pRect); //! Enable optimisations for non-overlapping draws - void startNonOverlapping(); + void start_nonoverlapping_draws(); //! Disable optimisations for non-overlapping draws - void finishNonOverlapping(); + void finish_nonoverlapping_draws(); //! Set the cursor to be used - void setCursor(THCursor* pCursor); + void set_cursor(cursor* pCursor); //! Update the cursor position (if the cursor is being simulated) - void setCursorPosition(int iX, int iY); + void set_cursor_position(int iX, int iY); //! Take a screenshot and save it as a bitmap - bool takeScreenshot(const char* sFile); + bool take_screenshot(const char* sFile); + + //! Set the amount by which future draw operations are scaled. + /*! + @param fScale New scale to use. + @param eWhatToScale Th kind of items to scale. + @return Whether the scale could be set. + */ + bool set_scale_factor(double fScale, scaled_items eWhatToScale); + + //! Set the window caption + void set_caption(const char* sCaption); + + //! Toggle mouse capture on the window. + void set_window_grab(bool bActivate); - //! Set the amount by which future draw operations are scaled - bool setScaleFactor(float fScale, THScaledItems eWhatToScale); + //! Get any user-displayable information to describe the renderer path used + const char *get_renderer_details() const; // If you add any extra methods here which are called from outside the // rendering engine, then be sure to at least add dummy implementations // to the other rendering engines. public: // Internal (this rendering engine only) API + SDL_Renderer *get_renderer() const { return renderer; } + + //! Should bitmaps be scaled? + /*! + @param [out] pFactor If the function returns \c true, the factor to use + for scaling (can be \c nullptr if not interested in the value). + @return Whether bitmaps should be scaled. + */ + bool should_scale_bitmaps(double* pFactor); + + SDL_Texture* create_palettized_texture(int iWidth, int iHeight, const uint8_t* pPixels, + const ::palette* pPalette, uint32_t iSpriteFlags) const; + SDL_Texture* create_texture(int iWidth, int iHeight, const uint32_t* pPixels) const; + void draw(SDL_Texture *pTexture, const SDL_Rect *prcSrcRect, const SDL_Rect *prcDstRect, int iFlags); + void draw_line(line *pLine, int iX, int iY); + +private: + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *zoom_texture; + SDL_PixelFormat *pixel_format; + bool blue_filter_active; + cursor* game_cursor; + double bitmap_scale_factor; ///< Bitmap scale factor. + int width; + int height; + int cursor_x; + int cursor_y; + bool scale_bitmaps; ///< Whether bitmaps should be scaled. + bool supports_target_textures; + + // In SDL2 < 2.0.4 there is an issue with the y coordinates used for + // ClipRects in opengl and opengles. + // see: https://bugzilla.libsdl.org/show_bug.cgi?id=2700 + bool apply_opengl_clip_fix; - SDL_Surface* getRawSurface() {return m_pSurface;} - const SDL_Surface* getRawSurface() const {return m_pSurface;} - bool shouldScaleBitmaps(float* pFactor); - -protected: - SDL_Surface* m_pSurface; - SDL_Surface* m_pDummySurface; - bool m_bBlueFilterActive; - THCursor* m_pCursor; - float m_fBitmapScaleFactor; - int m_iCursorX; - int m_iCursorY; - bool m_bShouldScaleBitmaps; + void flush_zoom_buffer(); }; -typedef SDL_Colour THColour; +//! 32bpp ARGB colour. See #palette::pack_argb +typedef uint32_t argb_colour; -class THPalette +//! 8bpp palette class. +class palette { -public: - THPalette(); - typedef SDL_Colour colour_t; +public: // External API + palette(); + + //! Load palette from the supplied data. + /*! + Note that the data uses palette entries of 6 bit colours. + @param pData Data loaded from the file. + @param iDataLength Size of the data. + @return Whether loading of the palette succeeded. + */ + bool load_from_th_file(const uint8_t* pData, size_t iDataLength); + + //! Set an entry of the palette. + /*! + The RGB colour (255, 0, 255) is used as the transparent colour. + @param iEntry Entry number to change. + @param iR Amount of red in the new entry. + @param iG Amount of green in the new entry. + @param iB Amount of blue in the new entry. + @return Setting the entry succeeded. + */ + bool set_entry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB); + +public: // Internal (this rendering engine only) API + + //! Convert A, R, G, B values to a 32bpp colour. + /*! + @param iA Amount of opacity (0-255). + @param iR Amount of red (0-255). + @param iG Amount of green (0-255). + @param iB Amount of blue (0-255). + @return 32bpp value representing the provided colour values. + */ + inline static argb_colour pack_argb(uint8_t iA, uint8_t iR, uint8_t iG, uint8_t iB) + { + return (static_cast(iR) << 0) | + (static_cast(iG) << 8) | + (static_cast(iB) << 16) | + (static_cast(iA) << 24) ; + } - bool loadFromTHFile(const unsigned char* pData, size_t iDataLength); - bool setEntry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB); + //! Get the red component of a colour. + /*! + @param iColour Colour to examine. + @return The red component intensity of the colour. + */ + inline static uint8_t get_red(argb_colour iColour) + { + return static_cast((iColour >> 0) & 0xFF); + } - colour_t operator[] (uint8_t iIndex) const {return m_aColours[iIndex];} + //! Get the green component of a colour. + /*! + @param iColour Colour to examine. + @return The green component intensity of the colour. + */ + inline static uint8_t get_green(argb_colour iColour) + { + return static_cast((iColour >> 8) & 0xFF); + } -protected: - friend class THSpriteSheet; - friend class THRawBitmap; + //! Get the blue component of a colour. + /*! + @param iColour Colour to examine. + @return The blue component intensity of the colour. + */ + inline static uint8_t get_blue(argb_colour iColour) + { + return static_cast((iColour >> 16) & 0xFF); + } - void _assign(THRenderTarget* pTarget) const; - void _assign(SDL_Surface* pSurface) const; + //! Get the opacity component of a colour. + /*! + @param iColour Colour to examine. + @return The opacity of the colour. + */ + inline static uint8_t get_alpha(argb_colour iColour) + { + return static_cast((iColour >> 24) & 0xFF); + } - colour_t m_aColours[256]; - int m_iNumColours; - int m_iTransparentIndex; + //! Get the number of colours in the palette. + /*! + @return The number of colours in the palette. + */ + int get_colour_count() const; + + //! Get the internal palette data for fast (read-only) access. + /*! + @return Table with all 256 colours of the palette. + */ + const argb_colour* get_argb_data() const; + + //! Set an entry of the palette. + /*! + @param iEntry Entry to modify. + @param iVal Palette value to set. + */ + inline void set_argb(int iEntry, uint32_t iVal) + { + colour_index_to_argb_map[iEntry] = iVal; + } + +private: + //! 32bpp palette colours associated with the 8bpp colour index. + uint32_t colour_index_to_argb_map[256]; + + //! Number of colours in the palette. + int colour_count; }; -class THRawBitmap +//! Stored image. +class raw_bitmap { public: - THRawBitmap(); - ~THRawBitmap(); + raw_bitmap(); + ~raw_bitmap(); + + //! Set the palette of the image. + /*! + @param pPalette Palette to set for this image. + */ + void set_palette(const ::palette* pPalette); - void setPalette(const THPalette* pPalette); + //! Load the image from the supplied pixel data. + /*! + Loader uses the palette supplied before. + @param pPixelData Image data loaded from a TH file. + @param iPixelDataLength Size of the loaded image data. + @param iWidth Width of the image. + @param pEventualCanvas Canvas to render the image to (eventually). + @return Loading was a success. + */ + bool load_from_th_file(const uint8_t* pPixelData, size_t iPixelDataLength, + int iWidth, render_target *pEventualCanvas); - bool loadFromTHFile(const unsigned char* pPixelData, size_t iPixelDataLength, - int iWidth, THRenderTarget *pUnused); + //! Draw the image at a given position at the given canvas. + /*! + @param pCanvas Canvas to draw at. + @param iX Destination x position. + @param iY Destination y position. + */ + void draw(render_target* pCanvas, int iX, int iY); - void draw(THRenderTarget* pCanvas, int iX, int iY); - void draw(THRenderTarget* pCanvas, int iX, int iY, int iSrcX, int iSrcY, + //! Draw part of the image at a given position at the given canvas. + /*! + @param pCanvas Canvas to draw at. + @param iX Destination x position. + @param iY Destination y position. + @param iSrcX X position of the part to display. + @param iSrcY Y position of the part to display. + @param iWidth Width of the part to display. + @param iHeight Height of the part to display. + */ + void draw(render_target* pCanvas, int iX, int iY, int iSrcX, int iSrcY, int iWidth, int iHeight); -protected: - bool _checkScaled(THRenderTarget* pCanvas, SDL_Rect& rcDest); +private: + //! Image stored in SDL format for quick rendering. + SDL_Texture *texture; + + //! Palette of the image. + const ::palette* bitmap_palette; - SDL_Surface* m_pBitmap; - SDL_Surface* m_pCachedScaledBitmap; - unsigned char* m_pData; - const THPalette* m_pPalette; + //! Target canvas. + render_target* target; + + //! Width of the stored image. + int width; + + //! Height of the stored image. + int height; }; -class THSpriteSheet +//! Sheet of sprites. +class sprite_sheet { -public: - THSpriteSheet(); - ~THSpriteSheet(); +public: // External API + sprite_sheet(); + ~sprite_sheet(); - void setPalette(const THPalette* pPalette); + //! Set the palette to use for the sprites in the sheet. + /*! + @param pPalette Palette to use for the sprites at the sheet. + */ + void set_palette(const ::palette* pPalette); - //! Load a sprite sheet from Theme Hospital data + //! Load the sprites from the supplied data (using the palette supplied earlier). /*! - @param bComplexChunks See THChunkRenderer::decodeChunks() + @param pTableData Start of table data with TH sprite information (see th_sprite_properties). + @param iTableDataLength Length of the table data. + @param pChunkData Start of image data (chunks). + @param iChunkDataLength Length of the chunk data. + @param bComplexChunks Whether the supplied chunks are 'complex'. + @param pEventualCanvas Canvas to draw at. + @return Loading succeeded. */ - bool loadFromTHFile(const unsigned char* pTableData, size_t iTableDataLength, - const unsigned char* pChunkData, size_t iChunkDataLength, - bool bComplexChunks, THRenderTarget *pUnused); + bool load_from_th_file(const uint8_t* pTableData, size_t iTableDataLength, + const uint8_t* pChunkData, size_t iChunkDataLength, + bool bComplexChunks, render_target* pEventualCanvas); - void setSpriteAltPaletteMap(unsigned int iSprite, const unsigned char* pMap); + //! Set the data of a sprite. + /*! + @param iSprite Number of the sprite to set. + @param pData Data of the sprite. + @param bTakeData Whether the data block may be taken (must be new[] then). + @param iDataLength Length of the data. + @param iWidth Width of the sprite. + @param iHeight Height of the sprite. + @return Setting the sprite succeeded. + */ + bool set_sprite_data(size_t iSprite, const uint8_t *pData, bool bTakeData, + size_t iDataLength, int iWidth, int iHeight); - unsigned int getSpriteCount() const; + //! Supply a new mapped palette to a sprite. + /*! + @param iSprite Sprite getting the mapped palette. + @param pMap The palette map to apply. + @param iAlt32 What to do for a 32bpp sprite (#THDF_Alt32_Mask bits). + */ + void set_sprite_alt_palette_map(size_t iSprite, const uint8_t* pMap, uint32_t iAlt32); - //! Get the size of a sprite + //! Get the number of sprites at the sheet. /*! - @param iSprite Sprite index. Should be in range [0, getSpriteCount() - 1]. - @param pX Pointer to store width at. May be NULL. - @param pY Pointer to store height at. May be NULL. - @return true if the sprite index was valid, false otherwise. + @return The number of sprites available at the sheet. */ - bool getSpriteSize(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const; + size_t get_sprite_count() const; - //! Get the size of a sprite + //! Set the number of sprites in the sheet. /*! - @param iSprite Sprite index. Must be in range [0, getSpriteCount() - 1]. - @param pX Pointer to store width at. Must not be NULL. - @param pY Pointer to store height at. Must not be NULL. + @param iCount The desired number of sprites. + @param pCanvas Canvas to draw at. + @return Whether the number of sprites could be allocated. */ - void getSpriteSizeUnchecked(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const; + bool set_sprite_count(size_t iCount, render_target* pCanvas); - //! Get the average of the non-transparent pixels of a sprite + //! Get size of a sprite. /*! - For this function, "average" means the mode (i.e. the colour which - occurs most frequently) rather than an arithmetic mean, modified to favour - both dark and bright colours over intermediate ones. - @param iSprite Sprite index. Should be in range [0, getSpriteCount() - 1]. - @param pColour Pointer to store resulting average at. - @return true if there was an average colour (i.e. sprite existed and - had at least one opaque pixel), false otherwise. + @param iSprite Sprite to get info from. + @param pWidth [out] If not nullptr, the sprite width is stored in the destination. + @param pHeight [out] If not nullptr, the sprite height is stored in the destination. + @return Size could be provided for the sprite. */ - bool getSpriteAverageColour(unsigned int iSprite, THColour* pColour) const; + bool get_sprite_size(size_t iSprite, unsigned int* pWidth, unsigned int* pHeight) const; - void drawSprite(THRenderTarget* pCanvas, unsigned int iSprite, int iX, int iY, unsigned long iFlags); - bool hitTestSprite(unsigned int iSprite, int iX, int iY, unsigned long iFlags) const; + //! Get size of a sprite, assuming all input is correctly supplied. + /*! + @param iSprite Sprite to get info from. + @param pWidth [out] The sprite width is stored in the destination. + @param pHeight [out] The sprite height is stored in the destination. + */ + void get_sprite_size_unchecked(size_t iSprite, unsigned int* pWidth, unsigned int* pHeight) const; -protected: - friend class THCursor; + //! Get the best colour to represent the sprite. + /*! + @param iSprite Sprite number to analyze. + @param pColour [out] Resulting colour. + @return Best colour could be established. + */ + bool get_sprite_average_colour(size_t iSprite, argb_colour* pColour) const; + + //! Draw a sprite onto the canvas. + /*! + @param pCanvas Canvas to draw on. + @param iSprite Sprite to draw. + @param iX X position to draw the sprite. + @param iY Y position to draw the sprite. + @param iFlags Flags to apply for drawing. + */ + void draw_sprite(render_target* pCanvas, size_t iSprite, int iX, int iY, uint32_t iFlags); + + //! Test whether a sprite was hit. + /*! + @param iSprite Sprite being tested. + @param iX X position of the point to test relative to the origin of the sprite. + @param iY Y position of the point to test relative to the origin of the sprite. + @param iFlags Draw flags to apply to the sprite before testing. + @return Whether the sprite covers the give point. + */ + bool hit_test_sprite(size_t iSprite, int iX, int iY, uint32_t iFlags) const; + +public: // Internal (this rendering engine only) API + //! Draw a sprite into wxImage data arrays (for the Map Editor) + /*! + @param iSprite Sprite number to draw. + @param pRGBData Output RGB data array. + @param pAData Output Alpha channel array. + */ + void wx_draw_sprite(size_t iSprite, uint8_t* pRGBData, uint8_t* pAData); + +private: + friend class cursor; #if CORSIX_TH_USE_PACK_PRAGMAS #pragma pack(push) #pragma pack(1) #endif - struct th_sprite_t + //! Sprite structure in the table file. + struct th_sprite_properties { + //! Position of the sprite in the chunk data file. uint32_t position; - unsigned char width; - unsigned char height; + + //! Width of the sprite. + uint8_t width; + + //! Height of the sprite. + uint8_t height; } CORSIX_TH_PACKED_FLAGS; #if CORSIX_TH_USE_PACK_PRAGMAS #pragma pack(pop) #endif - //! Sprite data structure. - struct sprite_t + //! Sprites of the sheet. + struct sprite { - SDL_Surface *pBitmap[32]; + //! SDL structure containing the sprite with original palette. + SDL_Texture *texture; + + //! SDL structure containing the sprite with alternative palette. + SDL_Texture *alt_texture; + + //! Data of the sprite. + const uint8_t *data; + + //! Alternative palette (if available). + const uint8_t *alt_palette_map; - //! Data of the sprite (width * height bytes). - unsigned char *pData; - const unsigned char *pAltPaletteMap; + //! Flags how to render the sprite, contains #THDF_Alt32_Mask bits. + uint32_t sprite_flags; //! Width of the sprite. - unsigned int iWidth; + int width; //! Height of the sprite. - unsigned int iHeight; - } *m_pSprites; - const THPalette* m_pPalette; + int height; + } *sprites; + + //! Original palette. + const ::palette* palette; + + //! Target to render to. + render_target* target; //! Number of sprites in the sprite sheet. - unsigned int m_iSpriteCount; - bool m_bHasAnyFlaggedBitmaps; + size_t sprite_count; + + //! Free memory of a single sprite. + /*! + @param iNumber Number of the sprite to clear. + */ + void _freeSingleSprite(size_t iNumber); //! Free the memory used by the sprites. Also releases the SDL bitmaps. void _freeSprites(); - SDL_Surface* _getSpriteBitmap(unsigned int iSprite, unsigned long iFlags); + + //! Construct an alternative version (with its alternative palette map) of the sprite. + /*! + @param pSprite Sprite to change. + @return SDL texture containing the sprite. + */ + SDL_Texture *_makeAltBitmap(sprite *pSprite); }; -class THCursor +class cursor { public: - THCursor(); - ~THCursor(); + cursor(); + ~cursor(); - bool createFromSprite(THSpriteSheet* pSheet, unsigned int iSprite, - int iHotspotX = 0, int iHotspotY = 0); + bool create_from_sprite(sprite_sheet* pSheet, size_t iSprite, + int iHotspotX = 0, int iHotspotY = 0); - void use(THRenderTarget* pTarget); + void use(render_target* pTarget); - static bool setPosition(THRenderTarget* pTarget, int iX, int iY); - - void draw(THRenderTarget* pCanvas, int iX, int iY); -protected: - SDL_Surface* m_pBitmap; - SDL_Cursor* m_pCursorHidden; - int m_iHotspotX; - int m_iHotspotY; + static bool set_position(render_target* pTarget, int iX, int iY); + + void draw(render_target* pCanvas, int iX, int iY); +private: + SDL_Surface* bitmap; + SDL_Cursor* hidden_cursor; + int hotspot_x; + int hotspot_y; }; -class THLine + +class line { public: - THLine(); - ~THLine(); + line(); + ~line(); - void moveTo(double fX, double fY); + void move_to(double fX, double fY); - void lineTo(double fX, double fY); + void line_to(double fX, double fY); - void setWidth(double lineWidth); + void set_width(double lineWidth); - void draw(THRenderTarget* pCanvas, int iX, int iY); + void draw(render_target* pCanvas, int iX, int iY); - void setColour(uint8_t iR, uint8_t iG, uint8_t iB, uint8_t iA = 255); + void set_colour(uint8_t iR, uint8_t iG, uint8_t iB, uint8_t iA = 255); - void persist(LuaPersistWriter *pWriter) const; - void depersist(LuaPersistReader *pReader); + void persist(lua_persist_writer *pWriter) const; + void depersist(lua_persist_reader *pReader); -protected: +private: + friend class render_target; void initialize(); - enum THLineOpType { - THLOP_MOVE, - THLOP_LINE + enum class line_operation_type { + move, + line }; - agg::path_storage* m_oPath; - double m_fWidth; - uint8_t m_iR, m_iG, m_iB, m_iA; + class line_operation : public link_list + { + public: + line_operation_type type; + double x, y; + line_operation(line_operation_type type, double x, double y) : type(type), x(x), y(y) { + next = nullptr; + } + }; - SDL_Surface* m_pBitmap; // A cache for line drawing - double m_fMaxX, m_fMaxY; // We'll need a surface with this size + line_operation* first_operation; + line_operation* current_operation; + double width; + uint8_t red, green, blue, alpha; }; -#endif // CORSIX_TH_USE_SDL_RENDERER #endif // CORSIX_TH_TH_GFX_SDL_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/th.h corsix-th-0.62/CorsixTH/Src/th.h --- corsix-th-0.30/CorsixTH/Src/th.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th.h 2018-07-21 11:13:17.000000000 +0000 @@ -22,62 +22,74 @@ #ifndef CORSIX_TH_TH_H_ #define CORSIX_TH_TH_H_ -#include +#include "config.h" +#include //! Generic linked list class (for inheriting from) -struct THLinkList +class link_list { - THLinkList() ; - ~THLinkList(); +public: + link_list() ; + ~link_list(); + + link_list* prev; + link_list* next; - THLinkList* m_pPrev; - THLinkList* m_pNext; + void remove_from_list(); - void removeFromList(); - int getDrawingLayer() {return m_drawingLayer;} - void setDrawingLayer(int layer) {m_drawingLayer = layer;} + // TODO: drawing layer doesn't belong in a generic link list. + int get_drawing_layer() {return drawing_layer;} + void set_drawing_layer(int layer) {drawing_layer = layer;} - int m_drawingLayer; +private: + int drawing_layer; }; -//! Theme Hospital localised string list -class THStringList +//! \brief Theme Hospital localised string list +//! +//! Presents Theme Hospital strings by section and index. +class th_string_list { public: - THStringList(); - ~THStringList(); - - bool loadFromTHFile(const unsigned char* pData, size_t iDataLength); + //! Construct an instance of string_list from the given data + //! from a Theme Hosptial string file. The format of the data is + //! described at: + //! https://github.com/alexandergitter/theme-hospital-spec/blob/master/format-specification.md#strings + //! + //! \param data A pointer to the raw data + //! \param length The size of the data + th_string_list(const uint8_t* data, size_t length); + + // Delete default constructors and assignment operators. They + // can be implemented properly later if they are needed but + // for now they are unneeded so it is safer to remove them. + th_string_list() = delete; + th_string_list(const th_string_list &) = delete; + th_string_list(th_string_list &&) = delete; + th_string_list& operator= (const th_string_list &) = delete; + th_string_list&& operator= (th_string_list &&) = delete; + ~th_string_list(); //! Get the number of sections in the string list - unsigned int getSectionCount(); + size_t get_section_count(); //! Get the number of strings in a section of the string list - unsigned int getSectionSize(unsigned int iSection); + size_t get_section_size(size_t section); //! Get a string from the string list /*! - @param iSection Section index in range [0, getSectionCount() - 1] - @param iIndex String index in range [0, getSectionSize(iSection) - 1] - @return NULL if the index is invalid, otherwise a UTF-8 encoded string. + @param section Section index in range [0, getSectionCount() - 1] + @param index String index in range [0, getSectionSize(iSection) - 1] + @return nullptr if the index is invalid, otherwise a UTF-8 encoded string. */ - const char* getString(unsigned int iSection, unsigned int iIndex); + const char* get_string(size_t section, size_t index); -protected: - struct section_t - { - //! Size of pStrings array - unsigned int iSize; - //! Array of string pointers (into THStringList::m_sData) - const char** pStrings; - }; - - //! Size of m_pSections array - unsigned int m_iSectionCount; +private: //! Section information - section_t* m_pSections; - //! Memory block containing all the actual strings - unsigned char* m_sData; + std::vector> sections; + + //! Memory block containing all the actual strings utf-8 encoded + std::vector string_buffer; }; #endif // CORSIX_TH_TH_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_anims.cpp corsix-th-0.62/CorsixTH/Src/th_lua_anims.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua_anims.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_anims.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -26,35 +26,50 @@ /* this variable is used to determine the layer of the animation, it should be rewriten at some point so that the it is passed as an argument in the function l_anim_set_tile */ -static int lastLayer = 2; +static int last_layer = 2; static int l_anims_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_anims_set_spritesheet(lua_State *L) { - THAnimationManager* pAnims = luaT_testuserdata(L); - THSpriteSheet* pSheet = luaT_testuserdata(L, 2); + animation_manager* pAnims = luaT_testuserdata(L); + sprite_sheet* pSheet = luaT_testuserdata(L, 2); lua_settop(L, 2); - pAnims->setSpriteSheet(pSheet); + pAnims->set_sprite_sheet(pSheet); luaT_setenvfield(L, 1, "sprites"); return 1; } +//! Set the video target for the sprites. +/*! + setCanvas() + */ +static int l_anims_set_canvas(lua_State *L) +{ + animation_manager* pAnims = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L, 2); + lua_settop(L, 2); + + pAnims->set_canvas(pCanvas); + luaT_setenvfield(L, 1, "target"); + return 1; +} + static int l_anims_load(lua_State *L) { - THAnimationManager* pAnims = luaT_testuserdata(L); + animation_manager* pAnims = luaT_testuserdata(L); size_t iStartDataLength, iFrameDataLength, iListDataLength, iElementDataLength; - const unsigned char* pStartData = luaT_checkfile(L, 2, &iStartDataLength); - const unsigned char* pFrameData = luaT_checkfile(L, 3, &iFrameDataLength); - const unsigned char* pListData = luaT_checkfile(L, 4, &iListDataLength); - const unsigned char* pElementData = luaT_checkfile(L, 5, &iElementDataLength); + const uint8_t* pStartData = luaT_checkfile(L, 2, &iStartDataLength); + const uint8_t* pFrameData = luaT_checkfile(L, 3, &iFrameDataLength); + const uint8_t* pListData = luaT_checkfile(L, 4, &iListDataLength); + const uint8_t* pElementData = luaT_checkfile(L, 5, &iElementDataLength); - if(pAnims->loadFromTHFile(pStartData, iStartDataLength, pFrameData, iFrameDataLength, + if(pAnims->load_from_th_file(pStartData, iStartDataLength, pFrameData, iFrameDataLength, pListData, iListDataLength, pElementData, iElementDataLength)) { lua_pushboolean(L, 1); @@ -67,34 +82,79 @@ return 1; } +//! Load custom animations. +/*! + loadCustom() -> true/false + */ +static int l_anims_loadcustom(lua_State *L) +{ + animation_manager* pAnims = luaT_testuserdata(L); + size_t iDataLength; + const uint8_t* pData = luaT_checkfile(L, 2, &iDataLength); + + if (pAnims->load_custom_animations(pData, iDataLength)) + { + lua_pushboolean(L, 1); + } + else + { + lua_pushboolean(L, 0); + } + + return 1; +} + +//! Lua interface for getting a set of animations by name and tile size (one for +//! each view direction, 'nil' if no animation is available for a direction). +/*! + getAnimations(, ) -> (, , , ) + */ +static int l_anims_getanims(lua_State *L) +{ + animation_manager* pAnims = luaT_testuserdata(L); + int iTileSize = static_cast(luaL_checkinteger(L, 2)); + const char *pName = luaL_checkstring(L, 3); + + const animation_start_frames &oFrames = pAnims->get_named_animations(pName, iTileSize); + if (oFrames.north < 0) { lua_pushnil(L); } else { lua_pushnumber(L, static_cast(oFrames.north)); } + if (oFrames.east < 0) { lua_pushnil(L); } else { lua_pushnumber(L, static_cast(oFrames.east)); } + if (oFrames.south < 0) { lua_pushnil(L); } else { lua_pushnumber(L, static_cast(oFrames.south)); } + if (oFrames.west < 0) { lua_pushnil(L); } else { lua_pushnumber(L, static_cast(oFrames.west)); } + return 4; +} + + static int l_anims_getfirst(lua_State *L) { - THAnimationManager* pAnims = luaT_testuserdata(L); - int iAnim = luaL_checkint(L, 2); + animation_manager* pAnims = luaT_testuserdata(L); + int iAnim = static_cast(luaL_checkinteger(L, 2)); - lua_pushinteger(L, pAnims->getFirstFrame((unsigned int)iAnim)); + lua_pushinteger(L, pAnims->get_first_frame(iAnim)); return 1; } static int l_anims_getnext(lua_State *L) { - THAnimationManager* pAnims = luaT_testuserdata(L); - int iFrame = luaL_checkint(L, 2); + animation_manager* pAnims = luaT_testuserdata(L); + int iFrame = static_cast(luaL_checkinteger(L, 2)); - lua_pushinteger(L, pAnims->getNextFrame((unsigned int)iFrame)); + lua_pushinteger(L, pAnims->get_next_frame(iFrame)); return 1; } static int l_anims_set_alt_pal(lua_State *L) { - THAnimationManager* pAnims = luaT_testuserdata(L); - unsigned int iAnimation = luaL_checkint(L, 2); + animation_manager* pAnims = luaT_testuserdata(L); + size_t iAnimation = luaL_checkinteger(L, 2); size_t iPalLen; - const unsigned char *pPal = luaT_checkfile(L, 3, &iPalLen); + const uint8_t *pPal = luaT_checkfile(L, 3, &iPalLen); if(iPalLen != 256) - return luaL_typerror(L, 3, "GhostPalette string"); + { + return luaL_argerror(L, 3, "GhostPalette string is not a valid palette"); + } + uint32_t iAlt32 = static_cast(luaL_checkinteger(L, 4)); - pAnims->setAnimationAltPaletteMap(iAnimation, pPal); + pAnims->set_animation_alt_palette_map(iAnimation, pPal, iAlt32); lua_getfenv(L, 1); lua_insert(L, 2); @@ -106,31 +166,31 @@ static int l_anims_set_marker(lua_State *L) { - THAnimationManager* pAnims = luaT_testuserdata(L); - lua_pushboolean(L, pAnims->setFrameMarker((unsigned int)luaL_checkinteger(L, 2), - luaL_checkint(L, 3), luaL_checkint(L, 4)) ? 1 : 0); + animation_manager* pAnims = luaT_testuserdata(L); + lua_pushboolean(L, pAnims->set_frame_marker(luaL_checkinteger(L, 2), + static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4))) ? 1 : 0); return 1; } static int l_anims_set_secondary_marker(lua_State *L) { - THAnimationManager* pAnims = luaT_testuserdata(L); - lua_pushboolean(L, pAnims->setFrameSecondaryMarker((unsigned int)luaL_checkinteger(L, 2), - luaL_checkint(L, 3), luaL_checkint(L, 4)) ? 1 : 0); + animation_manager* pAnims = luaT_testuserdata(L); + lua_pushboolean(L, pAnims->set_frame_secondary_marker(luaL_checkinteger(L, 2), + static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4))) ? 1 : 0); return 1; } static int l_anims_draw(lua_State *L) { - THAnimationManager* pAnims = luaT_testuserdata(L); - THRenderTarget* pCanvas = luaT_testuserdata(L, 2); - int iFrame = luaL_checkint(L, 3); - THLayers_t* pLayers = luaT_testuserdata(L, 4, luaT_upvalueindex(2)); - int iX = luaL_checkint(L, 5); - int iY = luaL_checkint(L, 6); - int iFlags = luaL_optint(L, 7, 0); + animation_manager* pAnims = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L, 2); + size_t iFrame = luaL_checkinteger(L, 3); + layers* pLayers = luaT_testuserdata(L, 4, luaT_upvalueindex(2)); + int iX = static_cast(luaL_checkinteger(L, 5)); + int iY = static_cast(luaL_checkinteger(L, 6)); + int iFlags = static_cast(luaL_optinteger(L, 7, 0)); - pAnims->drawFrame(pCanvas, (unsigned int)iFrame, *pLayers, iX, iY, iFlags); + pAnims->draw_frame(pCanvas, iFrame, *pLayers, iX, iY, iFlags); lua_settop(L, 1); return 1; @@ -162,13 +222,13 @@ // Fast __persist call pAnimation = (T*)lua_touserdata(L, -1); } - LuaPersistWriter* pWriter = (LuaPersistWriter*)lua_touserdata(L, 1); + lua_persist_writer* pWriter = (lua_persist_writer*)lua_touserdata(L, 1); pAnimation->persist(pWriter); lua_rawgeti(L, luaT_environindex, 1); lua_pushlightuserdata(L, pAnimation); lua_gettable(L, -2); - pWriter->writeStackObject(-1); + pWriter->write_stack_object(-1); lua_pop(L, 2); return 0; } @@ -181,8 +241,8 @@ // things work nicely, we initialise all the fields of a THAnimation as // soon as possible, thus preventing issues like an anim -> map -> anim // reference chain whereby l_anim_depersist is called after l_map_depersist - // (as anim references map in its environment table) causing the pPrev - // field to be set during map depersistence, then cleared to NULL by the + // (as anim references map in its environment table) causing the prev + // field to be set during map depersistence, then cleared to nullptr by the // constructor during l_anim_depersist. T* pAnimation = luaT_testuserdata(L); new (pAnimation) T; // Call constructor @@ -195,7 +255,7 @@ T* pAnimation = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - LuaPersistReader* pReader = (LuaPersistReader*)lua_touserdata(L, 1); + lua_persist_reader* pReader = (lua_persist_reader*)lua_touserdata(L, 1); lua_rawgeti(L, luaT_environindex, 2); lua_pushlightuserdata(L, pAnimation); @@ -205,7 +265,7 @@ pAnimation->depersist(pReader); lua_rawgeti(L, luaT_environindex, 1); lua_pushlightuserdata(L, pAnimation); - if(!pReader->readStackObject()) + if(!pReader->read_stack_object()) return 0; lua_settable(L, -3); lua_pop(L, 1); @@ -226,48 +286,48 @@ static int l_anim_set_frame(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - pAnimation->setFrame(luaL_checkint(L, 2)); + animation* pAnimation = luaT_testuserdata(L); + pAnimation->set_frame(luaL_checkinteger(L, 2)); lua_settop(L, 1); return 1; } static int l_anim_get_frame(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - lua_pushinteger(L, pAnimation->getFrame()); + animation* pAnimation = luaT_testuserdata(L); + lua_pushinteger(L, pAnimation->get_frame()); return 1; } static int l_anim_set_crop(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - pAnimation->setCropColumn(luaL_checkint(L, 2)); + animation* pAnimation = luaT_testuserdata(L); + pAnimation->set_crop_column(static_cast(luaL_checkinteger(L, 2))); lua_settop(L, 1); return 1; } static int l_anim_get_crop(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - lua_pushinteger(L, pAnimation->getCropColumn()); + animation* pAnimation = luaT_testuserdata(L); + lua_pushinteger(L, pAnimation->get_crop_column()); return 1; } static int l_anim_set_anim(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - THAnimationManager* pManager = luaT_testuserdata(L, 2); - int iAnim = luaL_checkint(L, 3); - if(iAnim < 0 || (unsigned int)iAnim >= pManager->getAnimationCount()) + animation* pAnimation = luaT_testuserdata(L); + animation_manager* pManager = luaT_testuserdata(L, 2); + size_t iAnim = luaL_checkinteger(L, 3); + if(iAnim < 0 || iAnim >= pManager->get_animation_count()) luaL_argerror(L, 3, "Animation index out of bounds"); if(lua_isnoneornil(L, 4)) - pAnimation->setFlags(0); + pAnimation->set_flags(0); else - pAnimation->setFlags(luaL_checkint(L, 4)); + pAnimation->set_flags(static_cast(luaL_checkinteger(L, 4))); - pAnimation->setAnimation(pManager, iAnim); + pAnimation->set_animation(pManager, iAnim); lua_settop(L, 2); luaT_setenvfield(L, 1, "animator"); lua_pushnil(L); @@ -278,14 +338,14 @@ static int l_anim_set_morph(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - THAnimation* pMorphTarget = luaT_testuserdata(L, 2, luaT_environindex); + animation* pAnimation = luaT_testuserdata(L); + animation* pMorphTarget = luaT_testuserdata(L, 2, luaT_environindex); unsigned int iDurationFactor = 1; - if(!lua_isnoneornil(L, 3) && luaL_checkint(L, 3) > 0) - iDurationFactor = luaL_checkint(L, 3); + if(!lua_isnoneornil(L, 3) && luaL_checkinteger(L, 3) > 0) + iDurationFactor = static_cast(luaL_checkinteger(L, 3)); - pAnimation->setMorphTarget(pMorphTarget, iDurationFactor); + pAnimation->set_morph_target(pMorphTarget, iDurationFactor); lua_settop(L, 2); luaT_setenvfield(L, 1, "morph_target"); @@ -294,14 +354,14 @@ static int l_anim_set_drawable_layer(lua_State *L) { - lastLayer = luaL_checkint(L, 2); + last_layer = static_cast(luaL_checkinteger(L, 2)); return 1; } static int l_anim_get_anim(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - lua_pushinteger(L, pAnimation->getAnimation()); + animation* pAnimation = luaT_testuserdata(L); + lua_pushinteger(L, pAnimation->get_animation()); return 1; } @@ -313,17 +373,17 @@ T* pAnimation = luaT_testuserdata(L); if(lua_isnoneornil(L, 2)) { - pAnimation->removeFromTile(); + pAnimation->remove_from_tile(); lua_pushnil(L); luaT_setenvfield(L, 1, "map"); lua_settop(L, 1); } else { - THMap* pMap = luaT_testuserdata(L, 2); - THMapNode* pNode = pMap->getNode(luaL_checkint(L, 3) - 1, luaL_checkint(L, 4) - 1); + level_map* pMap = luaT_testuserdata(L, 2); + map_tile* pNode = pMap->get_tile(static_cast(luaL_checkinteger(L, 3) - 1), static_cast(luaL_checkinteger(L, 4) - 1)); if(pNode) - pAnimation->attachToTile(pNode, lastLayer); + pAnimation->attach_to_tile(pNode, last_layer); else { @@ -341,7 +401,7 @@ static int l_anim_get_tile(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); + animation* pAnimation = luaT_testuserdata(L); lua_settop(L, 1); lua_getfenv(L, 1); lua_getfield(L, 2, "map"); @@ -350,24 +410,24 @@ { return 0; } - THMap* pMap = (THMap*)lua_touserdata(L, 2); - const THLinkList* pListNode = pAnimation->getPrevious(); - while(pListNode->m_pPrev) + level_map* pMap = (level_map*)lua_touserdata(L, 2); + const link_list* pListNode = pAnimation->get_previous(); + while(pListNode->prev) { - pListNode = pListNode->m_pPrev; + pListNode = pListNode->prev; } - // Casting pListNode to a THMapNode* is slightly dubious, but it should - // work. If on the normal list, then pListNode will be a THMapNode*, and + // Casting pListNode to a map_tile* is slightly dubious, but it should + // work. If on the normal list, then pListNode will be a map_tile*, and // all is fine. However, if on the early list, pListNode will be pointing - // to a member of a THMapNode, so we're relying on pointer arithmetic - // being a subtract and integer divide by sizeof(THMapNode) to yield the - // correct map node. - const THMapNode *pRootNode = pMap->getNodeUnchecked(0, 0); + // to a member of a map_tile, so we're relying on pointer arithmetic + // being a subtract and integer divide by sizeof(map_tile) to yield the + // correct map_tile. + const map_tile *pRootNode = pMap->get_tile_unchecked(0, 0); uintptr_t iDiff = reinterpret_cast(pListNode) - reinterpret_cast(pRootNode); - int iIndex = (int)(iDiff / sizeof(THMapNode)); - int iY = iIndex / pMap->getWidth(); - int iX = iIndex - (iY * pMap->getWidth()); + int iIndex = (int)(iDiff / sizeof(map_tile)); + int iY = iIndex / pMap->get_width(); + int iX = iIndex - (iY * pMap->get_width()); lua_pushinteger(L, iX + 1); lua_pushinteger(L, iY + 1); return 3; // map, x, y @@ -375,9 +435,9 @@ static int l_anim_set_parent(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - THAnimation* pParent = luaT_testuserdata(L, 2, luaT_environindex, false); - pAnimation->setParent(pParent); + animation* pAnimation = luaT_testuserdata(L); + animation* pParent = luaT_testuserdata(L, 2, luaT_environindex, false); + pAnimation->set_parent(pParent); lua_settop(L, 1); return 1; } @@ -386,7 +446,7 @@ static int l_anim_set_flag(lua_State *L) { T* pAnimation = luaT_testuserdata(L); - pAnimation->setFlags(luaL_checkint(L, 2)); + pAnimation->set_flags(static_cast(luaL_checkinteger(L, 2))); lua_settop(L, 1); return 1; @@ -396,14 +456,14 @@ static int l_anim_set_flag_partial(lua_State *L) { T* pAnimation = luaT_testuserdata(L); - int iFlags = luaL_checkint(L, 2); + uint32_t iFlags = static_cast(luaL_checkinteger(L, 2)); if(lua_isnone(L, 3) || lua_toboolean(L, 3)) { - pAnimation->setFlags(pAnimation->getFlags() | iFlags); + pAnimation->set_flags(pAnimation->get_flags() | iFlags); } else { - pAnimation->setFlags(pAnimation->getFlags() & ~iFlags); + pAnimation->set_flags(pAnimation->get_flags() & ~iFlags); } lua_settop(L, 1); return 1; @@ -413,7 +473,7 @@ static int l_anim_make_visible(lua_State *L) { T* pAnimation = luaT_testuserdata(L); - pAnimation->setFlags(pAnimation->getFlags() & ~(THDF_Alpha50 | THDF_Alpha75)); + pAnimation->set_flags(pAnimation->get_flags() & ~static_cast(thdf_alpha_50 | thdf_alpha_75)); lua_settop(L, 1); return 1; @@ -423,7 +483,7 @@ static int l_anim_make_invisible(lua_State *L) { T* pAnimation = luaT_testuserdata(L); - pAnimation->setFlags(pAnimation->getFlags() | THDF_Alpha50 | THDF_Alpha75); + pAnimation->set_flags(pAnimation->get_flags() | static_cast(thdf_alpha_50 | thdf_alpha_75)); lua_settop(L, 1); return 1; @@ -433,7 +493,7 @@ static int l_anim_get_flag(lua_State *L) { T* pAnimation = luaT_testuserdata(L); - lua_pushinteger(L, pAnimation->getFlags()); + lua_pushinteger(L, pAnimation->get_flags()); return 1; } @@ -443,7 +503,7 @@ { T* pAnimation = luaT_testuserdata(L); - pAnimation->setPosition(luaL_checkint(L, 2), luaL_checkint(L, 3)); + pAnimation->set_position(static_cast(luaL_checkinteger(L, 2)), static_cast(luaL_checkinteger(L, 3))); lua_settop(L, 1); return 1; @@ -451,10 +511,10 @@ static int l_anim_get_position(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); + animation* pAnimation = luaT_testuserdata(L); - lua_pushinteger(L, pAnimation->getX()); - lua_pushinteger(L, pAnimation->getY()); + lua_pushinteger(L, pAnimation->get_x()); + lua_pushinteger(L, pAnimation->get_y()); return 2; } @@ -464,7 +524,7 @@ { T* pAnimation = luaT_testuserdata(L); - pAnimation->setSpeed(luaL_optint(L, 2, 0), luaL_optint(L, 3, 0)); + pAnimation->set_speed(static_cast(luaL_optinteger(L, 2, 0)), static_cast(luaL_optinteger(L, 3, 0))); lua_settop(L, 1); return 1; @@ -475,7 +535,7 @@ { T* pAnimation = luaT_testuserdata(L); - pAnimation->setLayer(luaL_checkint(L, 2), luaL_optint(L, 3, 0)); + pAnimation->set_layer(static_cast(luaL_checkinteger(L, 2)), static_cast(luaL_optinteger(L, 3, 0))); lua_settop(L, 1); return 1; @@ -483,10 +543,10 @@ static int l_anim_set_layers_from(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); - const THAnimation* pAnimationSrc = luaT_testuserdata(L, 2, luaT_environindex); + animation* pAnimation = luaT_testuserdata(L); + const animation* pAnimationSrc = luaT_testuserdata(L, 2, luaT_environindex); - pAnimation->setLayersFrom(pAnimationSrc); + pAnimation->set_layers_from(pAnimationSrc); lua_settop(L, 1); return 1; @@ -494,7 +554,7 @@ static int l_anim_set_tag(lua_State *L) { - luaT_testuserdata(L); + luaT_testuserdata(L); lua_settop(L, 2); luaT_setenvfield(L, 1, "tag"); return 1; @@ -502,7 +562,7 @@ static int l_anim_get_tag(lua_State *L) { - luaT_testuserdata(L); + luaT_testuserdata(L); lua_settop(L, 1); lua_getfenv(L, 1); lua_getfield(L, 2, "tag"); @@ -511,10 +571,10 @@ static int l_anim_get_marker(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); + animation* pAnimation = luaT_testuserdata(L); int iX = 0; int iY = 0; - pAnimation->getMarker(&iX, &iY); + pAnimation->get_marker(&iX, &iY); lua_pushinteger(L, iX); lua_pushinteger(L, iY); return 2; @@ -522,10 +582,10 @@ static int l_anim_get_secondary_marker(lua_State *L) { - THAnimation* pAnimation = luaT_testuserdata(L); + animation* pAnimation = luaT_testuserdata(L); int iX = 0; int iY = 0; - pAnimation->getSecondaryMarker(&iX, &iY); + pAnimation->get_secondary_marker(&iX, &iY); lua_pushinteger(L, iX); lua_pushinteger(L, iY); return 2; @@ -544,17 +604,17 @@ static int l_anim_draw(lua_State *L) { T* pAnimation = luaT_testuserdata(L); - THRenderTarget* pCanvas = luaT_testuserdata(L, 2); - pAnimation->draw(pCanvas, luaL_checkint(L, 3), luaL_checkint(L, 4)); + render_target* pCanvas = luaT_testuserdata(L, 2); + pAnimation->draw(pCanvas, static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4))); lua_settop(L, 1); return 1; } static int l_srl_set_sheet(lua_State *L) { - THSpriteRenderList *pSrl = luaT_testuserdata(L); - THSpriteSheet *pSheet = luaT_testuserdata(L, 2); - pSrl->setSheet(pSheet); + sprite_render_list *pSrl = luaT_testuserdata(L); + sprite_sheet *pSheet = luaT_testuserdata(L, 2); + pSrl->set_sheet(pSheet); lua_settop(L, 2); luaT_setenvfield(L, 1, "sheet"); @@ -563,40 +623,45 @@ static int l_srl_append(lua_State *L) { - THSpriteRenderList *pSrl = luaT_testuserdata(L); - pSrl->appendSprite((unsigned int)luaL_checkint(L, 2), - luaL_checkint(L, 3), luaL_checkint(L, 4)); + sprite_render_list *pSrl = luaT_testuserdata(L); + pSrl->append_sprite(luaL_checkinteger(L, 2), + static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4))); lua_settop(L, 1); return 1; } static int l_srl_set_lifetime(lua_State *L) { - THSpriteRenderList *pSrl = luaT_testuserdata(L); - pSrl->setLifetime(luaL_checkint(L, 2)); + sprite_render_list *pSrl = luaT_testuserdata(L); + pSrl->set_lifetime(static_cast(luaL_checkinteger(L, 2))); lua_settop(L, 1); return 1; } static int l_srl_is_dead(lua_State *L) { - THSpriteRenderList *pSrl = luaT_testuserdata(L); - lua_pushboolean(L, pSrl->isDead() ? 1 : 0); + sprite_render_list *pSrl = luaT_testuserdata(L); + lua_pushboolean(L, pSrl->is_dead() ? 1 : 0); return 1; } -void THLuaRegisterAnims(const THLuaRegisterState_t *pState) +void lua_register_anims(const lua_register_state *pState) { // Anims - luaT_class(THAnimationManager, l_anims_new, "anims", MT_Anims); + luaT_class(animation_manager, l_anims_new, "anims", lua_metatable::anims); luaT_setfunction(l_anims_load, "load"); - luaT_setfunction(l_anims_set_spritesheet, "setSheet", MT_Sheet); + luaT_setfunction(l_anims_loadcustom, "loadCustom"); + luaT_setfunction(l_anims_set_spritesheet, "setSheet", lua_metatable::sheet); + luaT_setfunction(l_anims_set_canvas, "setCanvas", lua_metatable::surface); + luaT_setfunction(l_anims_getanims, "getAnimations"); luaT_setfunction(l_anims_getfirst, "getFirstFrame"); luaT_setfunction(l_anims_getnext, "getNextFrame"); luaT_setfunction(l_anims_set_alt_pal, "setAnimationGhostPalette"); luaT_setfunction(l_anims_set_marker, "setFrameMarker"); luaT_setfunction(l_anims_set_secondary_marker, "setFrameSecondaryMarker"); - luaT_setfunction(l_anims_draw, "draw", MT_Surface, MT_Layers); + luaT_setfunction(l_anims_draw, "draw", lua_metatable::surface, lua_metatable::layers); + luaT_setconstant("Alt32_GreyScale", thdf_alt32_grey_scale); + luaT_setconstant("Alt32_BlueRedSwap", thdf_alt32_blue_red_swap); luaT_endclass(); // Weak table at AnimMetatable[1] for light UD -> object lookup @@ -606,7 +671,7 @@ lua_pushliteral(pState->L, "v"); lua_setfield(pState->L, -2, "__mode"); lua_setmetatable(pState->L, -2); - lua_rawseti(pState->L, pState->aiMetatables[MT_Anim], 1); + lua_rawseti(pState->L, pState->metatables[static_cast(lua_metatable::anim)], 1); // Weak table at AnimMetatable[2] for light UD -> full UD lookup // For persisting Map @@ -615,68 +680,68 @@ lua_pushliteral(pState->L, "v"); lua_setfield(pState->L, -2, "__mode"); lua_setmetatable(pState->L, -2); - lua_rawseti(pState->L, pState->aiMetatables[MT_Anim], 2); + lua_rawseti(pState->L, pState->metatables[static_cast(lua_metatable::anim)], 2); // Anim - luaT_class(THAnimation, l_anim_new, "animation", MT_Anim); - luaT_setmetamethod(l_anim_persist, "persist"); - luaT_setmetamethod(l_anim_pre_depersist, "pre_depersist"); - luaT_setmetamethod(l_anim_depersist, "depersist"); - luaT_setfunction(l_anim_set_anim, "setAnimation", MT_Anims); + luaT_class(animation, l_anim_new, "animation", lua_metatable::anim); + luaT_setmetamethod(l_anim_persist, "persist"); + luaT_setmetamethod(l_anim_pre_depersist, "pre_depersist"); + luaT_setmetamethod(l_anim_depersist, "depersist"); + luaT_setfunction(l_anim_set_anim, "setAnimation", lua_metatable::anims); luaT_setfunction(l_anim_set_crop, "setCrop"); luaT_setfunction(l_anim_get_crop, "getCrop"); luaT_setfunction(l_anim_set_morph, "setMorph"); luaT_setfunction(l_anim_set_frame, "setFrame"); luaT_setfunction(l_anim_get_frame, "getFrame"); luaT_setfunction(l_anim_get_anim, "getAnimation"); - luaT_setfunction(l_anim_set_tile, "setTile", MT_Map); + luaT_setfunction(l_anim_set_tile, "setTile", lua_metatable::map); luaT_setfunction(l_anim_get_tile, "getTile"); luaT_setfunction(l_anim_set_parent, "setParent"); - luaT_setfunction(l_anim_set_flag, "setFlag"); - luaT_setfunction(l_anim_set_flag_partial, "setPartialFlag"); - luaT_setfunction(l_anim_get_flag, "getFlag"); - luaT_setfunction(l_anim_make_visible, "makeVisible"); - luaT_setfunction(l_anim_make_invisible, "makeInvisible"); + luaT_setfunction(l_anim_set_flag, "setFlag"); + luaT_setfunction(l_anim_set_flag_partial, "setPartialFlag"); + luaT_setfunction(l_anim_get_flag, "getFlag"); + luaT_setfunction(l_anim_make_visible, "makeVisible"); + luaT_setfunction(l_anim_make_invisible, "makeInvisible"); luaT_setfunction(l_anim_set_tag, "setTag"); luaT_setfunction(l_anim_get_tag, "getTag"); - luaT_setfunction(l_anim_set_position, "setPosition"); + luaT_setfunction(l_anim_set_position, "setPosition"); luaT_setfunction(l_anim_get_position, "getPosition"); - luaT_setfunction(l_anim_set_speed, "setSpeed"); - luaT_setfunction(l_anim_set_layer, "setLayer"); + luaT_setfunction(l_anim_set_speed, "setSpeed"); + luaT_setfunction(l_anim_set_layer, "setLayer"); luaT_setfunction(l_anim_set_layers_from, "setLayersFrom"); luaT_setfunction(l_anim_set_hitresult, "setHitTestResult"); luaT_setfunction(l_anim_get_marker, "getMarker"); luaT_setfunction(l_anim_get_secondary_marker, "getSecondaryMarker"); - luaT_setfunction(l_anim_tick, "tick"); - luaT_setfunction(l_anim_draw, "draw", MT_Surface); + luaT_setfunction(l_anim_tick, "tick"); + luaT_setfunction(l_anim_draw, "draw", lua_metatable::surface); luaT_setfunction(l_anim_set_drawable_layer, "setDrawingLayer"); luaT_endclass(); // Duplicate AnimMetatable[1,2] to SpriteListMetatable[1,2] - lua_rawgeti(pState->L, pState->aiMetatables[MT_Anim], 1); - lua_rawseti(pState->L, pState->aiMetatables[MT_SpriteList], 1); - lua_rawgeti(pState->L, pState->aiMetatables[MT_Anim], 2); - lua_rawseti(pState->L, pState->aiMetatables[MT_SpriteList], 2); + lua_rawgeti(pState->L, pState->metatables[static_cast(lua_metatable::anim)], 1); + lua_rawseti(pState->L, pState->metatables[static_cast(lua_metatable::sprite_list)], 1); + lua_rawgeti(pState->L, pState->metatables[static_cast(lua_metatable::anim)], 2); + lua_rawseti(pState->L, pState->metatables[static_cast(lua_metatable::sprite_list)], 2); // SpriteList - luaT_class(THSpriteRenderList, l_anim_new, "spriteList", MT_SpriteList); - luaT_setmetamethod(l_anim_persist, "persist"); - luaT_setmetamethod(l_anim_pre_depersist, "pre_depersist"); - luaT_setmetamethod(l_anim_depersist, "depersist"); - luaT_setfunction(l_srl_set_sheet, "setSheet", MT_Sheet); + luaT_class(sprite_render_list, l_anim_new, "spriteList", lua_metatable::sprite_list); + luaT_setmetamethod(l_anim_persist, "persist"); + luaT_setmetamethod(l_anim_pre_depersist, "pre_depersist"); + luaT_setmetamethod(l_anim_depersist, "depersist"); + luaT_setfunction(l_srl_set_sheet, "setSheet", lua_metatable::sheet); luaT_setfunction(l_srl_append, "append"); luaT_setfunction(l_srl_set_lifetime, "setLifetime"); luaT_setfunction(l_srl_is_dead, "isDead"); - luaT_setfunction(l_anim_set_tile, "setTile", MT_Map); - luaT_setfunction(l_anim_set_flag, "setFlag"); - luaT_setfunction(l_anim_set_flag_partial, "setPartialFlag"); - luaT_setfunction(l_anim_get_flag, "getFlag"); - luaT_setfunction(l_anim_make_visible, "makeVisible"); - luaT_setfunction(l_anim_make_invisible, "makeInvisible"); - luaT_setfunction(l_anim_set_position, "setPosition"); - luaT_setfunction(l_anim_set_speed, "setSpeed"); - luaT_setfunction(l_anim_set_layer, "setLayer"); - luaT_setfunction(l_anim_tick, "tick"); - luaT_setfunction(l_anim_draw, "draw", MT_Surface); + luaT_setfunction(l_anim_set_tile, "setTile", lua_metatable::map); + luaT_setfunction(l_anim_set_flag, "setFlag"); + luaT_setfunction(l_anim_set_flag_partial, "setPartialFlag"); + luaT_setfunction(l_anim_get_flag, "getFlag"); + luaT_setfunction(l_anim_make_visible, "makeVisible"); + luaT_setfunction(l_anim_make_invisible, "makeInvisible"); + luaT_setfunction(l_anim_set_position, "setPosition"); + luaT_setfunction(l_anim_set_speed, "setSpeed"); + luaT_setfunction(l_anim_set_layer, "setLayer"); + luaT_setfunction(l_anim_tick, "tick"); + luaT_setfunction(l_anim_draw, "draw", lua_metatable::surface); luaT_endclass(); } diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua.cpp corsix-th-0.62/CorsixTH/Src/th_lua.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -23,15 +23,18 @@ #include "th.h" #include "th_lua_internal.h" #include "bootstrap.h" -#include - -void THLuaRegisterAnims(const THLuaRegisterState_t *pState); -void THLuaRegisterGfx(const THLuaRegisterState_t *pState); -void THLuaRegisterMap(const THLuaRegisterState_t *pState); -void THLuaRegisterSound(const THLuaRegisterState_t *pState); -void THLuaRegisterMovie(const THLuaRegisterState_t *pState); -void THLuaRegisterStrings(const THLuaRegisterState_t *pState); -void THLuaRegisterUI(const THLuaRegisterState_t *pState); +#include +#include +#include + +void lua_register_anims(const lua_register_state *pState); +void lua_register_gfx(const lua_register_state *pState); +void lua_register_map(const lua_register_state *pState); +void lua_register_sound(const lua_register_state *pState); +void lua_register_movie(const lua_register_state *pState); +void lua_register_strings(const lua_register_state *pState); +void lua_register_ui(const lua_register_state *pState); +void lua_register_lfs_ext(const lua_register_state *pState); //! Set a field on the environment table of an object void luaT_setenvfield(lua_State *L, int index, const char *k) @@ -58,22 +61,22 @@ switch(iType) { case LUA_TUSERDATA: - lua_getenv(L, iIndex); + lua_getuservalue(L, iIndex); break; case LUA_TFUNCTION: if(lua_iscfunction(L, iIndex)) { // Our convention: upvalue at #1 is environment - if(lua_getupvalue(L, iIndex, 1) == NULL) + if(lua_getupvalue(L, iIndex, 1) == nullptr) lua_pushglobaltable(L); } else { // Language convention: upvalue called _ENV is environment - const char* sUpName = NULL; + const char* sUpName = nullptr; for(int i = 1; (sUpName = lua_getupvalue(L, iIndex, i)) ; ++i) { - if(strcmp(sUpName, "_ENV") == 0) + if(std::strcmp(sUpName, "_ENV") == 0) return; else lua_pop(L, 1); @@ -93,13 +96,13 @@ switch(iType) { case LUA_TUSERDATA: - lua_setenv(L, iIndex); + lua_setuservalue(L, iIndex); return 1; case LUA_TFUNCTION: if(lua_iscfunction(L, iIndex)) { // Our convention: upvalue at #1 is environment - if(lua_setupvalue(L, iIndex, 1) == NULL) + if(lua_setupvalue(L, iIndex, 1) == nullptr) { lua_pop(L, 1); return 0; @@ -110,10 +113,11 @@ { // Language convention: upvalue called _ENV is environment, which // might be shared with other functions. - const char* sUpName = NULL; + const char* sUpName = nullptr; for(int i = 1; (sUpName = lua_getupvalue(L, iIndex, i)) ; ++i) { - if(strcmp(sUpName, "_ENV") == 0) + lua_pop(L, 1); // lua_getupvalue puts the value on the stack, but we just want to replace it + if(std::strcmp(sUpName, "_ENV") == 0) { luaL_loadstring(L, "local upv = ... return function() return upv end"); lua_insert(L, -2); @@ -122,24 +126,14 @@ lua_pop(L, 1); return 1; } - else - lua_pop(L, 1); } + lua_pop(L, 1); return 0; } default: return 0; } } - -void luaT_pushcclosure(lua_State* L, lua_CFunction f, int nups) -{ - ++nups; - lua_pushvalue(L, luaT_environindex); - lua_insert(L, -nups); - lua_pushcclosure(L, f, nups); -} - #endif //! Push a C closure as a callable table @@ -155,29 +149,19 @@ lua_setmetatable(L, -2); // .. t (lua_touserdata(L, idx)); iLength = lua_objlen(L, idx); } else { - pData = (const unsigned char*)luaL_checklstring(L, idx, &iLength); + pData = reinterpret_cast(luaL_checklstring(L, idx, &iLength)); } if(pDataLen != 0) *pDataLen = iLength; @@ -187,27 +171,28 @@ static int l_load_strings(lua_State *L) { size_t iDataLength; - const unsigned char* pData = luaT_checkfile(L, 1, &iDataLength); - - THStringList oStrings; - if(!oStrings.loadFromTHFile(pData, iDataLength)) - { - lua_pushboolean(L, 0); - return 1; - } + const uint8_t* pData = luaT_checkfile(L, 1, &iDataLength); - lua_settop(L, 0); - lua_createtable(L, (int)oStrings.getSectionCount(), 0); - for(unsigned int iSec = 0; iSec < oStrings.getSectionCount(); ++iSec) + try { - unsigned int iCount = oStrings.getSectionSize(iSec); - lua_createtable(L, (int)iCount, 0); - for(unsigned int iStr = 0; iStr < iCount; ++iStr) + th_string_list oStrings(pData, iDataLength); + lua_settop(L, 0); + lua_createtable(L, static_cast(oStrings.get_section_count()), 0); + for(size_t iSec = 0; iSec < oStrings.get_section_count(); ++iSec) { - lua_pushstring(L, oStrings.getString(iSec, iStr)); - lua_rawseti(L, 2, (int)(iStr + 1)); + size_t iCount = oStrings.get_section_size(iSec); + lua_createtable(L, static_cast(iCount), 0); + for(size_t iStr = 0; iStr < iCount; ++iStr) + { + lua_pushstring(L, oStrings.get_string(iSec, iStr)); + lua_rawseti(L, 2, static_cast(iStr + 1)); + } + lua_rawseti(L, 1, static_cast(iSec + 1)); } - lua_rawseti(L, 1, (int)(iSec + 1)); + } + catch(std::invalid_argument) + { + lua_pushboolean(L, 0); } return 1; } @@ -229,15 +214,7 @@ #endif lua_setfield(L, -2, "arch_64"); -#if defined(CORSIX_TH_USE_OGL_RENDERER) - lua_pushliteral(L, "OpenGL"); -#elif defined(CORSIX_TH_USE_DX9_RENDERER) - lua_pushliteral(L, "DirectX 9"); -#elif defined(CORSIX_TH_USE_SDL_RENDERER) lua_pushliteral(L, "SDL"); -#else - lua_pushliteral(L, "Unknown"); -#endif lua_setfield(L, -2, "renderer"); #ifdef CORSIX_TH_USE_SDL_MIXER @@ -267,58 +244,44 @@ return 1; } -void luaT_setclosure(const THLuaRegisterState_t *pState, lua_CFunction fn, - eTHLuaMetatable eMetatable1, ...) -{ - int iUpCount = 0; - va_list args; - for(va_start(args, eMetatable1); - eMetatable1 != MT_Count; - eMetatable1 = static_cast(va_arg(args, int))) - { - if(eMetatable1 == MT_DummyString) - lua_pushstring(pState->L, va_arg(args, char*)); - else - lua_pushvalue(pState->L, pState->aiMetatables[eMetatable1]); - ++iUpCount; - } - va_end(args); - luaT_pushcclosure(pState->L, fn, iUpCount); +void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t iUps) { + luaT_pushcclosure(pState->L, fn, iUps); } int luaopen_th(lua_State *L) { lua_settop(L, 0); - lua_checkstack(L, 16 + static_cast(MT_Count)); + lua_checkstack(L, 16 + static_cast(lua_metatable::count)); - THLuaRegisterState_t oState; - const THLuaRegisterState_t *pState = &oState; + lua_register_state oState; + const lua_register_state *pState = &oState; oState.L = L; - for(int i = 0; i < static_cast(MT_Count); ++i) + for(int i = 0; i < static_cast(lua_metatable::count); ++i) { lua_createtable(L, 0, 5); - oState.aiMetatables[i] = lua_gettop(L); + oState.metatables[i] = lua_gettop(L); } lua_createtable(L, 0, lua_gettop(L)); - oState.iMainTable = lua_gettop(L); - oState.iTop = lua_gettop(L); + oState.main_table = lua_gettop(L); + oState.top = lua_gettop(L); // Misc. functions - lua_settop(L, oState.iTop); + lua_settop(L, oState.top); luaT_setfunction(l_load_strings, "LoadStrings"); luaT_setfunction(l_get_compile_options, "GetCompileOptions"); - luaT_setfunction(Bootstrap_lua_resources, "GetBuiltinFont"); + luaT_setfunction(bootstrap_lua_resources, "GetBuiltinFont"); // Classes - THLuaRegisterMap(pState); - THLuaRegisterGfx(pState); - THLuaRegisterAnims(pState); - THLuaRegisterSound(pState); - THLuaRegisterMovie(pState); - THLuaRegisterStrings(pState); - THLuaRegisterUI(pState); + lua_register_map(pState); + lua_register_gfx(pState); + lua_register_anims(pState); + lua_register_sound(pState); + lua_register_movie(pState); + lua_register_strings(pState); + lua_register_ui(pState); + lua_register_lfs_ext(pState); - lua_settop(L, oState.iMainTable); + lua_settop(L, oState.main_table); return 1; } @@ -340,6 +303,15 @@ lua_error(L); } lua_pop(L, 1); +#if LUA_VERSION_NUM >= 502 + luaL_loadstring(L, "local assert, load = assert, load\n" + "return setmetatable({}, {__mode = [[v]], \n" + "__index = function(t, k)\n" + "local v = assert(load(k))\n" + "t[k] = v\n" + "return v\n" + "end})"); +#else luaL_loadstring(L, "local assert, loadstring = assert, loadstring\n" "return setmetatable({}, {__mode = [[v]], \n" "__index = function(t, k)\n" @@ -347,6 +319,7 @@ "t[k] = v\n" "return v\n" "end})"); +#endif lua_call(L, 0, 1); lua_pushvalue(L, -1); lua_rawseti(L, LUA_REGISTRYINDEX, iRegistryCacheIndex); @@ -375,3 +348,71 @@ { lua_pushstring(L, s); } + +void luaT_pushtablebool(lua_State *L, const char *k, bool v) +{ + lua_pushstring(L, k); + lua_pushboolean(L, v); + lua_settable(L, -3); +} + +void luaT_printstack(lua_State* L) +{ + int i; + int top = lua_gettop(L); + + std::printf("total items in stack %d\n", top); + + for (i = 1; i <= top; i++) + { /* repeat for each level */ + int t = lua_type(L, i); + switch (t) { + case LUA_TSTRING: /* strings */ + std::printf("string: '%s'\n", lua_tostring(L, i)); + break; + case LUA_TBOOLEAN: /* booleans */ + std::printf("boolean %s\n", lua_toboolean(L, i) ? "true" : "false"); + break; + case LUA_TNUMBER: /* numbers */ + std::printf("number: %g\n", lua_tonumber(L, i)); + break; + default: /* other values */ + std::printf("%s\n", lua_typename(L, t)); + break; + } + std::printf(" "); /* put a separator */ + + } + std::printf("\n"); /* end the listing */ +} + +void luaT_printrawtable(lua_State* L, int idx) +{ + int i; + int len = static_cast(lua_objlen(L, idx)); + + std::printf("total items in table %d\n", len); + + for (i = 1; i <= len; i++) + { + lua_rawgeti(L, idx, i); + int t = lua_type(L, -1); + switch (t) { + case LUA_TSTRING: /* strings */ + std::printf("string: '%s'\n", lua_tostring(L, -1)); + break; + case LUA_TBOOLEAN: /* booleans */ + std::printf("boolean %s\n", lua_toboolean(L, -1) ? "true" : "false"); + break; + case LUA_TNUMBER: /* numbers */ + std::printf("number: %g\n", lua_tonumber(L, -1)); + break; + default: /* other values */ + std::printf("%s\n", lua_typename(L, t)); + break; + } + std::printf(" "); /* put a separator */ + lua_pop(L, 1); + } + std::printf("\n"); /* end the listing */ +} diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_gfx.cpp corsix-th-0.62/CorsixTH/Src/th_lua_gfx.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua_gfx.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_gfx.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -23,21 +23,21 @@ #include "th_lua_internal.h" #include "th_gfx.h" #include -#include +#include static int l_palette_new(lua_State *L) { - luaT_stdnew(L); + luaT_stdnew(L); return 1; } static int l_palette_load(lua_State *L) { - THPalette* pPalette = luaT_testuserdata(L); + palette* pPalette = luaT_testuserdata(L); size_t iDataLen; - const unsigned char* pData = luaT_checkfile(L, 2, &iDataLen); + const uint8_t* pData = luaT_checkfile(L, 2, &iDataLen); - if(pPalette->loadFromTHFile(pData, iDataLen)) + if(pPalette->load_from_th_file(pData, iDataLen)) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); @@ -46,8 +46,8 @@ static int l_palette_set_entry(lua_State *L) { - THPalette* pPalette = luaT_testuserdata(L); - lua_pushboolean(L, pPalette->setEntry(luaL_checkint(L, 2), + palette* pPalette = luaT_testuserdata(L); + lua_pushboolean(L, pPalette->set_entry(static_cast(luaL_checkinteger(L, 2)), static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4)), static_cast(luaL_checkinteger(L, 5))) @@ -57,30 +57,30 @@ static int l_rawbitmap_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_rawbitmap_set_pal(lua_State *L) { - THRawBitmap* pBitmap = luaT_testuserdata(L); - THPalette* pPalette = luaT_testuserdata(L, 2); + raw_bitmap* pBitmap = luaT_testuserdata(L); + palette* pPalette = luaT_testuserdata(L, 2); lua_settop(L, 2); - pBitmap->setPalette(pPalette); + pBitmap->set_palette(pPalette); luaT_setenvfield(L, 1, "palette"); return 1; } static int l_rawbitmap_load(lua_State *L) { - THRawBitmap* pBitmap = luaT_testuserdata(L); + raw_bitmap* pBitmap = luaT_testuserdata(L); size_t iDataLen; - const unsigned char* pData = luaT_checkfile(L, 2, &iDataLen); - int iWidth = luaL_checkint(L, 3); - THRenderTarget* pSurface = luaT_testuserdata(L, 4, luaT_upvalueindex(1), false); + const uint8_t* pData = luaT_checkfile(L, 2, &iDataLen); + int iWidth = static_cast(luaL_checkinteger(L, 3)); + render_target* pSurface = luaT_testuserdata(L, 4, luaT_upvalueindex(1), false); - if(pBitmap->loadFromTHFile(pData, iDataLen, iWidth, pSurface)) + if(pBitmap->load_from_th_file(pData, iDataLen, iWidth, pSurface)) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); @@ -90,17 +90,17 @@ static int l_rawbitmap_draw(lua_State *L) { - THRawBitmap* pBitmap = luaT_testuserdata(L); - THRenderTarget* pCanvas = luaT_testuserdata(L, 2); + raw_bitmap* pBitmap = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L, 2); if(lua_gettop(L) >= 8) { - pBitmap->draw(pCanvas, luaL_checkint(L, 3), luaL_checkint(L, 4), - luaL_checkint(L, 5), luaL_checkint(L, 6), luaL_checkint(L, 7), - luaL_checkint(L, 8)); + pBitmap->draw(pCanvas, static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4)), + static_cast(luaL_checkinteger(L, 5)), static_cast(luaL_checkinteger(L, 6)), static_cast(luaL_checkinteger(L, 7)), + static_cast(luaL_checkinteger(L, 8))); } else - pBitmap->draw(pCanvas, luaL_optint(L, 3, 0), luaL_optint(L, 4, 0)); + pBitmap->draw(pCanvas, static_cast(luaL_optinteger(L, 3, 0)), static_cast(luaL_optinteger(L, 4, 0))); lua_settop(L, 1); return 1; @@ -108,31 +108,31 @@ static int l_spritesheet_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_spritesheet_set_pal(lua_State *L) { - THSpriteSheet* pSheet = luaT_testuserdata(L); - THPalette* pPalette = luaT_testuserdata(L, 2); + sprite_sheet* pSheet = luaT_testuserdata(L); + palette* pPalette = luaT_testuserdata(L, 2); lua_settop(L, 2); - pSheet->setPalette(pPalette); + pSheet->set_palette(pPalette); luaT_setenvfield(L, 1, "palette"); return 1; } static int l_spritesheet_load(lua_State *L) { - THSpriteSheet* pSheet = luaT_testuserdata(L); + sprite_sheet* pSheet = luaT_testuserdata(L); size_t iDataLenTable, iDataLenChunk; - const unsigned char* pDataTable = luaT_checkfile(L, 2, &iDataLenTable); - const unsigned char* pDataChunk = luaT_checkfile(L, 3, &iDataLenChunk); + const uint8_t* pDataTable = luaT_checkfile(L, 2, &iDataLenTable); + const uint8_t* pDataChunk = luaT_checkfile(L, 3, &iDataLenChunk); bool bComplex = lua_toboolean(L, 4) != 0; - THRenderTarget* pSurface = luaT_testuserdata(L, 5, luaT_upvalueindex(1), false); + render_target* pSurface = luaT_testuserdata(L, 5, luaT_upvalueindex(1), false); - if(pSheet->loadFromTHFile(pDataTable, iDataLenTable, pDataChunk, iDataLenChunk, bComplex, pSurface)) + if(pSheet->load_from_th_file(pDataTable, iDataLenTable, pDataChunk, iDataLenChunk, bComplex, pSurface)) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); @@ -142,21 +142,21 @@ static int l_spritesheet_count(lua_State *L) { - THSpriteSheet* pSheet = luaT_testuserdata(L); + sprite_sheet* pSheet = luaT_testuserdata(L); - lua_pushinteger(L, pSheet->getSpriteCount()); + lua_pushinteger(L, pSheet->get_sprite_count()); return 1; } static int l_spritesheet_size(lua_State *L) { - THSpriteSheet* pSheet = luaT_testuserdata(L); - int iSprite = luaL_checkint(L, 2); // No array adjustment - if(iSprite < 0 || (unsigned int)iSprite >= pSheet->getSpriteCount()) + sprite_sheet* pSheet = luaT_testuserdata(L); + size_t iSprite = luaL_checkinteger(L, 2); // No array adjustment + if(iSprite < 0 || iSprite >= pSheet->get_sprite_count()) return luaL_argerror(L, 2, "Sprite index out of bounds"); unsigned int iWidth, iHeight; - pSheet->getSpriteSizeUnchecked((unsigned int)iSprite, &iWidth, &iHeight); + pSheet->get_sprite_size_unchecked(iSprite, &iWidth, &iHeight); lua_pushinteger(L, iWidth); lua_pushinteger(L, iHeight); @@ -165,11 +165,11 @@ static int l_spritesheet_draw(lua_State *L) { - THSpriteSheet* pSheet = luaT_testuserdata(L); - THRenderTarget* pCanvas = luaT_testuserdata(L, 2); - int iSprite = luaL_checkint(L, 3); // No array adjustment + sprite_sheet* pSheet = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L, 2); + int iSprite = static_cast(luaL_checkinteger(L, 3)); // No array adjustment - pSheet->drawSprite(pCanvas, iSprite, luaL_optint(L, 4, 0), luaL_optint(L, 5, 0), luaL_optint(L, 6, 0)); + pSheet->draw_sprite(pCanvas, iSprite, static_cast(luaL_optinteger(L, 4, 0)), static_cast(luaL_optinteger(L, 5, 0)), static_cast(luaL_optinteger(L, 6, 0))); lua_settop(L, 1); return 1; @@ -177,20 +177,20 @@ static int l_spritesheet_hittest(lua_State *L) { - THSpriteSheet* pSheet = luaT_testuserdata(L); - unsigned int iSprite = (unsigned int)luaL_checkinteger(L, 2); - int iX = luaL_checkint(L, 3); - int iY = luaL_checkint(L, 4); - unsigned long iFlags = (unsigned long)luaL_optint(L, 5, 0); - return pSheet->hitTestSprite(iSprite, iX, iY, iFlags); + sprite_sheet* pSheet = luaT_testuserdata(L); + size_t iSprite = luaL_checkinteger(L, 2); + int iX = static_cast(luaL_checkinteger(L, 3)); + int iY = static_cast(luaL_checkinteger(L, 4)); + uint32_t iFlags = static_cast(luaL_optinteger(L, 5, 0)); + return pSheet->hit_test_sprite(iSprite, iX, iY, iFlags); } static int l_spritesheet_isvisible(lua_State *L) { - THSpriteSheet* pSheet = luaT_testuserdata(L); - unsigned int iSprite = (unsigned int)luaL_checkinteger(L, 2); - THColour oDummy; - lua_pushboolean(L, pSheet->getSpriteAverageColour(iSprite, &oDummy) ? 1:0); + sprite_sheet* pSheet = luaT_testuserdata(L); + size_t iSprite = luaL_checkinteger(L, 2); + argb_colour oDummy; + lua_pushboolean(L, pSheet->get_sprite_average_colour(iSprite, &oDummy) ? 1:0); return 1; } @@ -201,33 +201,33 @@ static int l_bitmap_font_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_bitmap_font_set_spritesheet(lua_State *L) { - THBitmapFont* pFont = luaT_testuserdata(L); - THSpriteSheet* pSheet = luaT_testuserdata(L, 2); + bitmap_font* pFont = luaT_testuserdata(L); + sprite_sheet* pSheet = luaT_testuserdata(L, 2); lua_settop(L, 2); - pFont->setSpriteSheet(pSheet); + pFont->set_sprite_sheet(pSheet); luaT_setenvfield(L, 1, "sprites"); return 1; } static int l_bitmap_font_get_spritesheet(lua_State *L) { - luaT_testuserdata(L); + luaT_testuserdata(L); luaT_getenvfield(L, 1, "sprites"); return 1; } static int l_bitmap_font_set_sep(lua_State *L) { - THBitmapFont* pFont = luaT_testuserdata(L); + bitmap_font* pFont = luaT_testuserdata(L); - pFont->setSeparation(luaL_checkint(L, 2), luaL_optint(L, 3, 0)); + pFont->set_separation(static_cast(luaL_checkinteger(L, 2)), static_cast(luaL_optinteger(L, 3, 0))); lua_settop(L, 1); return 1; @@ -255,7 +255,7 @@ static int l_freetype_font_new(lua_State *L) { - THFreeTypeFont *pFont = luaT_stdnew(L, LUA_ENVIRONINDEX, + freetype_font *pFont = luaT_stdnew(L, luaT_environindex, true); l_freetype_throw_error_code(L, pFont->initialise()); return 1; @@ -263,183 +263,207 @@ static int l_freetype_font_set_spritesheet(lua_State *L) { - THFreeTypeFont* pFont = luaT_testuserdata(L); - THSpriteSheet* pSheet = luaT_testuserdata(L, 2); + freetype_font* pFont = luaT_testuserdata(L); + sprite_sheet* pSheet = luaT_testuserdata(L, 2); lua_settop(L, 2); - l_freetype_throw_error_code(L, pFont->matchBitmapFont(pSheet)); + l_freetype_throw_error_code(L, pFont->match_bitmap_font(pSheet)); lua_settop(L, 1); return 1; } static int l_freetype_font_get_copyright(lua_State *L) { - lua_pushstring(L, THFreeTypeFont::getCopyrightNotice()); + lua_pushstring(L, freetype_font::get_copyright_notice()); return 1; } static int l_freetype_font_set_face(lua_State *L) { - THFreeTypeFont* pFont = luaT_testuserdata(L); + freetype_font* pFont = luaT_testuserdata(L); size_t iLength; - const unsigned char* pData = luaT_checkfile(L, 2, &iLength); + const uint8_t* pData = luaT_checkfile(L, 2, &iLength); lua_settop(L, 2); - l_freetype_throw_error_code(L, pFont->setFace(pData, iLength)); + l_freetype_throw_error_code(L, pFont->set_face(pData, iLength)); luaT_setenvfield(L, 1, "face"); return 1; } + +static int l_freetype_font_clear_cache(lua_State *L) +{ + freetype_font* pFont = luaT_testuserdata(L); + pFont->clear_cache(); + return 0; +} + #endif static int l_font_get_size(lua_State *L) { - THFont* pFont = luaT_testuserdata(L); + font* pFont = luaT_testuserdata(L); size_t iMsgLen; const char* sMsg = luaT_checkstring(L, 2, &iMsgLen); - int iWidth, iHeight; - pFont->getTextSize(sMsg, iMsgLen, &iWidth, &iHeight); + int iMaxWidth = INT_MAX; + if(!lua_isnoneornil(L, 3)) + iMaxWidth = static_cast(luaL_checkinteger(L, 3)); - lua_pushinteger(L, iWidth); - lua_pushinteger(L, iHeight); - return 2; + text_layout oDrawArea = pFont->get_text_dimensions(sMsg, iMsgLen, iMaxWidth); + + lua_pushinteger(L, oDrawArea.end_x); + lua_pushinteger(L, oDrawArea.end_y); + lua_pushinteger(L, oDrawArea.row_count); + + return 3; } static int l_font_draw(lua_State *L) { - THFont* pFont = luaT_testuserdata(L); - THRenderTarget* pCanvas = NULL; + font* pFont = luaT_testuserdata(L); + render_target* pCanvas = nullptr; if(!lua_isnoneornil(L, 2)) { - pCanvas = luaT_testuserdata(L, 2); + pCanvas = luaT_testuserdata(L, 2); } size_t iMsgLen; const char* sMsg = luaT_checkstring(L, 3, &iMsgLen); - int iX = luaL_checkint(L, 4); - int iY = luaL_checkint(L, 5); - eTHAlign eAlign = Align_Center; - if(!lua_isnoneornil(L, 8)) - { + int iX = static_cast(luaL_checkinteger(L, 4)); + int iY = static_cast(luaL_checkinteger(L, 5)); + + text_alignment eAlign = text_alignment::center; + if(!lua_isnoneornil(L, 8)) { const char* sAlign = luaL_checkstring(L, 8); - if(strcmp(sAlign, "right") == 0) - eAlign = Align_Right; - else if(strcmp(sAlign, "left") == 0) - eAlign = Align_Left; - else if(strcmp(sAlign, "center") == 0 - || strcmp(sAlign, "centre") == 0 - || strcmp(sAlign, "middle") == 0) - { - eAlign = Align_Center; - } - else + if(std::strcmp(sAlign, "right") == 0) { + eAlign = text_alignment::right; + } else if(std::strcmp(sAlign, "left") == 0) { + eAlign = text_alignment::left; + } else if(std::strcmp(sAlign, "center") == 0 || + std::strcmp(sAlign, "centre") == 0 || + std::strcmp(sAlign, "middle") == 0) { + eAlign = text_alignment::center; + } else { return luaL_error(L, "Invalid alignment: \"%s\"", sAlign); + } } - int iWidth, iHeight; - pFont->getTextSize(sMsg, iMsgLen, &iWidth, &iHeight); + + text_layout oDrawArea = pFont->get_text_dimensions(sMsg, iMsgLen); if(!lua_isnoneornil(L, 7)) { - int iW = luaL_checkint(L, 6); - int iH = luaL_checkint(L, 7); - if(iW > iWidth && eAlign != Align_Left) - iX += (iW - iWidth) / ((eAlign == Align_Center) ? 2 : 1); - if(iH > iHeight) - iY += (iH - iHeight) / 2; + int iW = static_cast(luaL_checkinteger(L, 6)); + int iH = static_cast(luaL_checkinteger(L, 7)); + if(iW > oDrawArea.end_x && eAlign != text_alignment::left) { + iX += (iW - oDrawArea.end_x) / ((eAlign == text_alignment::center) ? 2 : 1); + } + if(iH > oDrawArea.end_y) { + iY += (iH - oDrawArea.end_y) / 2; + } } - if(pCanvas != NULL) + if(pCanvas != nullptr) { - pFont->drawText(pCanvas, sMsg, iMsgLen, iX, iY); + pFont->draw_text(pCanvas, sMsg, iMsgLen, iX, iY); } - lua_pushinteger(L, iY + iHeight); - lua_pushinteger(L, iX + iWidth); + lua_pushinteger(L, iY + oDrawArea.end_y); + lua_pushinteger(L, iX + oDrawArea.end_x); return 2; } static int l_font_draw_wrapped(lua_State *L) { - THFont* pFont = luaT_testuserdata(L); - THRenderTarget* pCanvas = NULL; + font* pFont = luaT_testuserdata(L); + render_target* pCanvas = nullptr; if(!lua_isnoneornil(L, 2)) { - pCanvas = luaT_testuserdata(L, 2); + pCanvas = luaT_testuserdata(L, 2); } size_t iMsgLen; const char* sMsg = luaT_checkstring(L, 3, &iMsgLen); - int iX = luaL_checkint(L, 4); - int iY = luaL_checkint(L, 5); - int iW = luaL_checkint(L, 6); - eTHAlign eAlign = Align_Left; - if(!lua_isnoneornil(L, 7)) - { + int iX = static_cast(luaL_checkinteger(L, 4)); + int iY = static_cast(luaL_checkinteger(L, 5)); + int iW = static_cast(luaL_checkinteger(L, 6)); + + text_alignment eAlign = text_alignment::left; + if(!lua_isnoneornil(L, 7)) { const char* sAlign = luaL_checkstring(L, 7); - if(strcmp(sAlign, "right") == 0) - eAlign = Align_Right; - else if(strcmp(sAlign, "left") == 0) - eAlign = Align_Left; - else if(strcmp(sAlign, "center") == 0 - || strcmp(sAlign, "centre") == 0 - || strcmp(sAlign, "middle") == 0) - { - eAlign = Align_Center; - } - else + if(std::strcmp(sAlign, "right") == 0) { + eAlign = text_alignment::right; + } else if(std::strcmp(sAlign, "left") == 0) { + eAlign = text_alignment::left; + } else if(std::strcmp(sAlign, "center") == 0 || + std::strcmp(sAlign, "centre") == 0 || + std::strcmp(sAlign, "middle") == 0) { + eAlign = text_alignment::center; + } else { return luaL_error(L, "Invalid alignment: \"%s\"", sAlign); + } + } + + int iMaxRows = INT_MAX; + if(!lua_isnoneornil(L, 8)) + { + iMaxRows = static_cast(luaL_checkinteger(L, 8)); } - int iLastX; - int iLastY = pFont->drawTextWrapped(pCanvas, sMsg, iMsgLen, iX, iY, - iW, NULL, &iLastX, eAlign); - lua_pushinteger(L, iLastY); - lua_pushinteger(L, iLastX); + int iSkipRows = 0; + if(!lua_isnoneornil(L, 9)) + { + iSkipRows = static_cast(luaL_checkinteger(L, 9)); + } - return 2; + text_layout oDrawArea = pFont->draw_text_wrapped(pCanvas, sMsg, iMsgLen, iX, iY, + iW, iMaxRows, iSkipRows, eAlign); + lua_pushinteger(L, oDrawArea.end_y); + lua_pushinteger(L, oDrawArea.end_x); + lua_pushinteger(L, oDrawArea.row_count); + + return 3; } static int l_font_draw_tooltip(lua_State *L) { - THFont* pFont = luaT_testuserdata(L); - THRenderTarget* pCanvas = luaT_testuserdata(L, 2); + font* pFont = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L, 2); size_t iMsgLen; const char* sMsg = luaT_checkstring(L, 3, &iMsgLen); - int iX = luaL_checkint(L, 4); - int iY = luaL_checkint(L, 5); - int iScreenWidth = pCanvas->getWidth(); + int iX = static_cast(luaL_checkinteger(L, 4)); + int iY = static_cast(luaL_checkinteger(L, 5)); + int iScreenWidth = pCanvas->get_width(); int iW = 200; // (for now) hardcoded width of tooltips - int iRealW; - uint32_t iBlack = pCanvas->mapColour(0x00, 0x00, 0x00); - uint32_t iWhite = pCanvas->mapColour(0xFF, 0xFF, 0xFF); - int iLastY = pFont->drawTextWrapped(NULL, sMsg, iMsgLen, iX + 2, iY + 1, iW - 4, &iRealW); - int iLastX = iX + iRealW + 3; - int iFirstY = iY - (iLastY - iY) - 1; + uint32_t iBlack = pCanvas->map_colour(0x00, 0x00, 0x00); + uint32_t iWhite = pCanvas->map_colour(0xFF, 0xFF, 0xFF); + text_layout oArea = pFont->draw_text_wrapped(nullptr, sMsg, iMsgLen, iX + 2, iY + 1, iW - 4, INT_MAX, 0); + int iLastX = iX + oArea.width + 3; + int iFirstY = iY - (oArea.end_y - iY) - 1; int iXOffset = iLastX > iScreenWidth ? iScreenWidth - iLastX : 0; int iYOffset = iFirstY < 0 ? -iFirstY : 0; - pCanvas->fillRect(iBlack, iX + iXOffset, iFirstY + iYOffset, iRealW + 3, iLastY - iY + 2); - pCanvas->fillRect(iWhite, iX + iXOffset + 1, iFirstY + 1 + iYOffset, iRealW + 1, iLastY - iY); + pCanvas->fill_rect(iBlack, iX + iXOffset, iFirstY + iYOffset, oArea.width + 3, oArea.end_y - iY + 2); + pCanvas->fill_rect(iWhite, iX + iXOffset + 1, iFirstY + 1 + iYOffset, oArea.width + 1, oArea.end_y - iY); - pFont->drawTextWrapped(pCanvas, sMsg, iMsgLen, iX + 2 + iXOffset, iFirstY + 1 + iYOffset, iW - 4); + pFont->draw_text_wrapped(pCanvas, sMsg, iMsgLen, iX + 2 + iXOffset, iFirstY + 1 + iYOffset, iW - 4); - lua_pushinteger(L, iLastY); + lua_pushinteger(L, oArea.end_y); return 1; } static int l_layers_new(lua_State *L) { - THLayers_t* pLayers = luaT_stdnew(L, luaT_environindex, false); + layers* pLayers = luaT_stdnew(L, luaT_environindex, false); for(int i = 0; i < 13; ++i) - pLayers->iLayerContents[i] = 0; + pLayers->layer_contents[i] = 0; return 1; } static int l_layers_get(lua_State *L) { - THLayers_t* pLayers = luaT_testuserdata(L); - int iLayer = luaL_checkint(L, 2); + layers* pLayers = luaT_testuserdata(L); + lua_Integer iLayer = luaL_checkinteger(L, 2); if(0 <= iLayer && iLayer < 13) - lua_pushinteger(L, pLayers->iLayerContents[iLayer]); + lua_pushinteger(L, pLayers->layer_contents[iLayer]); else lua_pushnil(L); return 1; @@ -447,53 +471,53 @@ static int l_layers_set(lua_State *L) { - THLayers_t* pLayers = luaT_testuserdata(L); - int iLayer = luaL_checkint(L, 2); - int iValue = luaL_checkint(L, 3); + layers* pLayers = luaT_testuserdata(L); + lua_Integer iLayer = luaL_checkinteger(L, 2); + uint8_t iValue = static_cast(luaL_checkinteger(L, 3)); if(0 <= iLayer && iLayer < 13) - pLayers->iLayerContents[iLayer] = (unsigned char)iValue; + pLayers->layer_contents[iLayer] = iValue; return 0; } static int l_layers_persist(lua_State *L) { - THLayers_t* pLayers = luaT_testuserdata(L); + layers* pLayers = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - LuaPersistWriter* pWriter = (LuaPersistWriter*)lua_touserdata(L, 1); + lua_persist_writer* pWriter = (lua_persist_writer*)lua_touserdata(L, 1); int iNumLayers = 13; for( ; iNumLayers >= 1; --iNumLayers) { - if(pLayers->iLayerContents[iNumLayers - 1] != 0) + if(pLayers->layer_contents[iNumLayers - 1] != 0) break; } - pWriter->writeVUInt(iNumLayers); - pWriter->writeByteStream(pLayers->iLayerContents, iNumLayers); + pWriter->write_uint(iNumLayers); + pWriter->write_byte_stream(pLayers->layer_contents, iNumLayers); return 0; } static int l_layers_depersist(lua_State *L) { - THLayers_t* pLayers = luaT_testuserdata(L); + layers* pLayers = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - LuaPersistReader* pReader = (LuaPersistReader*)lua_touserdata(L, 1); + lua_persist_reader* pReader = (lua_persist_reader*)lua_touserdata(L, 1); - memset(pLayers->iLayerContents, 0, sizeof(pLayers->iLayerContents)); + std::memset(pLayers->layer_contents, 0, sizeof(pLayers->layer_contents)); int iNumLayers; - if(!pReader->readVUInt(iNumLayers)) + if(!pReader->read_uint(iNumLayers)) return 0; if(iNumLayers > 13) { - if(!pReader->readByteStream(pLayers->iLayerContents, 13)) + if(!pReader->read_byte_stream(pLayers->layer_contents, 13)) return 0; - if(!pReader->readByteStream(NULL, iNumLayers - 13)) + if(!pReader->read_byte_stream(nullptr, iNumLayers - 13)) return 0; } else { - if(!pReader->readByteStream(pLayers->iLayerContents, iNumLayers)) + if(!pReader->read_byte_stream(pLayers->layer_contents, iNumLayers)) return 0; } return 0; @@ -501,16 +525,16 @@ static int l_cursor_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, false); + luaT_stdnew(L, luaT_environindex, false); return 1; } static int l_cursor_load(lua_State *L) { - THCursor* pCursor = luaT_testuserdata(L); - THSpriteSheet* pSheet = luaT_testuserdata(L, 2); - if(pCursor->createFromSprite(pSheet, (unsigned int)luaL_checkint(L, 3), - luaL_optint(L, 4, 0), luaL_optint(L, 5, 0))) + cursor* pCursor = luaT_testuserdata(L); + sprite_sheet* pSheet = luaT_testuserdata(L, 2); + if(pCursor->create_from_sprite(pSheet, static_cast(luaL_checkinteger(L, 3)), + static_cast(luaL_optinteger(L, 4, 0)), static_cast(luaL_optinteger(L, 5, 0)))) { lua_settop(L, 1); return 1; @@ -524,137 +548,134 @@ static int l_cursor_use(lua_State *L) { - THCursor* pCursor = luaT_testuserdata(L); - THRenderTarget* pCanvas = luaT_testuserdata(L, 2); + cursor* pCursor = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L, 2); pCursor->use(pCanvas); return 0; } static int l_cursor_position(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L, 1, luaT_upvalueindex(1)); - lua_pushboolean(L, THCursor::setPosition(pCanvas, luaL_checkint(L, 2), luaL_checkint(L, 3)) ? 1 : 0); + render_target* pCanvas = luaT_testuserdata(L, 1, luaT_upvalueindex(1)); + lua_pushboolean(L, cursor::set_position(pCanvas, static_cast(luaL_checkinteger(L, 2)), static_cast(luaL_checkinteger(L, 3))) ? 1 : 0); return 1; } -static int l_surface_new(lua_State *L) +/** Construct the helper structure for making a #THRenderTarget. */ +static render_target_creation_params l_surface_creation_params(lua_State *L, int iArgStart) { - lua_remove(L, 1); // Value inserted by __call + render_target_creation_params oParams; + oParams.width = static_cast(luaL_checkinteger(L, iArgStart)); + oParams.height = static_cast(luaL_checkinteger(L, iArgStart + 1)); - THRenderTargetCreationParams oParams; - oParams.iWidth = luaL_checkint(L, 1); - oParams.iHeight = luaL_checkint(L, 2); - int iArg = 3; - if(lua_type(L, iArg) == LUA_TNUMBER) - oParams.iBPP = luaL_checkint(L, iArg++); - else - oParams.iBPP = 0; - oParams.iSDLFlags = 0; - oParams.bHardware = false; - oParams.bDoubleBuffered = false; - oParams.bFullscreen = false; - oParams.bPresentImmediate = false; - oParams.bReuseContext = false; - oParams.bOpenGL = false; - -#define FLAG(name, field, flag) \ - else if(stricmp(sOption, name) == 0) \ - oParams.field = true, oParams.iSDLFlags |= flag + oParams.fullscreen = false; + oParams.present_immediate = false; - for(int iArgCount = lua_gettop(L); iArg <= iArgCount; ++iArg) + // Parse string arguments, looking for matching parameter names. + for(int iArg = iArgStart + 2, iArgCount = lua_gettop(L); iArg <= iArgCount; ++iArg) { const char* sOption = luaL_checkstring(L, iArg); if(sOption[0] == 0) continue; - FLAG("hardware" , bHardware , SDL_HWSURFACE ); - FLAG("doublebuf" , bDoubleBuffered , SDL_DOUBLEBUF ); - FLAG("fullscreen" , bFullscreen , SDL_FULLSCREEN); - FLAG("present immediate", bPresentImmediate, 0 ); - FLAG("reuse context" , bReuseContext , 0 ); - FLAG("opengl" , bOpenGL , SDL_OPENGL ); - } - -#undef FLAG - -#ifndef CORSIX_TH_USE_DX9_RENDERER - if(SDL_WasInit(SDL_INIT_VIDEO)) - { - char *sTitle, *sIcon; - SDL_WM_GetCaption(&sTitle, &sIcon); - if(sTitle) sTitle = strdup(sTitle); - if(sIcon) sIcon = strdup(sIcon); - SDL_QuitSubSystem(SDL_INIT_VIDEO); - SDL_InitSubSystem(SDL_INIT_VIDEO); - SDL_WM_SetCaption(sTitle, sIcon); - if(sTitle) free(sTitle); - if(sIcon) free(sIcon); + + if (std::strcmp(sOption, "fullscreen") == 0) oParams.fullscreen = true; + if (std::strcmp(sOption, "present immediate") == 0) oParams.present_immediate = true; } -#endif - THRenderTarget* pCanvas = luaT_stdnew(L); + return oParams; +} + +static int l_surface_new(lua_State *L) +{ + lua_remove(L, 1); // Value inserted by __call + + render_target_creation_params oParams = l_surface_creation_params(L, 1); + render_target* pCanvas = luaT_stdnew(L); if(pCanvas->create(&oParams)) return 1; lua_pushnil(L); - lua_pushstring(L, pCanvas->getLastError()); + lua_pushstring(L, pCanvas->get_last_error()); return 2; } +static int l_surface_update(lua_State *L) +{ + render_target* pCanvas = luaT_testuserdata(L); + render_target_creation_params oParams = l_surface_creation_params(L, 2); + if(pCanvas->update(&oParams)) + { + lua_pushnil(L); + return 1; + } + + lua_pushstring(L, pCanvas->get_last_error()); + return 1; +} + +static int l_surface_destroy(lua_State *L) +{ + render_target* pCanvas = luaT_testuserdata(L); + pCanvas->end_frame(); + pCanvas->destroy(); + return 1; +} + static int l_surface_fill_black(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L); lua_settop(L, 1); - if(pCanvas->fillBlack()) + if(pCanvas->fill_black()) return 1; lua_pushnil(L); - lua_pushstring(L, pCanvas->getLastError()); + lua_pushstring(L, pCanvas->get_last_error()); return 2; } static int l_surface_start_frame(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L); lua_settop(L, 1); - if(pCanvas->startFrame()) + if(pCanvas->start_frame()) return 1; lua_pushnil(L); - lua_pushstring(L, pCanvas->getLastError()); + lua_pushstring(L, pCanvas->get_last_error()); return 2; } static int l_surface_end_frame(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L); lua_settop(L, 1); - if(pCanvas->endFrame()) + if(pCanvas->end_frame()) return 1; lua_pushnil(L); - lua_pushstring(L, pCanvas->getLastError()); + lua_pushstring(L, pCanvas->get_last_error()); return 2; } static int l_surface_nonoverlapping(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L); if(lua_isnone(L, 2) || lua_toboolean(L, 2) != 0) - pCanvas->startNonOverlapping(); + pCanvas->start_nonoverlapping_draws(); else - pCanvas->finishNonOverlapping(); + pCanvas->finish_nonoverlapping_draws(); lua_settop(L, 1); return 1; } static int l_surface_set_blue_filter_active(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); - pCanvas->setBlueFilterActive(lua_isnoneornil(L, 2) ? false : lua_toboolean(L, 2)); + render_target* pCanvas = luaT_testuserdata(L); + pCanvas->set_blue_filter_active((lua_isnoneornil(L, 2) != 0) ? false : (lua_toboolean(L, 2) != 0)); return 1; } static int l_surface_map(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); - lua_pushnumber(L, (lua_Number)pCanvas->mapColour( + render_target* pCanvas = luaT_testuserdata(L); + lua_pushnumber(L, (lua_Number)pCanvas->map_colour( (Uint8)luaL_checkinteger(L, 2), (Uint8)luaL_checkinteger(L, 3), (Uint8)luaL_checkinteger(L, 4))); @@ -663,38 +684,38 @@ static int l_surface_rect(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); - if(pCanvas->fillRect((uint32_t)luaL_checknumber(L, 2), - luaL_checkint(L, 3), luaL_checkint(L, 4), luaL_checkint(L, 5), - luaL_checkint(L, 6))) + render_target* pCanvas = luaT_testuserdata(L); + if(pCanvas->fill_rect(static_cast(luaL_checkinteger(L, 2)), + static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4)), static_cast(luaL_checkinteger(L, 5)), + static_cast(luaL_checkinteger(L, 6)))) { lua_settop(L, 1); return 1; } lua_pushnil(L); - lua_pushstring(L, pCanvas->getLastError()); + lua_pushstring(L, pCanvas->get_last_error()); return 2; } static int l_surface_screenshot(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L); const char *sFile = luaL_checkstring(L, 2); - if(pCanvas->takeScreenshot(sFile)) + if(pCanvas->take_screenshot(sFile)) { lua_settop(L, 1); return 1; } lua_pushnil(L); - lua_pushstring(L, pCanvas->getLastError()); + lua_pushstring(L, pCanvas->get_last_error()); return 2; } static int l_surface_get_clip(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); - THClipRect rcClip; - pCanvas->getClipRect(&rcClip); + render_target* pCanvas = luaT_testuserdata(L); + clip_rect rcClip; + pCanvas->get_clip_rect(&rcClip); lua_pushinteger(L, rcClip.x); lua_pushinteger(L, rcClip.y); lua_pushinteger(L, rcClip.w); @@ -704,57 +725,81 @@ static int l_surface_set_clip(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); - THClipRect rcClip; - rcClip.x = static_cast(luaL_checkint(L, 2)); - rcClip.y = static_cast(luaL_checkint(L, 3)); - rcClip.w = static_cast(luaL_checkint(L, 4)); - rcClip.h = static_cast(luaL_checkint(L, 5)); + render_target* pCanvas = luaT_testuserdata(L); + clip_rect rcClip; + rcClip.x = static_cast(luaL_checkinteger(L, 2)); + rcClip.y = static_cast(luaL_checkinteger(L, 3)); + rcClip.w = static_cast(luaL_checkinteger(L, 4)); + rcClip.h = static_cast(luaL_checkinteger(L, 5)); if(lua_toboolean(L, 6) != 0) { - THClipRect rcExistingClip; - pCanvas->getClipRect(&rcExistingClip); - IntersectTHClipRect(rcClip, rcExistingClip); + clip_rect rcExistingClip; + pCanvas->get_clip_rect(&rcExistingClip); + clip_rect_intersection(rcClip, rcExistingClip); } - pCanvas->setClipRect(&rcClip); + pCanvas->set_clip_rect(&rcClip); lua_settop(L, 1); return 1; } static int l_surface_scale(lua_State *L) { - THRenderTarget* pCanvas = luaT_testuserdata(L); - THScaledItems eToScale = THSI_None; + render_target* pCanvas = luaT_testuserdata(L); + scaled_items eToScale = scaled_items::none; if(lua_isnoneornil(L, 3)) { - eToScale = THSI_All; + eToScale = scaled_items::all; } else { size_t iLength; const char* sOption = lua_tolstring(L, 3, &iLength); - if(sOption && iLength >= 6 && memcmp(sOption, "bitmap", 6) == 0) + if(sOption && iLength >= 6 && std::memcmp(sOption, "bitmap", 6) == 0) { - eToScale = THSI_Bitmaps; + eToScale = scaled_items::bitmaps; } else luaL_error(L, "Expected \"bitmap\" as 2nd argument"); } - lua_pushboolean(L, pCanvas->setScaleFactor(static_cast( + lua_pushboolean(L, pCanvas->set_scale_factor(static_cast( luaL_checknumber(L, 2)), eToScale) ? 1 : 0); return 1; } +static int l_surface_set_caption(lua_State *L) +{ + render_target* pCanvas = luaT_testuserdata(L); + pCanvas->set_caption(luaL_checkstring(L, 2)); + + lua_settop(L, 1); + return 1; +} + +static int l_surface_get_renderer_details(lua_State *L) +{ + render_target* pCanvas = luaT_testuserdata(L); + lua_pushstring(L, pCanvas->get_renderer_details()); + return 1; +} + +// Lua to THRenderTarget->setWindowGrab +static int l_surface_set_capture_mouse(lua_State *L) +{ + render_target* pCanvas = luaT_testuserdata(L); + pCanvas->set_window_grab((lua_isnoneornil(L, 2) != 0) ? false : (lua_toboolean(L, 2) != 0)); + return 0; +} + static int l_line_new(lua_State *L) { - luaT_stdnew(L); + luaT_stdnew(L); return 1; } static int l_move_to(lua_State *L) { - THLine* pLine = luaT_testuserdata(L); - pLine->moveTo(luaL_optnumber(L, 2, 0), luaL_optnumber(L, 3, 0)); + line* pLine = luaT_testuserdata(L); + pLine->move_to(luaL_optnumber(L, 2, 0), luaL_optnumber(L, 3, 0)); lua_settop(L, 1); return 1; @@ -762,8 +807,8 @@ static int l_line_to(lua_State *L) { - THLine* pLine = luaT_testuserdata(L); - pLine->lineTo(luaL_optnumber(L, 2, 0), luaL_optnumber(L, 3, 0)); + line* pLine = luaT_testuserdata(L); + pLine->line_to(luaL_optnumber(L, 2, 0), luaL_optnumber(L, 3, 0)); lua_settop(L, 1); return 1; @@ -771,8 +816,8 @@ static int l_set_width(lua_State *L) { - THLine* pLine = luaT_testuserdata(L); - pLine->setWidth(luaL_optnumber(L, 2, 1)); + line* pLine = luaT_testuserdata(L); + pLine->set_width(luaL_optnumber(L, 2, 1)); lua_settop(L, 1); return 1; @@ -780,8 +825,11 @@ static int l_set_colour(lua_State *L) { - THLine* pLine = luaT_testuserdata(L); - pLine->setColour(luaL_optint(L, 2, 0), luaL_optint(L, 3, 0), luaL_optint(L, 4, 0), luaL_optint(L, 5, 255)); + line* pLine = luaT_testuserdata(L); + pLine->set_colour(static_cast(luaL_optinteger(L, 2, 0)), + static_cast(luaL_optinteger(L, 3, 0)), + static_cast(luaL_optinteger(L, 4, 0)), + static_cast(luaL_optinteger(L, 5, 255))); lua_settop(L, 1); return 1; @@ -789,9 +837,9 @@ static int l_line_draw(lua_State *L) { - THLine* pLine = luaT_testuserdata(L); - THRenderTarget* pCanvas = luaT_testuserdata(L, 2); - pLine->draw(pCanvas, luaL_optint(L, 3, 0), luaL_optint(L, 4, 0)); + line* pLine = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L, 2); + pLine->draw(pCanvas, static_cast(luaL_optinteger(L, 3, 0)), static_cast(luaL_optinteger(L, 4, 0))); lua_settop(L, 1); return 1; @@ -799,78 +847,80 @@ static int l_line_persist(lua_State *L) { - THLine* pLine = luaT_testuserdata(L); + line* pLine = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - LuaPersistWriter* pWriter = (LuaPersistWriter*)lua_touserdata(L, 1); + lua_persist_writer* pWriter = (lua_persist_writer*)lua_touserdata(L, 1); pLine->persist(pWriter); return 0; } static int l_line_depersist(lua_State *L) { - THLine* pLine = luaT_testuserdata(L); + line* pLine = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - LuaPersistReader* pReader = (LuaPersistReader*)lua_touserdata(L, 1); + lua_persist_reader* pReader = (lua_persist_reader*)lua_touserdata(L, 1); pLine->depersist(pReader); return 0; } -void THLuaRegisterGfx(const THLuaRegisterState_t *pState) +void lua_register_gfx(const lua_register_state *pState) { // Palette - luaT_class(THPalette, l_palette_new, "palette", MT_Palette); + luaT_class(palette, l_palette_new, "palette", lua_metatable::palette); luaT_setfunction(l_palette_load, "load"); luaT_setfunction(l_palette_set_entry, "setEntry"); luaT_endclass(); // Raw bitmap - luaT_class(THRawBitmap, l_rawbitmap_new, "bitmap", MT_Bitmap); - luaT_setfunction(l_rawbitmap_load, "load", MT_Surface); - luaT_setfunction(l_rawbitmap_set_pal, "setPalette", MT_Palette); - luaT_setfunction(l_rawbitmap_draw, "draw", MT_Surface); + luaT_class(raw_bitmap, l_rawbitmap_new, "bitmap", lua_metatable::bitmap); + luaT_setfunction(l_rawbitmap_load, "load", lua_metatable::surface); + luaT_setfunction(l_rawbitmap_set_pal, "setPalette", lua_metatable::palette); + luaT_setfunction(l_rawbitmap_draw, "draw", lua_metatable::surface); luaT_endclass(); // Sprite sheet - luaT_class(THSpriteSheet, l_spritesheet_new, "sheet", MT_Sheet); + luaT_class(sprite_sheet, l_spritesheet_new, "sheet", lua_metatable::sheet); luaT_setmetamethod(l_spritesheet_count, "len"); - luaT_setfunction(l_spritesheet_load, "load", MT_Surface); - luaT_setfunction(l_spritesheet_set_pal, "setPalette", MT_Palette); + luaT_setfunction(l_spritesheet_load, "load", lua_metatable::surface); + luaT_setfunction(l_spritesheet_set_pal, "setPalette", lua_metatable::palette); luaT_setfunction(l_spritesheet_size, "size"); - luaT_setfunction(l_spritesheet_draw, "draw", MT_Surface); + luaT_setfunction(l_spritesheet_draw, "draw", lua_metatable::surface); luaT_setfunction(l_spritesheet_hittest, "hitTest"); luaT_setfunction(l_spritesheet_isvisible, "isVisible"); luaT_endclass(); // Font - luaT_class(THFont, l_font_new, "font", MT_Font); + // Also adapt the font proxy meta table (font_proxy_mt) in graphics.lua. + luaT_class(font, l_font_new, "font", lua_metatable::font); luaT_setfunction(l_font_get_size, "sizeOf"); - luaT_setfunction(l_font_draw, "draw", MT_Surface); - luaT_setfunction(l_font_draw_wrapped, "drawWrapped", MT_Surface); - luaT_setfunction(l_font_draw_tooltip, "drawTooltip", MT_Surface); + luaT_setfunction(l_font_draw, "draw", lua_metatable::surface); + luaT_setfunction(l_font_draw_wrapped, "drawWrapped", lua_metatable::surface); + luaT_setfunction(l_font_draw_tooltip, "drawTooltip", lua_metatable::surface); luaT_endclass(); // BitmapFont - luaT_class(THBitmapFont, l_bitmap_font_new, "bitmap_font", MT_BitmapFont); - luaT_superclass(MT_Font); - luaT_setfunction(l_bitmap_font_set_spritesheet, "setSheet", MT_Sheet); - luaT_setfunction(l_bitmap_font_get_spritesheet, "getSheet", MT_Sheet); + luaT_class(bitmap_font, l_bitmap_font_new, "bitmap_font", lua_metatable::bitmap_font); + luaT_superclass(lua_metatable::font); + luaT_setfunction(l_bitmap_font_set_spritesheet, "setSheet", lua_metatable::sheet); + luaT_setfunction(l_bitmap_font_get_spritesheet, "getSheet", lua_metatable::sheet); luaT_setfunction(l_bitmap_font_set_sep, "setSeparation"); luaT_endclass(); #ifdef CORSIX_TH_USE_FREETYPE2 // FreeTypeFont - luaT_class(THFreeTypeFont, l_freetype_font_new, "freetype_font", MT_FreeTypeFont); - luaT_superclass(MT_Font); - luaT_setfunction(l_freetype_font_set_spritesheet, "setSheet", MT_Sheet); + luaT_class(freetype_font, l_freetype_font_new, "freetype_font", lua_metatable::freetype_font); + luaT_superclass(lua_metatable::font); + luaT_setfunction(l_freetype_font_set_spritesheet, "setSheet", lua_metatable::sheet); luaT_setfunction(l_freetype_font_set_face, "setFace"); luaT_setfunction(l_freetype_font_get_copyright, "getCopyrightNotice"); + luaT_setfunction(l_freetype_font_clear_cache, "clearCache"); luaT_endclass(); #endif // Layers - luaT_class(THLayers_t, l_layers_new, "layers", MT_Layers); + luaT_class(layers, l_layers_new, "layers", lua_metatable::layers); luaT_setmetamethod(l_layers_get, "index"); luaT_setmetamethod(l_layers_set, "newindex"); luaT_setmetamethod(l_layers_persist, "persist"); @@ -878,14 +928,16 @@ luaT_endclass(); // Cursor - luaT_class(THCursor, l_cursor_new, "cursor", MT_Cursor); - luaT_setfunction(l_cursor_load, "load", MT_Sheet); - luaT_setfunction(l_cursor_use, "use", MT_Surface); - luaT_setfunction(l_cursor_position, "setPosition", MT_Surface); + luaT_class(cursor, l_cursor_new, "cursor", lua_metatable::cursor); + luaT_setfunction(l_cursor_load, "load", lua_metatable::sheet); + luaT_setfunction(l_cursor_use, "use", lua_metatable::surface); + luaT_setfunction(l_cursor_position, "setPosition", lua_metatable::surface); luaT_endclass(); // Surface - luaT_class(THRenderTarget, l_surface_new, "surface", MT_Surface); + luaT_class(render_target, l_surface_new, "surface", lua_metatable::surface); + luaT_setfunction(l_surface_update, "update"); + luaT_setfunction(l_surface_destroy, "destroy"); luaT_setfunction(l_surface_fill_black, "fillBlack"); luaT_setfunction(l_surface_start_frame, "startFrame"); luaT_setfunction(l_surface_end_frame, "endFrame"); @@ -897,15 +949,18 @@ luaT_setfunction(l_surface_set_clip, "setClip"); luaT_setfunction(l_surface_screenshot, "takeScreenshot"); luaT_setfunction(l_surface_scale, "scale"); + luaT_setfunction(l_surface_set_caption, "setCaption"); + luaT_setfunction(l_surface_get_renderer_details, "getRendererDetails"); + luaT_setfunction(l_surface_set_capture_mouse, "setCaptureMouse"); luaT_endclass(); // Line - luaT_class(THLine, l_line_new, "line", MT_Line); + luaT_class(line, l_line_new, "line", lua_metatable::line); luaT_setfunction(l_move_to, "moveTo"); luaT_setfunction(l_line_to, "lineTo"); luaT_setfunction(l_set_width, "setWidth"); luaT_setfunction(l_set_colour, "setColour"); - luaT_setfunction(l_line_draw, "draw", MT_Surface); + luaT_setfunction(l_line_draw, "draw", lua_metatable::surface); luaT_setmetamethod(l_line_persist, "persist"); luaT_setmetamethod(l_line_depersist, "depersist"); luaT_endclass(); diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua.h corsix-th-0.62/CorsixTH/Src/th_lua.h --- corsix-th-0.30/CorsixTH/Src/th_lua.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua.h 2018-07-21 11:13:17.000000000 +0000 @@ -22,37 +22,100 @@ #ifndef CORSIX_TH_TH_LUA_H_ #define CORSIX_TH_TH_LUA_H_ +#include "config.h" #include "lua.hpp" #include +#include int luaopen_th(lua_State *L); // Compatibility layer for removal of environments in 5.2 #if LUA_VERSION_NUM >= 502 -#define luaT_environindex lua_upvalueindex(1) -#define luaT_upvalueindex(i) lua_upvalueindex((i) + 1) -void luaT_pushcclosure(lua_State* L, lua_CFunction f, int nups); -#define luaT_register(L, n, p) (\ - lua_pushvalue(L, luaT_enrivonindex), \ - luaL_openlib(L, n, p, 1) ) +const int luaT_environindex = lua_upvalueindex(1); #else -#define luaT_environindex LUA_ENVIRONINDEX -#define luaT_upvalueindex lua_upvalueindex -#define luaT_pushcclosure lua_pushcclosure -#define luaT_register luaL_register +const int luaT_environindex = LUA_ENVIRONINDEX; #endif -#define luaT_pushcfunction(L, f) luaT_pushcclosure(L, f, 0) -// Compatibility layer for removal of cpcall in 5.2 +inline int luaT_upvalueindex(int i) +{ #if LUA_VERSION_NUM >= 502 -#define luaT_cpcall(L, f, u) (\ - lua_checkstack(L, 2), \ - lua_pushcfunction(L, f), \ - lua_pushlightuserdata(L, u), \ - lua_pcall(L, 1, 0, 0) ) + return lua_upvalueindex(i + 1); #else -#define luaT_cpcall lua_cpcall + return lua_upvalueindex(i); #endif +} + +inline void luaT_register(lua_State *L, const char *n, const std::vector &l) +{ +#if LUA_VERSION_NUM >= 502 + lua_createtable(L, 0, static_cast(l.size())); + lua_pushvalue(L, luaT_environindex); + luaL_setfuncs(L, l.data(), 1); + lua_pushvalue(L, -1); + lua_setglobal(L, n); +#else + luaL_register(L, n, l.data()); +#endif +} + +inline void luaT_setfuncs(lua_State *L, const luaL_Reg *R) +{ +#if LUA_VERSION_NUM >= 502 + lua_pushvalue(L, luaT_environindex); + luaL_setfuncs(L, R, 1); +#else + luaL_register(L, nullptr, R); +#endif +} + +inline void luaT_pushcclosure(lua_State* L, lua_CFunction f, int nups) +{ +#if LUA_VERSION_NUM >= 502 + ++nups; + lua_pushvalue(L, luaT_environindex); + lua_insert(L, -nups); + lua_pushcclosure(L, f, nups); +#else + lua_pushcclosure(L, f, nups); +#endif +} + +inline void luaT_pushcfunction(lua_State *L, lua_CFunction f) +{ + luaT_pushcclosure(L, f, 0); +} + +inline int luaT_cpcall(lua_State *L, lua_CFunction f, void *u) +{ +#if LUA_VERSION_NUM >= 502 + lua_checkstack(L, 2); + lua_pushcfunction(L, f); + lua_pushlightuserdata(L, u); + return lua_pcall(L, 1, 0, 0); +#else + return lua_cpcall(L, f, u); +#endif +} + +// Compatibility for missing mode argument on lua_load in 5.1 +inline int luaT_load(lua_State *L, lua_Reader r, void *d, const char *s, const char *m) +{ +#if LUA_VERSION_NUM >= 502 + return lua_load(L, r, d, s, m); +#else + return lua_load(L, r, d, s); +#endif +} + +// Compatibility for missing from argument on lua_resume in 5.1 +inline int luaT_resume(lua_State *L, lua_State *f, int n) +{ +#if LUA_VERSION_NUM >= 502 + return lua_resume(L, f, n); +#else + return lua_resume(L, n); +#endif +} //! Version of operator new which allocates into a Lua userdata /*! @@ -65,16 +128,13 @@ */ #define luaT_new(L, T) new ((T*)lua_newuserdata(L, sizeof(T))) T -//! Register a function to be called after a lua_State is destroyed -void luaT_addcleanup(lua_State *L, void(*fnCleanup)(void)); - //! Check that a Lua argument is a binary data blob /*! If the given argument is a string or (full) userdata, then returns a pointer to the start of it, and the length of it. Otherwise, throws a Lua error. */ -const unsigned char* luaT_checkfile(lua_State *L, int idx, size_t* pDataLen); +const uint8_t* luaT_checkfile(lua_State *L, int idx, size_t* pDataLen); //! Check that a Lua argument is a string or a proxied string const char* luaT_checkstring(lua_State *L, int idx, size_t* pLength); @@ -110,115 +170,120 @@ template struct luaT_classinfo {}; -class THRenderTarget; -template <> struct luaT_classinfo { +class render_target; +template <> struct luaT_classinfo { static inline const char* name() {return "Surface";} }; -class THMap; -template <> struct luaT_classinfo { +class level_map; +template <> struct luaT_classinfo { static inline const char* name() {return "Map";} }; -class THSpriteSheet; -template <> struct luaT_classinfo { +class sprite_sheet; +template <> struct luaT_classinfo { static inline const char* name() {return "SpriteSheet";} }; -class THAnimation; -template <> struct luaT_classinfo { +class animation; +template <> struct luaT_classinfo { static inline const char* name() {return "Animation";} }; -class THAnimationManager; -template <> struct luaT_classinfo { +class animation_manager; +template <> struct luaT_classinfo { static inline const char* name() {return "Animator";} }; -class THPalette; -template <> struct luaT_classinfo { +class palette; +template <> struct luaT_classinfo { static inline const char* name() {return "Palette";} }; -class THRawBitmap; -template <> struct luaT_classinfo { +class raw_bitmap; +template <> struct luaT_classinfo { static inline const char* name() {return "RawBitmap";} }; -class THFont; -template <> struct luaT_classinfo { +class font; +template <> struct luaT_classinfo { static inline const char* name() {return "Font";} }; -class THBitmapFont; -template <> struct luaT_classinfo { +class bitmap_font; +template <> struct luaT_classinfo { static inline const char* name() {return "BitmapFont";} }; #ifdef CORSIX_TH_USE_FREETYPE2 -class THFreeTypeFont; -template <> struct luaT_classinfo { +class freetype_font; +template <> struct luaT_classinfo { static inline const char* name() {return "FreeTypeFont";} }; #endif -struct THLayers_t; -template <> struct luaT_classinfo { +struct layers; +template <> struct luaT_classinfo { static inline const char* name() {return "Layers";} }; -class THPathfinder; -template <> struct luaT_classinfo { +class pathfinder; +template <> struct luaT_classinfo { static inline const char* name() {return "Pathfinder";} }; -class THCursor; -template <> struct luaT_classinfo { +class cursor; +template <> struct luaT_classinfo { static inline const char* name() {return "Cursor";} }; -class THLine; -template <> struct luaT_classinfo { +class line; +template <> struct luaT_classinfo { static inline const char* name() {return "Line";} }; -struct music_t; -template <> struct luaT_classinfo { +class music; +template <> struct luaT_classinfo { static inline const char* name() {return "Music";} }; -class THSoundArchive; -template <> struct luaT_classinfo { +class sound_archive; +template <> struct luaT_classinfo { static inline const char* name() {return "SoundArchive";} }; -class THSoundEffects; -template <> struct luaT_classinfo { +class sound_player; +template <> struct luaT_classinfo { static inline const char* name() {return "SoundEffects";} }; -class THMovie; -template <> struct luaT_classinfo { +class movie_player; +template <> struct luaT_classinfo { static inline const char* name() {return "Movie";} }; -struct THWindowBase_t; -template <> struct luaT_classinfo { +class abstract_window; +template <> struct luaT_classinfo { static inline const char* name() {return "WindowBase";} }; -class THSpriteRenderList; -template <> struct luaT_classinfo { +class sprite_render_list; +template <> struct luaT_classinfo { static inline const char* name() {return "SpriteRenderList";} }; -struct THStringProxy_t; -template <> struct luaT_classinfo { +class string_proxy; +template <> struct luaT_classinfo { static inline const char* name() {return "StringProxy";} }; -class IsoFilesystem; -template <> struct luaT_classinfo { +class lfs_ext; +template <> struct luaT_classinfo { + static inline const char* name() {return "LfsExt";} +}; + +class iso_filesystem; +template <> struct luaT_classinfo { static inline const char* name() {return "ISO Filesystem";} }; @@ -234,7 +299,7 @@ mt_idx = lua_gettop(L) + mt_idx + 1; void *ud = lua_touserdata(L, idx); - if(ud != NULL && lua_getmetatable(L, idx) != 0) + if(ud != nullptr && lua_getmetatable(L, idx) != 0) { while(true) { @@ -252,9 +317,12 @@ lua_pop(L, 1); } - if(required) - luaL_typerror(L, idx, luaT_classinfo::name()); - return NULL; + if (required) + { + const char *msg = lua_pushfstring(L, "%s expected, got %s", luaT_classinfo::name(), luaL_typename(L, idx)); + luaL_argerror(L, idx, msg); + } + return nullptr; } template @@ -270,7 +338,7 @@ static int luaT_stdgc(lua_State *L) { T* p = luaT_testuserdata(L, 1, mt, false); - if(p != NULL) + if(p != nullptr) { p->~T(); } @@ -325,4 +393,10 @@ lua_call(L, 4, LUA_MULTRET); } +void luaT_pushtablebool(lua_State *L, const char *k, bool v); + +void luaT_printstack(lua_State *L); + +void luaT_printrawtable(lua_State *L, int idx); + #endif // CORSIX_TH_TH_LUA_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_internal.h corsix-th-0.62/CorsixTH/Src/th_lua_internal.h --- corsix-th-0.30/CorsixTH/Src/th_lua_internal.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_internal.h 2018-07-21 11:13:17.000000000 +0000 @@ -24,58 +24,64 @@ #define CORSIX_TH_TH_LUA_INTERNAL_H_ #include "config.h" #include "th_lua.h" -#ifndef _MSC_VER -#define stricmp strcasecmp -#else -#pragma warning(disable: 4996) // Deprecated CRT -#endif -enum eTHLuaMetatable -{ - MT_Map, - MT_Palette, - MT_Sheet, - MT_Font, - MT_BitmapFont, +enum class lua_metatable { + map, + palette, + sheet, + font, + bitmap_font, #ifdef CORSIX_TH_USE_FREETYPE2 - MT_FreeTypeFont, + freetype_font, #endif - MT_Layers, - MT_Anims, - MT_Anim, - MT_Path, - MT_Surface, - MT_Bitmap, - MT_Cursor, - MT_SoundArc, - MT_SoundFx, - MT_Movie, - MT_String, - MT_WindowBase, - MT_SpriteList, - MT_StringProxy, - MT_Line, - - MT_Count, + layers, + anims, + anim, + pathfinder, + surface, + bitmap, + cursor, + lfs_ext, + sound_archive, + sound_fx, + movie, + string, + window_base, + sprite_list, + string_proxy, + line, - MT_DummyString, + count }; -struct THLuaRegisterState_t +struct lua_register_state { lua_State *L; - int aiMetatables[MT_Count]; - int iMainTable; - int iTop; + int metatables[static_cast(lua_metatable::count)]; + int main_table; + int top; }; -void luaT_setclosure(const THLuaRegisterState_t *pState, lua_CFunction fn, - eTHLuaMetatable eMetatable1, ...); +void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t iUps); + +template +void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t iUps, + lua_metatable eMetatable1, Args... args) { + lua_pushvalue(pState->L, pState->metatables[static_cast(eMetatable1)]); + luaT_setclosure(pState, fn, iUps + 1, args...); +} + +template +void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t iUps, + const char* str, Args... args) { + lua_pushstring(pState->L, str); + luaT_setclosure(pState, fn, iUps + 1, args...); +} #define luaT_class(typnam, new_fn, name, mt) { \ const char * sCurrentClassName = name; \ - int iCurrentClassMT = pState->aiMetatables[mt]; \ - lua_settop(pState->L, pState->iTop); \ + int iCurrentClassMT = pState->metatables[static_cast(mt)]; \ + lua_settop(pState->L, pState->top); \ /* Make metatable the environment for registered functions */ \ lua_pushvalue(pState->L, iCurrentClassMT); \ lua_replace(pState->L, luaT_environindex); \ @@ -99,22 +105,31 @@ #define luaT_superclass(super_mt) \ /* Set __index on the methods metatable to the superclass methods */ \ lua_getmetatable(pState->L, -1); \ - lua_getfield(pState->L, pState->aiMetatables[super_mt], "__index"); \ + lua_getfield(pState->L, pState->metatables[static_cast(super_mt)], "__index"); \ lua_setfield(pState->L, -2, "__index"); \ lua_pop(pState->L, 1); \ /* Set metatable[1] to super_mt */ \ - lua_pushvalue(pState->L, pState->aiMetatables[super_mt]); \ + lua_pushvalue(pState->L, pState->metatables[static_cast(super_mt)]); \ lua_rawseti(pState->L, iCurrentClassMT, 1) #define luaT_endclass() \ - lua_setfield(pState->L, pState->iMainTable, sCurrentClassName); } + lua_setfield(pState->L, pState->main_table, sCurrentClassName); } #define luaT_setmetamethod(fn, name, ...) \ - luaT_setclosure(pState, fn, ## __VA_ARGS__, MT_Count); \ + luaT_setclosure(pState, fn, 0, ## __VA_ARGS__); \ lua_setfield(pState->L, iCurrentClassMT, "__" name) #define luaT_setfunction(fn, name, ...) \ - luaT_setclosure(pState, fn, ## __VA_ARGS__, MT_Count); \ + luaT_setclosure(pState, fn, 0, ## __VA_ARGS__); \ + lua_setfield(pState->L, -2, name) + +/** + * Add a named constant to the lua interface. + * @param name (string literal) Name of the constant. + * @param value (tested with int) Value of the constant. + */ +#define luaT_setconstant(name, value) \ + luaT_push(pState->L, value); \ lua_setfield(pState->L, -2, name) #endif diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_lfs_ext.cpp corsix-th-0.62/CorsixTH/Src/th_lua_lfs_ext.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua_lfs_ext.cpp 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_lfs_ext.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,104 @@ +/* +Copyright (c) 2010 Peter "Corsix" Cawley +Copyright (c) 2014 Stephen E. Baker + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "th_lua_internal.h" +#include "config.h" +#ifdef CORSIX_TH_USE_WIN32_SDK +#include +#endif + +class lfs_ext {}; + +static int l_lfs_ext_new(lua_State *L) +{ + luaT_stdnew(L, luaT_environindex, true); + return 1; +} + +#ifdef _WIN32 +#ifdef CORSIX_TH_USE_WIN32_SDK +static int l_volume_list(lua_State *L) +{ + /* Windows, using the Win32 API. */ + DWORD iDriveMask = GetLogicalDrives(); + int iNDrives = 0; + char cDrive; + lua_settop(L, 0); + lua_newtable(L); + for (cDrive = 'A'; cDrive <= 'Z'; ++cDrive) + { + if (iDriveMask & (1 << (cDrive - 'A'))) + { + char sName[4] = { cDrive, ':', '\\', 0 }; + if (GetDriveTypeA(sName) > DRIVE_NO_ROOT_DIR) + { + lua_pushlstring(L, sName, 2); + lua_rawseti(L, 1, ++iNDrives); + } + } + } + return 1; +} +#else +static int l_volume_list(lua_State *L) +{ + /* Windows, without the Win32 API. */ + int iNDrives = 0; + char cDrive; + lua_settop(L, 0); + lua_newtable(L); + lua_getfield(L, luaT_upvalueindex(1), "attributes"); + for (cDrive = 'A'; cDrive <= 'Z'; ++cDrive) + { + lua_pushvalue(L, 2); + lua_pushfstring(L, "%c:\\", cDrive); + lua_pushliteral(L, "mode"); + lua_call(L, 2, 1); + if (lua_toboolean(L, 3) != 0) + { + lua_pushfstring(L, "%c:", cDrive); + lua_rawseti(L, 1, ++iNDrives); + } + lua_pop(L, 1); + } + return 1; +} +#endif +#else +static int l_volume_list(lua_State *L) +{ + /* Non-Windows systems. Assume that / is the root of the filesystem. */ + lua_settop(L, 0); + lua_newtable(L); + lua_pushliteral(L, "/"); + lua_rawseti(L, 1, 1); + return 1; +} +#endif + +void lua_register_lfs_ext(const lua_register_state *pState) +{ + luaT_class(lfs_ext, l_lfs_ext_new, "lfsExt", lua_metatable::lfs_ext); + luaT_setfunction(l_volume_list, "volumes"); + luaT_endclass(); +} diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_map.cpp corsix-th-0.62/CorsixTH/Src/th_lua_map.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua_map.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_map.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -23,49 +23,53 @@ #include "th_lua_internal.h" #include "th_map.h" #include "th_pathfind.h" -#include +#include +#include +#include + +static const int player_max = 4; static int l_map_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_map_set_sheet(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - THSpriteSheet* pSheet = luaT_testuserdata(L, 2); + level_map* pMap = luaT_testuserdata(L); + sprite_sheet* pSheet = luaT_testuserdata(L, 2); lua_settop(L, 2); - pMap->setBlockSheet(pSheet); + pMap->set_block_sheet(pSheet); luaT_setenvfield(L, 1, "sprites"); return 1; } static int l_map_persist(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); + level_map* pMap = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - pMap->persist((LuaPersistWriter*)lua_touserdata(L, 1)); + pMap->persist((lua_persist_writer*)lua_touserdata(L, 1)); return 0; } static int l_map_depersist(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); + level_map* pMap = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - LuaPersistReader* pReader = (LuaPersistReader*)lua_touserdata(L, 1); + lua_persist_reader* pReader = (lua_persist_reader*)lua_touserdata(L, 1); pMap->depersist(pReader); luaT_getenvfield(L, 2, "sprites"); - pMap->setBlockSheet((THSpriteSheet*)lua_touserdata(L, -1)); + pMap->set_block_sheet((sprite_sheet*)lua_touserdata(L, -1)); lua_pop(L, 1); return 0; } -static void l_map_load_obj_cb(void *pL, int iX, int iY, THObjectType eTHOB, uint8_t iFlags) +static void l_map_load_obj_cb(void *pL, int iX, int iY, object_type eTHOB, uint8_t iFlags) { lua_State *L = reinterpret_cast(pL); lua_createtable(L, 4, 0); @@ -84,12 +88,12 @@ static int l_map_load(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); + level_map* pMap = luaT_testuserdata(L); size_t iDataLen; - const unsigned char* pData = luaT_checkfile(L, 2, &iDataLen); + const uint8_t* pData = luaT_checkfile(L, 2, &iDataLen); lua_settop(L, 2); lua_newtable(L); - if(pMap->loadFromTHFile(pData, iDataLen, l_map_load_obj_cb, (void*)L)) + if(pMap->load_from_th_file(pData, iDataLen, l_map_load_obj_cb, (void*)L)) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); @@ -99,8 +103,8 @@ static int l_map_loadblank(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - if(pMap->loadBlank()) + level_map* pMap = luaT_testuserdata(L); + if(pMap->load_blank()) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); @@ -108,27 +112,35 @@ return 2; } -THAnimation* l_map_updateblueprint_getnextanim(lua_State *L, int& iIndex) +static int l_map_save(lua_State *L) +{ + level_map* pMap = luaT_testuserdata(L); + std::string filename(luaL_checkstring(L, 2)); + pMap->save(filename); + return 0; +} + +static animation* l_map_updateblueprint_getnextanim(lua_State *L, int& iIndex) { - THAnimation *pAnim; - lua_rawgeti(L, 10, iIndex); + animation *pAnim; + lua_rawgeti(L, 11, iIndex); if(lua_type(L, -1) == LUA_TNIL) { lua_pop(L, 1); - pAnim = luaT_new(L, THAnimation); + pAnim = luaT_new(L, animation); lua_pushvalue(L, luaT_upvalueindex(2)); lua_setmetatable(L, -2); lua_createtable(L, 0, 2); lua_pushvalue(L, 1); lua_setfield(L, -2, "map"); - lua_pushvalue(L, 11); + lua_pushvalue(L, 12); lua_setfield(L, -2, "animator"); lua_setfenv(L, -2); - lua_rawseti(L, 10, iIndex); + lua_rawseti(L, 11, iIndex); } else { - pAnim = luaT_testuserdata(L, -1, luaT_upvalueindex(2)); + pAnim = luaT_testuserdata(L, -1, luaT_upvalueindex(2)); lua_pop(L, 1); } ++iIndex; @@ -145,92 +157,123 @@ static int l_map_settemperaturedisplay(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iTD = luaL_checkint(L, 2) - 1; - if (iTD >= THMT_Count) iTD = THMT_Red; - pMap->setTemperatureDisplay((THMapTemperatureDisplay)iTD); + level_map* pMap = luaT_testuserdata(L); + lua_Integer iTD = luaL_checkinteger(L, 2); + + temperature_theme temperatureDisplay; + switch(iTD) { + case 1: + temperatureDisplay = temperature_theme::red; + break; + case 2: + temperatureDisplay = temperature_theme::multi_colour; + break; + case 3: + temperatureDisplay = temperature_theme::yellow_red; + break; + default: + return luaL_argerror(L, 2, "TemperatureDisplay index out of bounds"); + } + + pMap->set_temperature_display(temperatureDisplay); + return 1; } static int l_map_updatetemperature(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); + level_map* pMap = luaT_testuserdata(L); uint16_t iAir = l_check_temp(L, 2); uint16_t iRadiator = l_check_temp(L, 3); - pMap->updateTemperatures(iAir, iRadiator); + pMap->update_temperatures(iAir, iRadiator); lua_settop(L, 1); return 1; } static int l_map_gettemperature(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX = luaL_checkint(L, 2) - 1; - int iY = luaL_checkint(L, 3) - 1; - const THMapNode* pNode = pMap->getNode(iX, iY); - uint16_t iTemp = pMap->getNodeTemperature(pNode); + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2)) - 1; + int iY = static_cast(luaL_checkinteger(L, 3)) - 1; + const map_tile* pNode = pMap->get_tile(iX, iY); + uint16_t iTemp = pMap->get_tile_temperature(pNode); lua_pushnumber(L, static_cast(iTemp) / static_cast(65535)); return 1; } +/** + * Is the tile position valid for a new room? + * @param entire_invalid Entire blueprint is invalid (eg wrong position or too small). + * @param pNode Tile to examine. + * @param pMap The world map. + * @param player_id The player to check for. + * @return Whether the tile position is valid for a new room. + */ +static inline bool is_valid( + bool entire_invalid, const map_tile *pNode, + const level_map* pMap, int player_id) +{ + return !entire_invalid && !pNode->flags.room && pNode->flags.buildable && + (player_id == 0 || pMap->get_tile_owner(pNode) == player_id); +} + static int l_map_updateblueprint(lua_State *L) { // NB: This function can be implemented in Lua, but is implemented in C for // efficiency. - const unsigned short iFloorTileGood = 24 + (THDF_Alpha50 << 8); - const unsigned short iFloorTileGoodCenter = 37 + (THDF_Alpha50 << 8); - const unsigned short iFloorTileBad = 67 + (THDF_Alpha50 << 8); + const unsigned short iFloorTileGood = 24 + (thdf_alpha_50 << 8); + const unsigned short iFloorTileGoodCenter = 37 + (thdf_alpha_50 << 8); + const unsigned short iFloorTileBad = 67 + (thdf_alpha_50 << 8); const unsigned int iWallAnimTopCorner = 124; const unsigned int iWallAnim = 120; - THMap* pMap = luaT_testuserdata(L); - int iOldX = luaL_checkint(L, 2) - 1; - int iOldY = luaL_checkint(L, 3) - 1; - int iOldW = luaL_checkint(L, 4); - int iOldH = luaL_checkint(L, 5); - int iNewX = luaL_checkint(L, 6) - 1; - int iNewY = luaL_checkint(L, 7) - 1; - int iNewW = luaL_checkint(L, 8); - int iNewH = luaL_checkint(L, 9); - luaL_checktype(L, 10, LUA_TTABLE); // Animation list - THAnimationManager* pAnims = luaT_testuserdata(L, 11, luaT_upvalueindex(1)); - bool entire_invalid = lua_toboolean(L, 12) != 0; + level_map* pMap = luaT_testuserdata(L); + int iOldX = static_cast(luaL_checkinteger(L, 2)) - 1; + int iOldY = static_cast(luaL_checkinteger(L, 3)) - 1; + int iOldW = static_cast(luaL_checkinteger(L, 4)); + int iOldH = static_cast(luaL_checkinteger(L, 5)); + int iNewX = static_cast(luaL_checkinteger(L, 6)) - 1; + int iNewY = static_cast(luaL_checkinteger(L, 7)) - 1; + int iNewW = static_cast(luaL_checkinteger(L, 8)); + int iNewH = static_cast(luaL_checkinteger(L, 9)); + int player_id = static_cast(luaL_checkinteger(L, 10)); + + luaL_checktype(L, 11, LUA_TTABLE); // Animation list + animation_manager* pAnims = luaT_testuserdata(L, 12, luaT_upvalueindex(1)); + bool entire_invalid = lua_toboolean(L, 13) != 0; bool valid = !entire_invalid; - if(iOldX < 0 || iOldY < 0 || (iOldX + iOldW) > pMap->getWidth() || (iOldY + iOldH) > pMap->getHeight()) + if(iOldX < 0 || iOldY < 0 || (iOldX + iOldW) > pMap->get_width() || (iOldY + iOldH) > pMap->get_height()) luaL_argerror(L, 2, "Old rectangle is out of bounds"); - if(iNewX < 0 || iNewY < 0 || (iNewX + iNewW) >= pMap->getWidth() || (iNewY + iNewH) >= pMap->getHeight()) + if(iNewX < 0 || iNewY < 0 || (iNewX + iNewW) >= pMap->get_width() || (iNewY + iNewH) >= pMap->get_height()) luaL_argerror(L, 6, "New rectangle is out of bounds"); - // Clear old floor tiles + // Clear blueprint flag from previous selected floor tiles (copying it to the passable flag). for(int iY = iOldY; iY < iOldY + iOldH; ++iY) { for(int iX = iOldX; iX < iOldX + iOldW; ++iX) { - THMapNode *pNode = pMap->getNodeUnchecked(iX, iY); + map_tile *pNode = pMap->get_tile_unchecked(iX, iY); pNode->iBlock[3] = 0; - pNode->iFlags |= (pNode->iFlags & THMN_PassableIfNotForBlueprint) >> THMN_PassableIfNotForBlueprint_ShiftDelta; - pNode->iFlags &= ~THMN_PassableIfNotForBlueprint; + pNode->flags.passable |= pNode->flags.passable_if_not_for_blueprint; + pNode->flags.passable_if_not_for_blueprint = false; } } -#define IsValid(node) \ - (!entire_invalid && (((node)->iFlags & (THMN_Buildable | THMN_Room)) == THMN_Buildable)) - - // Set new floor tiles + // Add blueprint flag to new floor tiles. for(int iY = iNewY; iY < iNewY + iNewH; ++iY) { for(int iX = iNewX; iX < iNewX + iNewW; ++iX) { - THMapNode *pNode = pMap->getNodeUnchecked(iX, iY); - if(IsValid(pNode)) + map_tile *pNode = pMap->get_tile_unchecked(iX, iY); + if(is_valid(entire_invalid, pNode, pMap, player_id)) pNode->iBlock[3] = iFloorTileGood; else { pNode->iBlock[3] = iFloorTileBad; valid = false; } - pNode->iFlags |= (pNode->iFlags & THMN_Passable) << THMN_PassableIfNotForBlueprint_ShiftDelta; + pNode->flags.passable_if_not_for_blueprint = pNode->flags.passable; } } @@ -240,79 +283,80 @@ int iCenterX = iNewX + (iNewW - 2) / 2; int iCenterY = iNewY + (iNewH - 2) / 2; - THMapNode *pNode = pMap->getNodeUnchecked(iCenterX, iCenterY); + map_tile *pNode = pMap->get_tile_unchecked(iCenterX, iCenterY); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 2; - pNode = pMap->getNodeUnchecked(iCenterX + 1, iCenterY); + + pNode = pMap->get_tile_unchecked(iCenterX + 1, iCenterY); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 1; - pNode = pMap->getNodeUnchecked(iCenterX, iCenterY + 1); + + pNode = pMap->get_tile_unchecked(iCenterX, iCenterY + 1); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 0; - pNode = pMap->getNodeUnchecked(iCenterX + 1, iCenterY + 1); + + pNode = pMap->get_tile_unchecked(iCenterX + 1, iCenterY + 1); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 3; } // Set wall animations int iNextAnim = 1; - THAnimation *pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); - THMapNode *pNode = pMap->getNodeUnchecked(iNewX, iNewY); - pAnim->setAnimation(pAnims, iWallAnimTopCorner); - pAnim->setFlags(THDF_ListBottom | (IsValid(pNode) ? 0 : THDF_AltPalette)); - pAnim->attachToTile(pNode, 0); + animation *pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); + map_tile *pNode = pMap->get_tile_unchecked(iNewX, iNewY); + pAnim->set_animation(pAnims, iWallAnimTopCorner); + pAnim->set_flags(thdf_list_bottom | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); + pAnim->attach_to_tile(pNode, 0); for(int iX = iNewX; iX < iNewX + iNewW; ++iX) { if(iX != iNewX) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); - pNode = pMap->getNodeUnchecked(iX, iNewY); - pAnim->setAnimation(pAnims, iWallAnim); - pAnim->setFlags(THDF_ListBottom | (IsValid(pNode) ? 0 : THDF_AltPalette)); - pAnim->attachToTile(pNode, 0); - pAnim->setPosition(0, 0); + pNode = pMap->get_tile_unchecked(iX, iNewY); + pAnim->set_animation(pAnims, iWallAnim); + pAnim->set_flags(thdf_list_bottom | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); + pAnim->attach_to_tile(pNode, 0); + pAnim->set_position(0, 0); } pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); - pNode = pMap->getNodeUnchecked(iX, iNewY + iNewH - 1); - pAnim->setAnimation(pAnims, iWallAnim); - pAnim->setFlags(THDF_ListBottom | (IsValid(pNode) ? 0 : THDF_AltPalette)); - pNode = pMap->getNodeUnchecked(iX, iNewY + iNewH); - pAnim->attachToTile(pNode, 0); - pAnim->setPosition(0, -1); + pNode = pMap->get_tile_unchecked(iX, iNewY + iNewH - 1); + pAnim->set_animation(pAnims, iWallAnim); + pAnim->set_flags(thdf_list_bottom | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); + pNode = pMap->get_tile_unchecked(iX, iNewY + iNewH); + pAnim->attach_to_tile(pNode, 0); + pAnim->set_position(0, -1); } for(int iY = iNewY; iY < iNewY + iNewH; ++iY) { if(iY != iNewY) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); - pNode = pMap->getNodeUnchecked(iNewX, iY); - pAnim->setAnimation(pAnims, iWallAnim); - pAnim->setFlags(THDF_ListBottom | THDF_FlipHorizontal | (IsValid(pNode) ? 0 : THDF_AltPalette)); - pAnim->attachToTile(pNode, 0); - pAnim->setPosition(2, 0); + pNode = pMap->get_tile_unchecked(iNewX, iY); + pAnim->set_animation(pAnims, iWallAnim); + pAnim->set_flags(thdf_list_bottom | thdf_flip_horizontal | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); + pAnim->attach_to_tile(pNode, 0); + pAnim->set_position(2, 0); } pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); - pNode = pMap->getNodeUnchecked(iNewX + iNewW - 1, iY); - pAnim->setAnimation(pAnims, iWallAnim); - pAnim->setFlags(THDF_ListBottom | THDF_FlipHorizontal | (IsValid(pNode) ? 0 : THDF_AltPalette)); - pNode = pMap->getNodeUnchecked(iNewX + iNewW, iY); - pAnim->attachToTile(pNode, 0); - pAnim->setPosition(2, -1); + pNode = pMap->get_tile_unchecked(iNewX + iNewW - 1, iY); + pAnim->set_animation(pAnims, iWallAnim); + pAnim->set_flags(thdf_list_bottom | thdf_flip_horizontal | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); + pNode = pMap->get_tile_unchecked(iNewX + iNewW, iY); + pAnim->attach_to_tile(pNode, 0); + pAnim->set_position(2, -1); } -#undef IsValid - // Clear away extra animations - int iAnimCount = (int)lua_objlen(L, 10); + int iAnimCount = (int)lua_objlen(L, 11); if(iAnimCount >= iNextAnim) { for(int i = iNextAnim; i <= iAnimCount; ++i) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); - pAnim->removeFromTile(); + pAnim->remove_from_tile(); lua_pushnil(L); - lua_rawseti(L, 10, i); + lua_rawseti(L, 11, i); } } @@ -322,25 +366,41 @@ static int l_map_getsize(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - lua_pushinteger(L, pMap->getWidth()); - lua_pushinteger(L, pMap->getHeight()); + level_map* pMap = luaT_testuserdata(L); + lua_pushinteger(L, pMap->get_width()); + lua_pushinteger(L, pMap->get_height()); return 2; } static int l_map_get_player_count(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - lua_pushinteger(L, pMap->getPlayerCount()); + level_map* pMap = luaT_testuserdata(L); + lua_pushinteger(L, pMap->get_player_count()); return 1; } +static int l_map_set_player_count(lua_State *L) +{ + level_map* pMap = luaT_testuserdata(L); + int count = static_cast(luaL_checkinteger(L, 2)); + + try + { + pMap->set_player_count(count); + } + catch (std::out_of_range) + { + return luaL_error(L, "Player count out of range %d", count); + } + return 0; +} + static int l_map_get_player_camera(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); + level_map* pMap = luaT_testuserdata(L); int iX, iY; - int iPlayer = luaL_optint(L, 2, 1); - bool bGood = pMap->getPlayerCameraTile(iPlayer - 1, &iX, &iY); + int iPlayer = static_cast(luaL_optinteger(L, 2, 1)); + bool bGood = pMap->get_player_camera_tile(iPlayer - 1, &iX, &iY); if(!bGood) return luaL_error(L, "Player index out of range: %d", iPlayer); lua_pushinteger(L, iX + 1); @@ -348,27 +408,54 @@ return 2; } +static int l_map_set_player_camera(lua_State *L) +{ + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2) - 1); + int iY = static_cast(luaL_checkinteger(L, 3) - 1); + int iPlayer = static_cast(luaL_optinteger(L, 4, 1)); + + if (iPlayer < 1 || iPlayer > player_max) + return luaL_error(L, "Player index out of range: %i", iPlayer); + + pMap->set_player_camera_tile(iPlayer - 1, iX, iY); + return 0; +} + static int l_map_get_player_heliport(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); + level_map* pMap = luaT_testuserdata(L); int iX, iY; - int iPlayer = luaL_optint(L, 2, 1); - bool bGood = pMap->getPlayerHeliportTile(iPlayer - 1, &iX, &iY); - bGood = pMap->getPlayerHeliportTile(iPlayer - 1, &iX, &iY); + int iPlayer = static_cast(luaL_optinteger(L, 2, 1)); + bool bGood = pMap->get_player_heliport_tile(iPlayer - 1, &iX, &iY); if(!bGood) - return luaL_error(L, "Player index out of range: %i", iPlayer); + return luaL_error(L, "Player index out of range: %d", iPlayer); lua_pushinteger(L, iX + 1); - lua_pushinteger(L, iY + 2); + lua_pushinteger(L, iY + 1); return 2; } +static int l_map_set_player_heliport(lua_State *L) +{ + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2) - 1); + int iY = static_cast(luaL_checkinteger(L, 3) - 1); + int iPlayer = static_cast(luaL_optinteger(L, 4, 1)); + + if (iPlayer < 1 || iPlayer > player_max) + return luaL_error(L, "Player index out of range: %i", iPlayer); + + pMap->set_player_heliport_tile(iPlayer - 1, iX, iY); + return 0; +} + static int l_map_getcell(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX = luaL_checkint(L, 2) - 1; // Lua arrays start at 1 - pretend - int iY = luaL_checkint(L, 3) - 1; // the map does too. - THMapNode* pNode = pMap->getNode(iX, iY); - if(pNode == NULL) + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2) - 1); // Lua arrays start at 1 - pretend + int iY = static_cast(luaL_checkinteger(L, 3) - 1); // the map does too. + map_tile* pNode = pMap->get_tile(iX, iY); + if(pNode == nullptr) { return luaL_argerror(L, 2, lua_pushfstring(L, "Map co-ordinates out " "of bounds (%d, %d)", iX + 1, iY + 1)); @@ -383,7 +470,7 @@ } else { - int iLayer = luaL_checkint(L, 4) - 1; + lua_Integer iLayer = luaL_checkinteger(L, 4) - 1; if(iLayer < 0 || iLayer >= 4) return luaL_argerror(L, 4, "Layer index is out of bounds (1-4)"); lua_pushinteger(L, pNode->iBlock[iLayer]); @@ -391,13 +478,67 @@ } } +/** Recognized tile flags by Lua. */ +static const std::map lua_tile_flag_map = { + {"passable", map_tile_flags::key::passable_mask}, + {"hospital", map_tile_flags::key::hospital_mask}, + {"buildable", map_tile_flags::key::buildable_mask}, + {"room", map_tile_flags::key::room_mask}, + {"doorWest", map_tile_flags::key::door_west_mask}, + {"doorNorth", map_tile_flags::key::door_north_mask}, + {"tallWest", map_tile_flags::key::tall_west_mask}, + {"tallNorth", map_tile_flags::key::tall_north_mask}, + {"travelNorth", map_tile_flags::key::can_travel_n_mask}, + {"travelEast", map_tile_flags::key::can_travel_e_mask}, + {"travelSouth", map_tile_flags::key::can_travel_s_mask}, + {"travelWest", map_tile_flags::key::can_travel_w_mask}, + {"doNotIdle", map_tile_flags::key::do_not_idle_mask}, + {"buildableNorth", map_tile_flags::key::buildable_n_mask}, + {"buildableEast", map_tile_flags::key::buildable_e_mask}, + {"buildableSouth", map_tile_flags::key::buildable_s_mask}, + {"buildableWest", map_tile_flags::key::buildable_w_mask}, +}; + +/** + * Add the current value of the \a flag in the \a tile to the output. + * @param L Lua context. + * @param tile Tile to inspect. + * @param flag Flag of the tile to check (and report). + * @param name Name of the flag in Lua code. + */ +static inline void add_cellflag(lua_State *L, const map_tile *tile, + map_tile_flags::key flag, const std::string &name) +{ + lua_pushlstring(L, name.c_str(), name.size()); + lua_pushboolean(L, tile->flags[flag] ? 1 : 0); + lua_settable(L, 4); +} + +/** + * Add the current value of a tile field to the output. + * @param L Lua context. + * @param value Value of the tile field to add. + * @param name Name of the field in Lua code. + */ +static inline void add_cellint(lua_State *L, int value, const std::string &name) +{ + lua_pushlstring(L, name.c_str(), name.size()); + lua_pushinteger(L, value); + lua_settable(L, 4); +} + +/** + * Get the value of all cell flags at a position. + * @param L Lua context. + * @return Number of results of the call. + */ static int l_map_getcellflags(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX = luaL_checkint(L, 2) - 1; // Lua arrays start at 1 - pretend - int iY = luaL_checkint(L, 3) - 1; // the map does too. - THMapNode* pNode = pMap->getNode(iX, iY); - if(pNode == NULL) + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2) - 1); // Lua arrays start at 1 - pretend + int iY = static_cast(luaL_checkinteger(L, 3) - 1); // the map does too. + map_tile* pNode = pMap->get_tile(iX, iY); + if(pNode == nullptr) return luaL_argerror(L, 2, "Map co-ordinates out of bounds"); if(lua_type(L, 4) != LUA_TTABLE) { @@ -409,176 +550,65 @@ lua_settop(L, 4); } -#define Flag(CName, LName) \ - { \ - lua_pushliteral(L, LName); \ - lua_pushboolean(L, (pNode->iFlags & CName) ? 1 : 0); \ - lua_settable(L, 4); \ - } - -#define FlagInt(CField, LName) \ - { \ - lua_pushliteral(L, LName); \ - lua_pushinteger(L, pNode->CField); \ - lua_settable(L, 4); \ + // Fill Lua table with the flags and numbers of the tile. + for (auto val : lua_tile_flag_map) + { + add_cellflag(L, pNode, val.second, val.first); } - - - Flag(THMN_Passable, "passable") - Flag(THMN_Hospital, "hospital") - Flag(THMN_Buildable, "buildable") - Flag(THMN_Room, "room") - Flag(THMN_DoorWest, "doorWest") - Flag(THMN_DoorNorth, "doorNorth") - Flag(THMN_TallWest, "tallWest") - Flag(THMN_TallNorth, "tallNorth") - Flag(THMN_CanTravelN, "travelNorth") - Flag(THMN_CanTravelE, "travelEast") - Flag(THMN_CanTravelS, "travelSouth") - Flag(THMN_CanTravelW, "travelWest") - Flag(THMN_DoNotIdle, "doNotIdle") - Flag(THMN_BuildableN, "buildableNorth") - Flag(THMN_BuildableE, "buildableEast") - Flag(THMN_BuildableS, "buildableSouth") - Flag(THMN_BuildableW, "buildableWest") - FlagInt(iRoomId, "roomId") - FlagInt(iParcelId, "parcelId"); - FlagInt(iFlags >> 24, "thob") - -#undef FlagInt -#undef Flag - + add_cellint(L, pNode->iRoomId, "roomId"); + add_cellint(L, pNode->iParcelId, "parcelId"); + add_cellint(L, pMap->get_tile_owner(pNode), "owner"); + add_cellint(L, static_cast(pNode->objects.empty() ? object_type::no_object : pNode->objects.front()), "thob"); return 1; } - /* because all the thobs are not retrieved when the map is loaded in c lua objects use the afterLoad function to be registered after a load, if the object list would not be cleared it would result in duplication of thobs in the object list. */ static int l_map_erase_thobs(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX = luaL_checkint(L, 2) - 1; // Lua arrays start at 1 - pretend - int iY = luaL_checkint(L, 3) - 1; // the map does too. - THMapNode* pNode = pMap->getNode(iX, iY); - if(pNode == NULL) + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2) - 1); // Lua arrays start at 1 - pretend + int iY = static_cast(luaL_checkinteger(L, 3) - 1); // the map does too. + map_tile* pNode = pMap->get_tile(iX, iY); + if(pNode == nullptr) return luaL_argerror(L, 2, "Map co-ordinates out of bounds"); - if(pNode->iFlags & THMN_ObjectsAlreadyErased) - { - // after the last load the map node already has had its object type list erased - // so the call must be ignored - return 2; - } - if(pNode->pExtendedObjectList) - delete pNode->pExtendedObjectList; - pNode->pExtendedObjectList = NULL; - pNode->iFlags &= 0x00FFFFFF; //erase thob - pNode->iFlags |= THMN_ObjectsAlreadyErased; + pNode->objects.clear(); return 1; } static int l_map_remove_cell_thob(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX = luaL_checkint(L, 2) - 1; // Lua arrays start at 1 - pretend - int iY = luaL_checkint(L, 3) - 1; // the map does too. - THMapNode* pNode = pMap->getNode(iX, iY); - if(pNode == NULL) + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2) - 1); // Lua arrays start at 1 - pretend + int iY = static_cast(luaL_checkinteger(L, 3) - 1); // the map does too. + map_tile* pNode = pMap->get_tile(iX, iY); + if(pNode == nullptr) return luaL_argerror(L, 2, "Map co-ordinates out of bounds"); - int thob = luaL_checkint(L, 4); - if(pNode->pExtendedObjectList == NULL) - { - if(((pNode->iFlags & 0xFF000000) >> 24) == thob) - { - pNode->iFlags &= 0x00FFFFFF; - } - } - else + auto thob = static_cast(luaL_checkinteger(L, 4)); + for(auto iter = pNode->objects.begin(); iter != pNode->objects.end(); iter++) { - int i, nr = *pNode->pExtendedObjectList & 7; - if(((pNode->iFlags & 0xFF000000) >> 24) == thob) - { - pNode->iFlags &= 0x00FFFFFF; - pNode->iFlags |= (*pNode->pExtendedObjectList & (255 << 3)) << 21; - if(nr == 1) - { - delete pNode->pExtendedObjectList; - pNode->pExtendedObjectList = NULL; - } - else - { - // shift all thobs in pExtentedObjectList by 8 bits to the right and update the count - for( i = 0; i < nr - 1; i++) - { - *pNode->pExtendedObjectList &= ~(255 << (3 + (i << 3))); - *pNode->pExtendedObjectList |= (*pNode->pExtendedObjectList & (255 << (3 + ((i + 1) << 3)))) >> 8; - } - *pNode->pExtendedObjectList &= ~(255 << (3 + (nr << 3))); - *pNode->pExtendedObjectList &= ~7; - *pNode->pExtendedObjectList |= (nr - 1); - } - - } - else + if(*iter == thob) { - bool found = false; - for(i = 0; i < nr; i++) - { - - if(((*pNode->pExtendedObjectList & (255 << (3 + (i << 3)))) >> (3 + (i << 3))) == thob) - { - found = true; - //shift all thobs to the left of the found one by 8 bits to the right - for(int j = i; i < nr - 1; i++) - { - *pNode->pExtendedObjectList &= ~(255 << (3 + (j << 3))); - *pNode->pExtendedObjectList |= (*pNode->pExtendedObjectList & (255 << (3 + ((j + 1) << 3)))) >> 8; - } - break; - } - } - if(found) - { - nr--; - if(nr > 0) - { - //delete the last thob in the list and update the count - *pNode->pExtendedObjectList &= ~(255 << (3 + (nr << 3))); - *pNode->pExtendedObjectList &= ~7; - *pNode->pExtendedObjectList |= nr; - } - else - { - delete pNode->pExtendedObjectList; - pNode->pExtendedObjectList = NULL; - } - } + pNode->objects.erase(iter); + break; } } - return 1; + return 1; } static int l_map_setcellflags(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX = luaL_checkint(L, 2) - 1; // Lua arrays start at 1 - pretend - int iY = luaL_checkint(L, 3) - 1; // the map does too. - THMapNode* pNode = pMap->getNode(iX, iY); - if(pNode == NULL) + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2) - 1); // Lua arrays start at 1 - pretend + int iY = static_cast(luaL_checkinteger(L, 3) - 1); // the map does too. + map_tile* pNode = pMap->get_tile(iX, iY); + if(pNode == nullptr) return luaL_argerror(L, 2, "Map co-ordinates out of bounds"); luaL_checktype(L, 4, LUA_TTABLE); lua_settop(L, 4); -#define Flag(CName, LName) \ - if(strcmp(field, LName) == 0) \ - { \ - if(lua_toboolean(L, 6) == 0) \ - pNode->iFlags &= ~CName; \ - else \ - pNode->iFlags |= CName; \ - } else - lua_pushnil(L); while(lua_next(L, 4)) @@ -587,102 +617,67 @@ { const char *field = lua_tostring(L, 5); - - Flag(THMN_Passable, "passable") - Flag(THMN_Hospital, "hospital") - Flag(THMN_Buildable, "buildable") - Flag(THMN_Room, "room") - Flag(THMN_DoorWest, "doorWest") - Flag(THMN_DoorNorth, "doorNorth") - Flag(THMN_TallWest, "tallWest") - Flag(THMN_TallNorth, "tallNorth") - Flag(THMN_CanTravelN, "travelNorth") - Flag(THMN_CanTravelE, "travelEast") - Flag(THMN_CanTravelS, "travelSouth") - Flag(THMN_CanTravelW, "travelWest") - Flag(THMN_DoNotIdle, "doNotIdle") - Flag(THMN_BuildableN, "buildableNorth") - Flag(THMN_BuildableE, "buildableEast") - Flag(THMN_BuildableS, "buildableSouth") - Flag(THMN_BuildableW, "buildableWest") - /* else */ if(strcmp(field, "thob") == 0) + auto iter = lua_tile_flag_map.find(field); + if(iter != lua_tile_flag_map.end()) { - uint64_t x; - uint64_t thob = static_cast(lua_tointeger(L, 6)); - if((pNode->iFlags >> 24) != 0) - { - if(pNode->pExtendedObjectList == NULL) - { - pNode->pExtendedObjectList = new uint64_t; - x = 1; - x |= thob << 3; - *pNode->pExtendedObjectList = x; - } - else - { - x = *pNode->pExtendedObjectList; - int nr = x & 7; - nr++; - x = (x & (~7)) | nr; - uint64_t orAmount = thob << (3 + ((nr - 1) << 3)); - x |= orAmount; - *pNode->pExtendedObjectList = x; - } - } + if (lua_toboolean(L, 6) == 0) + pNode->flags[(*iter).second] = false; else - { - pNode->iFlags |= (thob << 24); - } - } - else if(strcmp(field, "parcelId") == 0) + pNode->flags[(*iter).second] = true; + } + else if (std::strcmp(field, "thob") == 0) + { + auto thob = static_cast(lua_tointeger(L, 6)); + pNode->objects.push_back(thob); + } + else if(std::strcmp(field, "parcelId") == 0) { pNode->iParcelId = static_cast(lua_tointeger(L, 6)); } - else if(strcmp(field, "roomId") == 0) { + else if(std::strcmp(field, "roomId") == 0) + { pNode->iRoomId = static_cast(lua_tointeger(L,6)); } else { luaL_error(L, "Invalid flag \'%s\'", field); } - } + } lua_settop(L, 5); } -#undef Flag - return 0; } static int l_map_setwallflags(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - pMap->setAllWallDrawFlags((unsigned char)luaL_checkint(L, 2)); + level_map* pMap = luaT_testuserdata(L); + pMap->set_all_wall_draw_flags((uint8_t)luaL_checkinteger(L, 2)); lua_settop(L, 1); return 1; } static int l_map_setcell(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX = luaL_checkint(L, 2) - 1; // Lua arrays start at 1 - pretend - int iY = luaL_checkint(L, 3) - 1; // the map does too. - THMapNode* pNode = pMap->getNode(iX, iY); - if(pNode == NULL) + level_map* pMap = luaT_testuserdata(L); + int iX = static_cast(luaL_checkinteger(L, 2) - 1); // Lua arrays start at 1 - pretend + int iY = static_cast(luaL_checkinteger(L, 3) - 1); // the map does too. + map_tile* pNode = pMap->get_tile(iX, iY); + if(pNode == nullptr) return luaL_argerror(L, 2, "Map co-ordinates out of bounds"); if(lua_gettop(L) >= 7) { - pNode->iBlock[0] = (uint16_t)luaL_checkint(L, 4); - pNode->iBlock[1] = (uint16_t)luaL_checkint(L, 5); - pNode->iBlock[2] = (uint16_t)luaL_checkint(L, 6); - pNode->iBlock[3] = (uint16_t)luaL_checkint(L, 7); + pNode->iBlock[0] = (uint16_t)luaL_checkinteger(L, 4); + pNode->iBlock[1] = (uint16_t)luaL_checkinteger(L, 5); + pNode->iBlock[2] = (uint16_t)luaL_checkinteger(L, 6); + pNode->iBlock[3] = (uint16_t)luaL_checkinteger(L, 7); } else { - int iLayer = luaL_checkint(L, 4) - 1; + lua_Integer iLayer = luaL_checkinteger(L, 4) - 1; if(iLayer < 0 || iLayer >= 4) return luaL_argerror(L, 4, "Layer index is out of bounds (1-4)"); - int iBlock = luaL_checkint(L, 5); - pNode->iBlock[iLayer] = (uint16_t)iBlock; + uint16_t iBlock = static_cast(luaL_checkinteger(L, 5)); + pNode->iBlock[iLayer] = iBlock; } lua_settop(L, 1); @@ -691,70 +686,77 @@ static int l_map_updateshadows(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - pMap->updateShadows(); + level_map* pMap = luaT_testuserdata(L); + pMap->update_shadows(); + lua_settop(L, 1); + return 1; +} + +static int l_map_updatepathfinding(lua_State *L) +{ + level_map* pMap = luaT_testuserdata(L); + pMap->update_pathfinding(); lua_settop(L, 1); return 1; } static int l_map_mark_room(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX_ = luaL_checkint(L, 2) - 1; - int iY_ = luaL_checkint(L, 3) - 1; - int iW = luaL_checkint(L, 4); - int iH = luaL_checkint(L, 5); - int iTile = luaL_checkint(L, 6); - int iRoomId = luaL_optint(L, 7, 0); - if(iX_ < 0 || iY_ < 0 || (iX_ + iW) > pMap->getWidth() || (iY_ + iH) > pMap->getHeight()) + level_map* pMap = luaT_testuserdata(L); + int iX_ = static_cast(luaL_checkinteger(L, 2) - 1); + int iY_ = static_cast(luaL_checkinteger(L, 3) - 1); + int iW = static_cast(luaL_checkinteger(L, 4)); + int iH = static_cast(luaL_checkinteger(L, 5)); + uint16_t iTile = static_cast(luaL_checkinteger(L, 6)); + uint16_t iRoomId = static_cast(luaL_optinteger(L, 7, 0)); + + if(iX_ < 0 || iY_ < 0 || (iX_ + iW) > pMap->get_width() || (iY_ + iH) > pMap->get_height()) luaL_argerror(L, 2, "Rectangle is out of bounds"); for(int iY = iY_; iY < iY_ + iH; ++iY) { for(int iX = iX_; iX < iX_ + iW; ++iX) { - THMapNode *pNode = pMap->getNodeUnchecked(iX, iY); + map_tile *pNode = pMap->get_tile_unchecked(iX, iY); pNode->iBlock[0] = iTile; pNode->iBlock[3] = 0; - uint32_t iFlags = pNode->iFlags; - iFlags |= THMN_Room; - iFlags |= (iFlags & THMN_PassableIfNotForBlueprint) >> THMN_PassableIfNotForBlueprint_ShiftDelta; - iFlags &= ~THMN_PassableIfNotForBlueprint; - pNode->iFlags = iFlags; + pNode->flags.room = true; + pNode->flags.passable |= pNode->flags.passable_if_not_for_blueprint; + pNode->flags.passable_if_not_for_blueprint = false; pNode->iRoomId = iRoomId; } } - pMap->updatePathfinding(); - pMap->updateShadows(); + pMap->update_pathfinding(); + pMap->update_shadows(); lua_settop(L, 1); return 1; } static int l_map_unmark_room(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iX_ = luaL_checkint(L, 2) - 1; - int iY_ = luaL_checkint(L, 3) - 1; - int iW = luaL_checkint(L, 4); - int iH = luaL_checkint(L, 5); + level_map* pMap = luaT_testuserdata(L); + int iX_ = static_cast(luaL_checkinteger(L, 2) - 1); + int iY_ = static_cast(luaL_checkinteger(L, 3) - 1); + int iW = static_cast(luaL_checkinteger(L, 4)); + int iH = static_cast(luaL_checkinteger(L, 5)); - if(iX_ < 0 || iY_ < 0 || (iX_ + iW) > pMap->getWidth() || (iY_ + iH) > pMap->getHeight()) + if(iX_ < 0 || iY_ < 0 || (iX_ + iW) > pMap->get_width() || (iY_ + iH) > pMap->get_height()) luaL_argerror(L, 2, "Rectangle is out of bounds"); for(int iY = iY_; iY < iY_ + iH; ++iY) { for(int iX = iX_; iX < iX_ + iW; ++iX) { - THMapNode *pNode = pMap->getNodeUnchecked(iX, iY); - pNode->iBlock[0] = pMap->getOriginalNodeUnchecked(iX, iY)->iBlock[0]; - pNode->iFlags &= ~THMN_Room; + map_tile *pNode = pMap->get_tile_unchecked(iX, iY); + pNode->iBlock[0] = pMap->get_original_tile_unchecked(iX, iY)->iBlock[0]; + pNode->flags.room = false; pNode->iRoomId = 0; } } - pMap->updatePathfinding(); - pMap->updateShadows(); + pMap->update_pathfinding(); + pMap->update_shadows(); lua_settop(L, 1); return 1; @@ -762,11 +764,11 @@ static int l_map_draw(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - THRenderTarget* pCanvas = luaT_testuserdata(L, 2); + level_map* pMap = luaT_testuserdata(L); + render_target* pCanvas = luaT_testuserdata(L, 2); - pMap->draw(pCanvas, luaL_checkint(L, 3), luaL_checkint(L, 4), luaL_checkint(L, 5), - luaL_checkint(L, 6), luaL_optint(L, 7, 0), luaL_optint(L, 8, 0)); + pMap->draw(pCanvas, static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4)), static_cast(luaL_checkinteger(L, 5)), + static_cast(luaL_checkinteger(L, 6)), static_cast(luaL_optinteger(L, 7, 0)), static_cast(luaL_optinteger(L, 8, 0))); lua_settop(L, 1); return 1; @@ -774,9 +776,9 @@ static int l_map_hittest(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - THDrawable* pObject = pMap->hitTest(luaL_checkint(L, 2), luaL_checkint(L, 3)); - if(pObject == NULL) + level_map* pMap = luaT_testuserdata(L); + drawable* pObject = pMap->hit_test(static_cast(luaL_checkinteger(L, 2)), static_cast(luaL_checkinteger(L, 3))); + if(pObject == nullptr) return 0; lua_rawgeti(L, luaT_upvalueindex(1), 1); lua_pushlightuserdata(L, pObject); @@ -786,91 +788,154 @@ static int l_map_get_parcel_tilecount(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - int iParcel = luaL_checkint(L, 2); - int iCount = pMap->getParcelTileCount(iParcel); + level_map* pMap = luaT_testuserdata(L); + int iParcel = static_cast(luaL_checkinteger(L, 2)); + lua_Integer iCount = pMap->get_parcel_tile_count(iParcel); lua_pushinteger(L, iCount); return 1; } static int l_map_get_parcel_count(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - lua_pushinteger(L, pMap->getParcelCount()); + level_map* pMap = luaT_testuserdata(L); + lua_pushinteger(L, pMap->get_parcel_count()); return 1; } static int l_map_set_parcel_owner(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - pMap->setParcelOwner(luaL_checkint(L, 2), luaL_checkint(L, 3)); - lua_settop(L, 1); + level_map* pMap = luaT_testuserdata(L); + int parcelId = static_cast(luaL_checkinteger(L, 2)); + int player = static_cast(luaL_checkinteger(L, 3)); + if(lua_type(L, 4) != LUA_TTABLE) + { + lua_settop(L, 3); + lua_newtable(L); + } + else + { + lua_settop(L, 4); + } + std::vector> vSplitTiles = pMap->set_parcel_owner(parcelId, player); + for (std::vector>::size_type i = 0; i != vSplitTiles.size(); i++) + { + lua_pushinteger(L, i + 1); + lua_createtable(L, 0, 2); + lua_pushinteger(L, 1); + lua_pushinteger(L, vSplitTiles[i].first + 1); + lua_settable(L, 6); + lua_pushinteger(L, 2); + lua_pushinteger(L, vSplitTiles[i].second + 1); + lua_settable(L, 6); + lua_settable(L, 4); + } return 1; } static int l_map_get_parcel_owner(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - lua_pushinteger(L, pMap->getParcelOwner(luaL_checkint(L, 2))); + level_map* pMap = luaT_testuserdata(L); + lua_pushinteger(L, pMap->get_parcel_owner(static_cast(luaL_checkinteger(L, 2)))); return 1; } static int l_map_is_parcel_purchasable(lua_State *L) { - THMap* pMap = luaT_testuserdata(L); - lua_pushboolean(L, pMap->isParcelPurchasable(luaL_checkint(L, 2), - luaL_checkint(L, 3)) ? 1 : 0); + level_map* pMap = luaT_testuserdata(L); + lua_pushboolean(L, pMap->is_parcel_purchasable(static_cast(luaL_checkinteger(L, 2)), + static_cast(luaL_checkinteger(L, 3))) ? 1 : 0); + return 1; +} + +/* Compute the fraction of corridor tiles with litter, of the parcels owned by the given player. */ +static int l_map_get_litter_fraction(lua_State *L) +{ + level_map* pMap = luaT_testuserdata(L); + int owner = static_cast(luaL_checkinteger(L, 2)); + if (owner == 0) + { + lua_pushnumber(L, 0.0); // Outside has no litter. + return 1; + } + + double tile_count = 0; + double litter_count = 0; + for (int x = 0; x < pMap->get_width(); x++) + { + for (int y = 0; y < pMap->get_height(); y++) + { + const map_tile* pNode = pMap->get_tile_unchecked(x, y); + if (pNode->iParcelId == 0 || owner != pMap->get_parcel_owner(pNode->iParcelId) || + pNode->iRoomId != 0) + { + continue; + } + + tile_count++; + for(auto iter = pNode->objects.begin(); iter != pNode->objects.end(); iter++) + { + if(*iter == object_type::litter) + { + litter_count++; + break; + } + } + } + } + + double fraction = (tile_count == 0) ? 0.0 : litter_count / tile_count; + lua_pushnumber(L, fraction); return 1; } static int l_path_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_path_set_map(lua_State *L) { - THPathfinder* pPathfinder = luaT_testuserdata(L); - THMap* pMap = luaT_testuserdata(L, 2); + pathfinder* pPathfinder = luaT_testuserdata(L); + level_map* pMap = luaT_testuserdata(L, 2); lua_settop(L, 2); - pPathfinder->setDefaultMap(pMap); + pPathfinder->set_default_map(pMap); luaT_setenvfield(L, 1, "map"); return 1; } static int l_path_persist(lua_State *L) { - THPathfinder* pPathfinder = luaT_testuserdata(L); + pathfinder* pPathfinder = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - pPathfinder->persist((LuaPersistWriter*)lua_touserdata(L, 1)); + pPathfinder->persist((lua_persist_writer*)lua_touserdata(L, 1)); return 0; } static int l_path_depersist(lua_State *L) { - THPathfinder* pPathfinder = luaT_testuserdata(L); + pathfinder* pPathfinder = luaT_testuserdata(L); lua_settop(L, 2); lua_insert(L, 1); - LuaPersistReader* pReader = (LuaPersistReader*)lua_touserdata(L, 1); + lua_persist_reader* pReader = (lua_persist_reader*)lua_touserdata(L, 1); pPathfinder->depersist(pReader); luaT_getenvfield(L, 2, "map"); - pPathfinder->setDefaultMap(reinterpret_cast(lua_touserdata(L, -1))); + pPathfinder->set_default_map(reinterpret_cast(lua_touserdata(L, -1))); return 0; } static int l_path_is_reachable_from_hospital(lua_State *L) { - THPathfinder* pPathfinder = luaT_testuserdata(L); - if(pPathfinder->findPathToHospital(NULL, luaL_checkint(L, 2) - 1, - luaL_checkint(L, 3) - 1)) + pathfinder* pPathfinder = luaT_testuserdata(L); + if(pPathfinder->find_path_to_hospital(nullptr, static_cast(luaL_checkinteger(L, 2) - 1), + static_cast(luaL_checkinteger(L, 3) - 1))) { lua_pushboolean(L, 1); int iX, iY; - pPathfinder->getPathEnd(&iX, &iY); + pPathfinder->get_path_end(&iX, &iY); lua_pushinteger(L, iX + 1); lua_pushinteger(L, iY + 1); return 3; @@ -884,11 +949,11 @@ static int l_path_distance(lua_State *L) { - THPathfinder* pPathfinder = luaT_testuserdata(L); - if(pPathfinder->findPath(NULL, luaL_checkint(L, 2) - 1, luaL_checkint(L, 3) - 1, - luaL_checkint(L, 4) - 1, luaL_checkint(L, 5) - 1)) + pathfinder* pPathfinder = luaT_testuserdata(L); + if(pPathfinder->find_path(nullptr, static_cast(luaL_checkinteger(L, 2)) - 1, static_cast(luaL_checkinteger(L, 3)) - 1, + static_cast(luaL_checkinteger(L, 4)) - 1, static_cast(luaL_checkinteger(L, 5)) - 1)) { - lua_pushinteger(L, pPathfinder->getPathLength()); + lua_pushinteger(L, pPathfinder->get_path_length()); } else { @@ -899,23 +964,23 @@ static int l_path_path(lua_State *L) { - THPathfinder* pPathfinder = luaT_testuserdata(L); - pPathfinder->findPath(NULL, luaL_checkint(L, 2) - 1, luaL_checkint(L, 3) - 1, - luaL_checkint(L, 4) - 1, luaL_checkint(L, 5) - 1); - pPathfinder->pushResult(L); + pathfinder* pPathfinder = luaT_testuserdata(L); + pPathfinder->find_path(nullptr, static_cast(luaL_checkinteger(L, 2)) - 1, static_cast(luaL_checkinteger(L, 3)) - 1, + static_cast(luaL_checkinteger(L, 4)) - 1, static_cast(luaL_checkinteger(L, 5)) - 1); + pPathfinder->push_result(L); return 2; } static int l_path_idle(lua_State *L) { - THPathfinder* pPathfinder = luaT_testuserdata(L); - if(!pPathfinder->findIdleTile(NULL, luaL_checkint(L, 2) - 1, - luaL_checkint(L, 3) - 1, luaL_optint(L, 4, 0))) + pathfinder* pPathfinder = luaT_testuserdata(L); + if(!pPathfinder->find_idle_tile(nullptr, static_cast(luaL_checkinteger(L, 2)) - 1, + static_cast(luaL_checkinteger(L, 3)) - 1, static_cast(luaL_optinteger(L, 4, 0)))) { return 0; } int iX, iY; - pPathfinder->getPathEnd(&iX, &iY); + pPathfinder->get_path_end(&iX, &iY); lua_pushinteger(L, iX + 1); lua_pushinteger(L, iY + 1); return 2; @@ -923,26 +988,30 @@ static int l_path_visit(lua_State *L) { - THPathfinder* pPathfinder = luaT_testuserdata(L); + pathfinder* pPathfinder = luaT_testuserdata(L); luaL_checktype(L, 6, LUA_TFUNCTION); - lua_pushboolean(L, pPathfinder->visitObjects(NULL, luaL_checkint(L, 2) - 1, - luaL_checkint(L, 3) - 1, static_cast(luaL_checkint(L, 4)), - luaL_checkint(L, 5), L, 6, luaL_checkint(L, 4) == 0 ? true : false) ? 1 : 0); + lua_pushboolean(L, pPathfinder->visit_objects(nullptr, static_cast(luaL_checkinteger(L, 2)) - 1, + static_cast(luaL_checkinteger(L, 3)) - 1, static_cast(luaL_checkinteger(L, 4)), + static_cast(luaL_checkinteger(L, 5)), L, 6, luaL_checkinteger(L, 4) == 0 ? true : false) ? 1 : 0); return 1; } -void THLuaRegisterMap(const THLuaRegisterState_t *pState) +void lua_register_map(const lua_register_state *pState) { // Map - luaT_class(THMap, l_map_new, "map", MT_Map); - luaT_setmetamethod(l_map_persist, "persist", MT_Anim); - luaT_setmetamethod(l_map_depersist, "depersist", MT_Anim); + luaT_class(level_map, l_map_new, "map", lua_metatable::map); + luaT_setmetamethod(l_map_persist, "persist", lua_metatable::anim); + luaT_setmetamethod(l_map_depersist, "depersist", lua_metatable::anim); luaT_setfunction(l_map_load, "load"); luaT_setfunction(l_map_loadblank, "loadBlank"); + luaT_setfunction(l_map_save, "save"); luaT_setfunction(l_map_getsize, "size"); luaT_setfunction(l_map_get_player_count, "getPlayerCount"); + luaT_setfunction(l_map_set_player_count, "setPlayerCount"); luaT_setfunction(l_map_get_player_camera, "getCameraTile"); + luaT_setfunction(l_map_set_player_camera, "setCameraTile"); luaT_setfunction(l_map_get_player_heliport, "getHeliportTile"); + luaT_setfunction(l_map_set_player_heliport, "setHeliportTile"); luaT_setfunction(l_map_getcell, "getCell"); luaT_setfunction(l_map_gettemperature, "getCellTemperature"); luaT_setfunction(l_map_getcellflags, "getCellFlags"); @@ -951,13 +1020,14 @@ luaT_setfunction(l_map_setwallflags, "setWallDrawFlags"); luaT_setfunction(l_map_settemperaturedisplay, "setTemperatureDisplay"); luaT_setfunction(l_map_updatetemperature, "updateTemperatures"); - luaT_setfunction(l_map_updateblueprint, "updateRoomBlueprint", MT_Anims, MT_Anim); + luaT_setfunction(l_map_updateblueprint, "updateRoomBlueprint", lua_metatable::anims, lua_metatable::anim); luaT_setfunction(l_map_updateshadows, "updateShadows"); + luaT_setfunction(l_map_updatepathfinding, "updatePathfinding"); luaT_setfunction(l_map_mark_room, "markRoom"); luaT_setfunction(l_map_unmark_room, "unmarkRoom"); - luaT_setfunction(l_map_set_sheet, "setSheet", MT_Sheet); - luaT_setfunction(l_map_draw, "draw", MT_Surface); - luaT_setfunction(l_map_hittest, "hitTestObjects", MT_Anim); + luaT_setfunction(l_map_set_sheet, "setSheet", lua_metatable::sheet); + luaT_setfunction(l_map_draw, "draw", lua_metatable::surface); + luaT_setfunction(l_map_hittest, "hitTestObjects", lua_metatable::anim); luaT_setfunction(l_map_get_parcel_tilecount, "getParcelTileCount"); luaT_setfunction(l_map_get_parcel_count, "getPlotCount"); luaT_setfunction(l_map_set_parcel_owner, "setPlotOwner"); @@ -965,10 +1035,11 @@ luaT_setfunction(l_map_is_parcel_purchasable, "isParcelPurchasable"); luaT_setfunction(l_map_erase_thobs, "eraseObjectTypes"); luaT_setfunction(l_map_remove_cell_thob, "removeObjectType"); + luaT_setfunction(l_map_get_litter_fraction, "getLitterFraction"); luaT_endclass(); // Pathfinder - luaT_class(THPathfinder, l_path_new, "pathfinder", MT_Path); + luaT_class(pathfinder, l_path_new, "pathfinder", lua_metatable::pathfinder); luaT_setmetamethod(l_path_persist, "persist"); luaT_setmetamethod(l_path_depersist, "depersist"); luaT_setfunction(l_path_distance, "findDistance"); @@ -976,6 +1047,6 @@ luaT_setfunction(l_path_path, "findPath"); luaT_setfunction(l_path_idle, "findIdleTile"); luaT_setfunction(l_path_visit, "findObject"); - luaT_setfunction(l_path_set_map, "setMap", MT_Map); + luaT_setfunction(l_path_set_map, "setMap", lua_metatable::map); luaT_endclass(); } diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_movie.cpp corsix-th-0.62/CorsixTH/Src/th_lua_movie.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua_movie.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_movie.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -22,17 +22,26 @@ #include "th_lua_internal.h" #include "th_movie.h" +#include "th_gfx.h" static int l_movie_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } +static int l_movie_set_renderer(lua_State *L) +{ + movie_player *pMovie = luaT_testuserdata(L); + render_target *pRenderTarget = luaT_testuserdata(L, 2); + pMovie->set_renderer(pRenderTarget->get_renderer()); + return 0; +} + static int l_movie_enabled(lua_State *L) { - THMovie *pMovie = luaT_testuserdata(L); - lua_pushboolean(L, pMovie->moviesEnabled()); + movie_player *pMovie = luaT_testuserdata(L); + lua_pushboolean(L, pMovie->movies_enabled()); return 1; } @@ -40,11 +49,11 @@ { bool loaded; const char* warning; - THMovie *pMovie = luaT_testuserdata(L); - const char* filepath = lua_tolstring(L, 2, NULL); - pMovie->clearLastError(); + movie_player *pMovie = luaT_testuserdata(L); + const char* filepath = lua_tolstring(L, 2, nullptr); + pMovie->clear_last_error(); loaded = pMovie->load(filepath); - warning = pMovie->getLastError(); + warning = pMovie->get_last_error(); lua_pushboolean(L, loaded); lua_pushstring(L, warning); return 2; @@ -52,7 +61,7 @@ static int l_movie_unload(lua_State *L) { - THMovie *pMovie = luaT_testuserdata(L); + movie_player *pMovie = luaT_testuserdata(L); pMovie->unload(); return 0; } @@ -60,73 +69,72 @@ static int l_movie_play(lua_State *L) { const char* warning; - THMovie *pMovie = luaT_testuserdata(L); - pMovie->clearLastError(); - pMovie->play(luaL_checkinteger(L, 2), luaL_checkinteger(L, 3), luaL_checkinteger(L, 4), luaL_checkinteger(L, 5), luaL_checkinteger(L, 6)); - warning = pMovie->getLastError(); + movie_player *pMovie = luaT_testuserdata(L); + pMovie->clear_last_error(); + pMovie->play( + static_cast(luaL_checkinteger(L, 2))); + warning = pMovie->get_last_error(); lua_pushstring(L, warning); return 1; } static int l_movie_stop(lua_State *L) { - THMovie *pVideo = luaT_testuserdata(L); + movie_player *pVideo = luaT_testuserdata(L); pVideo->stop(); return 0; } static int l_movie_get_native_height(lua_State *L) { - THMovie *pMovie = luaT_testuserdata(L); - lua_pushinteger(L, pMovie->getNativeHeight()); + movie_player *pMovie = luaT_testuserdata(L); + lua_pushinteger(L, pMovie->get_native_height()); return 1; } static int l_movie_get_native_width(lua_State *L) { - THMovie *pMovie = luaT_testuserdata(L); - lua_pushinteger(L, pMovie->getNativeWidth()); + movie_player *pMovie = luaT_testuserdata(L); + lua_pushinteger(L, pMovie->get_native_width()); return 1; } static int l_movie_has_audio_track(lua_State *L) { - THMovie *pMovie = luaT_testuserdata(L); - lua_pushboolean(L, pMovie->hasAudioTrack()); - return 1; -} - -static int l_movie_requires_video_reset(lua_State *L) -{ - THMovie *pMovie = luaT_testuserdata(L); - lua_pushboolean(L, pMovie->requiresVideoReset()); + movie_player *pMovie = luaT_testuserdata(L); + lua_pushboolean(L, pMovie->has_audio_track()); return 1; } static int l_movie_refresh(lua_State *L) { - THMovie *pMovie = luaT_testuserdata(L); - pMovie->refresh(); + movie_player *pMovie = luaT_testuserdata(L); + pMovie->refresh(SDL_Rect{ + static_cast(luaL_checkinteger(L, 2)), + static_cast(luaL_checkinteger(L, 3)), + static_cast(luaL_checkinteger(L, 4)), + static_cast(luaL_checkinteger(L, 5)) }); return 0; } static int l_movie_allocate_picture_buffer(lua_State *L) { - THMovie *pMovie = luaT_testuserdata(L); - pMovie->allocatePictureBuffer(); + movie_player *pMovie = luaT_testuserdata(L); + pMovie->allocate_picture_buffer(); return 0; } static int l_movie_deallocate_picture_buffer(lua_State *L) { - THMovie *pMovie = luaT_testuserdata(L); - pMovie->deallocatePictureBuffer(); + movie_player *pMovie = luaT_testuserdata(L); + pMovie->deallocate_picture_buffer(); return 0; } -void THLuaRegisterMovie(const THLuaRegisterState_t *pState) +void lua_register_movie(const lua_register_state *pState) { - luaT_class(THMovie, l_movie_new, "moviePlayer", MT_Movie); + luaT_class(movie_player, l_movie_new, "moviePlayer", lua_metatable::movie); + luaT_setfunction(l_movie_set_renderer, "setRenderer", lua_metatable::surface); luaT_setfunction(l_movie_enabled, "getEnabled"); luaT_setfunction(l_movie_load, "load"); luaT_setfunction(l_movie_unload, "unload"); @@ -135,7 +143,6 @@ luaT_setfunction(l_movie_get_native_height, "getNativeHeight"); luaT_setfunction(l_movie_get_native_width, "getNativeWidth"); luaT_setfunction(l_movie_has_audio_track, "hasAudioTrack"); - luaT_setfunction(l_movie_requires_video_reset, "requiresVideoReset"); luaT_setfunction(l_movie_refresh, "refresh"); luaT_setfunction(l_movie_allocate_picture_buffer, "allocatePictureBuffer"); luaT_setfunction(l_movie_deallocate_picture_buffer, "deallocatePictureBuffer"); diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_sound.cpp corsix-th-0.62/CorsixTH/Src/th_lua_sound.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua_sound.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_sound.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -22,20 +22,29 @@ #include "th_lua_internal.h" #include "th_sound.h" +#include "th_lua.h" +#include "lua_sdl.h" +#include +#include +#include + +static int played_sound_callback_ids[1000]; +static int played_sound_callback_index = 0; +static std::map map_sound_timers; static int l_soundarc_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_soundarc_load(lua_State *L) { - THSoundArchive* pArchive = luaT_testuserdata(L); + sound_archive* pArchive = luaT_testuserdata(L); size_t iDataLen; - const unsigned char* pData = luaT_checkfile(L, 2, &iDataLen); + const uint8_t* pData = luaT_checkfile(L, 2, &iDataLen); - if(pArchive->loadFromTHFile(pData, iDataLen)) + if(pArchive->load_from_th_file(pData, iDataLen)) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); @@ -44,23 +53,43 @@ static int l_soundarc_count(lua_State *L) { - THSoundArchive* pArchive = luaT_testuserdata(L); - lua_pushnumber(L, (lua_Number)pArchive->getSoundCount()); + sound_archive* pArchive = luaT_testuserdata(L); + lua_pushnumber(L, (lua_Number)pArchive->get_number_of_sounds()); return 1; } -static size_t l_soundarc_checkidx(lua_State *L, int iArg, THSoundArchive* pArchive) +/** + * Perform case-insensitive string compare. + * @param s1 First string to compare. + * @param s2 Second string to compare. + * @return Negative number when \a s1 should be before \a s2, zero if both + * string are equal, else a positive number. + */ +static int ignorecase_cmp(const char *s1, const char *s2) +{ + while(*s1 && *s2) + { + if (std::tolower(*s1) != std::tolower(*s2)) + break; + + s1++; + s2++; + } + return std::tolower(*s1) - std::tolower(*s2); +} + +static size_t l_soundarc_checkidx(lua_State *L, int iArg, sound_archive* pArchive) { if(lua_isnumber(L, iArg)) { size_t iIndex = (size_t)lua_tonumber(L, iArg); - if(iIndex >= pArchive->getSoundCount()) + if(iIndex >= pArchive->get_number_of_sounds()) { lua_pushnil(L); lua_pushfstring(L, "Sound index out of " "bounds (%f is not in range [0, %d])", lua_tonumber(L, iArg), - static_cast(pArchive->getSoundCount()) - 1); - return pArchive->getSoundCount(); + static_cast(pArchive->get_number_of_sounds()) - 1); + return pArchive->get_number_of_sounds(); } return iIndex; } @@ -75,10 +104,10 @@ return iIndex; } lua_pop(L, 2); - size_t iCount = pArchive->getSoundCount(); + size_t iCount = pArchive->get_number_of_sounds(); for(size_t i = 0; i < iCount; ++i) { - if(stricmp(sName, pArchive->getSoundFilename(i)) == 0) + if(ignorecase_cmp(sName, pArchive->get_sound_name(i)) == 0) { lua_getfenv(L, 1); lua_pushvalue(L, iArg); @@ -92,40 +121,40 @@ lua_pushliteral(L, "File not found in sound archive: "); lua_pushvalue(L, iArg); lua_concat(L, 2); - return pArchive->getSoundCount(); + return pArchive->get_number_of_sounds(); } -static int l_soundarc_filename(lua_State *L) +static int l_soundarc_sound_name(lua_State *L) { - THSoundArchive* pArchive = luaT_testuserdata(L); + sound_archive* pArchive = luaT_testuserdata(L); size_t iIndex = l_soundarc_checkidx(L, 2, pArchive); - if(iIndex == pArchive->getSoundCount()) + if(iIndex == pArchive->get_number_of_sounds()) return 2; - lua_pushstring(L, pArchive->getSoundFilename(iIndex)); + lua_pushstring(L, pArchive->get_sound_name(iIndex)); return 1; } static int l_soundarc_duration(lua_State *L) { - THSoundArchive* pArchive = luaT_testuserdata(L); + sound_archive* pArchive = luaT_testuserdata(L); size_t iIndex = l_soundarc_checkidx(L, 2, pArchive); - if(iIndex == pArchive->getSoundCount()) + if(iIndex == pArchive->get_number_of_sounds()) return 2; - size_t iDuration = pArchive->getSoundDuration(iIndex); + size_t iDuration = pArchive->get_sound_duration(iIndex); lua_pushnumber(L, static_cast(iDuration) / static_cast(1000)); return 1; } -static int l_soundarc_filedata(lua_State *L) +static int l_soundarc_data(lua_State *L) { - THSoundArchive* pArchive = luaT_testuserdata(L); + sound_archive* pArchive = luaT_testuserdata(L); size_t iIndex = l_soundarc_checkidx(L, 2, pArchive); - if(iIndex == pArchive->getSoundCount()) + if(iIndex == pArchive->get_number_of_sounds()) return 2; - SDL_RWops *pRWops = pArchive->loadSound(iIndex); + SDL_RWops *pRWops = pArchive->load_sound(iIndex); if(!pRWops) return 0; - int iLength = SDL_RWseek(pRWops, 0, SEEK_END); + size_t iLength = SDL_RWseek(pRWops, 0, SEEK_END); SDL_RWseek(pRWops, 0, SEEK_SET); // There is a potential leak of pRWops if either of these Lua calls cause // a memory error, but it isn't very likely, and this a debugging function @@ -139,9 +168,9 @@ static int l_soundarc_sound_exists(lua_State *L) { - THSoundArchive* pArchive = luaT_testuserdata(L); + sound_archive* pArchive = luaT_testuserdata(L); size_t iIndex = l_soundarc_checkidx(L, 2, pArchive); - if(iIndex == pArchive->getSoundCount()) + if(iIndex == pArchive->get_number_of_sounds()) lua_pushboolean(L, 0); else lua_pushboolean(L, 1); @@ -150,15 +179,15 @@ static int l_soundfx_new(lua_State *L) { - luaT_stdnew(L, luaT_environindex, true); + luaT_stdnew(L, luaT_environindex, true); return 1; } static int l_soundfx_set_archive(lua_State *L) { - THSoundEffects *pEffects = luaT_testuserdata(L); - THSoundArchive *pArchive = luaT_testuserdata(L, 2); - pEffects->setSoundArchive(pArchive); + sound_player *pEffects = luaT_testuserdata(L); + sound_archive *pArchive = luaT_testuserdata(L, 2); + pEffects->populate_from(pArchive); lua_settop(L, 2); luaT_setenvfield(L, 1, "archive"); return 1; @@ -166,85 +195,119 @@ static int l_soundfx_set_sound_volume(lua_State *L) { - THSoundEffects *pEffects = luaT_testuserdata(L); - pEffects->setSoundEffectsVolume(luaL_checknumber(L, 2)); + sound_player *pEffects = luaT_testuserdata(L); + pEffects->set_sound_effect_volume(luaL_checknumber(L, 2)); return 1; } static int l_soundfx_set_sound_effects_on(lua_State *L) { - THSoundEffects *pEffects = luaT_testuserdata(L); - pEffects->setSoundEffectsOn(lua_toboolean(L, 2) != 0); + sound_player *pEffects = luaT_testuserdata(L); + pEffects->set_sound_effects_enabled(lua_toboolean(L, 2) != 0); return 1; } +static Uint32 played_sound_callback(Uint32 interval, void* param) +{ + SDL_Event e; + e.type = SDL_USEREVENT_SOUND_OVER; + e.user.data1 = param; + int iSoundID = *(static_cast(param)); + SDL_RemoveTimer(map_sound_timers[iSoundID]); + map_sound_timers.erase(iSoundID); + SDL_PushEvent(&e); + + return interval; +} + static int l_soundfx_play(lua_State *L) { - THSoundEffects *pEffects = luaT_testuserdata(L); - lua_settop(L, 5); + sound_player *pEffects = luaT_testuserdata(L); + lua_settop(L, 7); lua_getfenv(L, 1); lua_pushliteral(L, "archive"); - lua_rawget(L, 6); - THSoundArchive *pArchive = (THSoundArchive*)lua_touserdata(L, 7); - if(pArchive == NULL) + lua_rawget(L,8); + sound_archive *pArchive = (sound_archive*)lua_touserdata(L, 9); + if(pArchive == nullptr) { return 0; } // l_soundarc_checkidx requires the archive at the bottom of the stack lua_replace(L, 1); size_t iIndex = l_soundarc_checkidx(L, 2, pArchive); - if(iIndex == pArchive->getSoundCount()) + if(iIndex == pArchive->get_number_of_sounds()) return 2; if(lua_isnil(L, 4)) { - pEffects->playSound(iIndex, luaL_checknumber(L, 3)); + pEffects->play(iIndex, luaL_checknumber(L, 3)); } else { - pEffects->playSoundAt(iIndex, luaL_checknumber(L, 3), luaL_checkint(L, 4), luaL_checkint(L, 5)); + pEffects->play_at(iIndex, luaL_checknumber(L, 3), static_cast(luaL_checkinteger(L, 4)), static_cast(luaL_checkinteger(L, 5))); } + //SDL SOUND_OVER Callback Timer: + //6: unusedPlayedCallbackID + if(!lua_isnil(L, 6)) + { + //7: Callback delay + int iPlayedCallbackDelay = 0; //ms + if(!lua_isnil(L, 7)) + iPlayedCallbackDelay = static_cast(luaL_checknumber(L, 7)); + + if(played_sound_callback_index == sizeof(played_sound_callback_ids)) + played_sound_callback_index = 0; + + played_sound_callback_ids[played_sound_callback_index] = static_cast(luaL_checkinteger(L, 6)); + size_t interval = pArchive->get_sound_duration(iIndex) + iPlayedCallbackDelay; + SDL_TimerID timersID = SDL_AddTimer(static_cast(interval), + played_sound_callback, + &(played_sound_callback_ids[played_sound_callback_index])); + map_sound_timers.insert(std::pair(played_sound_callback_ids[played_sound_callback_index], timersID)); + played_sound_callback_index++; + } + lua_pushboolean(L, 1); return 1; } static int l_soundfx_set_camera(lua_State *L) { - THSoundEffects *pEffects = luaT_testuserdata(L); - pEffects->setCamera(luaL_checkint(L, 2), luaL_checkint(L, 3), luaL_checkint(L, 4)); + sound_player *pEffects = luaT_testuserdata(L); + pEffects->set_camera(static_cast(luaL_checkinteger(L, 2)), static_cast(luaL_checkinteger(L, 3)), static_cast(luaL_checkinteger(L, 4))); return 0; } static int l_soundfx_reserve_channel(lua_State *L) { int iChannel; - THSoundEffects *pEffects = luaT_testuserdata(L); - iChannel = pEffects->reserveChannel(); + sound_player *pEffects = luaT_testuserdata(L); + iChannel = pEffects->reserve_channel(); lua_pushinteger(L, iChannel); return 1; } static int l_soundfx_release_channel(lua_State *L) { - THSoundEffects *pEffects = luaT_testuserdata(L); - pEffects->releaseChannel(luaL_checkinteger(L, 2)); + sound_player *pEffects = luaT_testuserdata(L); + pEffects->release_channel(static_cast(luaL_checkinteger(L, 2))); return 1; } -void THLuaRegisterSound(const THLuaRegisterState_t *pState) +void lua_register_sound(const lua_register_state *pState) { // Sound Archive - luaT_class(THSoundArchive, l_soundarc_new, "soundArchive", MT_SoundArc); + luaT_class(sound_archive, l_soundarc_new, "soundArchive", lua_metatable::sound_archive); luaT_setmetamethod(l_soundarc_count, "len"); luaT_setfunction(l_soundarc_load, "load"); - luaT_setfunction(l_soundarc_filename, "getFilename"); + luaT_setfunction(l_soundarc_sound_name, "getFilename"); // Bad name, doesn't represent a file luaT_setfunction(l_soundarc_duration, "getDuration"); - luaT_setfunction(l_soundarc_filedata, "getFileData"); + luaT_setfunction(l_soundarc_data, "getFileData"); // Bad name, doesn't represent a file luaT_setfunction(l_soundarc_sound_exists, "soundExists"); luaT_endclass(); // Sound Effects - luaT_class(THSoundEffects, l_soundfx_new, "soundEffects", MT_SoundFx); - luaT_setfunction(l_soundfx_set_archive, "setSoundArchive", MT_SoundArc); + luaT_class(sound_player, l_soundfx_new, "soundEffects", lua_metatable::sound_fx); + luaT_setfunction(l_soundfx_set_archive, "setSoundArchive", lua_metatable::sound_archive); luaT_setfunction(l_soundfx_play, "play"); luaT_setfunction(l_soundfx_set_sound_volume, "setSoundVolume"); luaT_setfunction(l_soundfx_set_sound_effects_on, "setSoundEffectsOn"); diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_strings.cpp corsix-th-0.62/CorsixTH/Src/th_lua_strings.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua_strings.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_strings.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -22,7 +22,7 @@ #include "th_lua_internal.h" #include "persist_lua.h" -#include +#include /* This file implements a string proxy system. A string proxy is a userdata @@ -51,22 +51,22 @@ environment. */ -struct THStringProxy_t {}; +class string_proxy {}; // We need 2 lightuserdata keys for naming the weak tables in the registry, // which we get by having 2 bytes of dummy global variables. -unsigned char g_aStringDummyGlobals[2] = {0}; +static uint8_t weak_table_keys[2] = {0}; static inline void aux_push_weak_table(lua_State *L, int iIndex) { - lua_pushlightuserdata(L, &g_aStringDummyGlobals[iIndex]); + lua_pushlightuserdata(L, &weak_table_keys[iIndex]); lua_rawget(L, LUA_REGISTRYINDEX); } // Replace the value at the top of the stack with a userdata proxy static int l_str_new_aux(lua_State *L) { - luaT_stdnew(L); + luaT_stdnew(L); aux_push_weak_table(L, 0); lua_pushvalue(L, -2); lua_pushvalue(L, -4); @@ -188,7 +188,7 @@ { size_t iLen; const char* sKey = lua_tolstring(L, 2, &iLen); - if(iLen == 8 && strcmp(sKey, "__random") == 0) + if(iLen == 8 && std::strcmp(sKey, "__random") == 0) { aux_push_random_key(L); lua_replace(L, 2); @@ -444,12 +444,12 @@ { lua_settop(L, 2); lua_insert(L, 1); - LuaPersistWriter *pWriter = (LuaPersistWriter*)lua_touserdata(L, 1); + lua_persist_writer *pWriter = (lua_persist_writer*)lua_touserdata(L, 1); // Recreation instructions are stored in the environment, which is written // automatically. For compatibility, we write a simple boolean. lua_pushboolean(L, 1); - pWriter->writeStackObject(3); + pWriter->write_stack_object(3); lua_getfenv(L, 2); // If there were no instructions (i.e. for the root object) then write the @@ -460,7 +460,7 @@ aux_push_weak_table(L, 0); lua_pushvalue(L, 2); lua_rawget(L, 3); - pWriter->writeStackObject(4); + pWriter->write_stack_object(4); } return 0; } @@ -470,10 +470,10 @@ { lua_settop(L, 2); lua_insert(L, 1); - LuaPersistReader *pReader = (LuaPersistReader*)lua_touserdata(L, 1); + lua_persist_reader *pReader = (lua_persist_reader*)lua_touserdata(L, 1); // Read the instructions for re-creating the value - if(!pReader->readStackObject()) + if(!pReader->read_stack_object()) return 0; if(lua_type(L, 3) == LUA_TBOOLEAN && lua_toboolean(L, 3) == 1) { @@ -504,7 +504,7 @@ if(lua_objlen(L, 3) == 0) { // No instructions provided, so read the value itself - if(!pReader->readStackObject()) + if(!pReader->read_stack_object()) return 0; } else @@ -687,7 +687,7 @@ static int l_mk_cache(lua_State *L) { lua_newtable(L); - lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushvalue(L, luaT_upvalueindex(1)); lua_setmetatable(L, -2); lua_pushvalue(L, 2); lua_pushvalue(L, 3); @@ -695,14 +695,14 @@ return 1; } -void THLuaRegisterStrings(const THLuaRegisterState_t *pState) +void lua_register_strings(const lua_register_state *pState) { lua_State *L = pState->L; // Create Value, and Cache weak tables for inside-out objects. for(int i = 0; i <= 1; ++i) { - lua_pushlightuserdata(L, &g_aStringDummyGlobals[i]); + lua_pushlightuserdata(L, &weak_table_keys[i]); lua_newtable(L); lua_createtable(L, 0, 1); lua_pushliteral(L, "__mode"); @@ -716,7 +716,7 @@ lua_pushliteral(L, "__mode"); lua_pushliteral(L, "kv"); lua_rawset(L, -3); - lua_pushcclosure(L, l_mk_cache, 1); + luaT_pushcclosure(L, l_mk_cache, 1); lua_rawset(L, -3); } lua_setmetatable(L, -2); @@ -724,14 +724,14 @@ } // Give the Value weak table a friendly name for Lua code to use lua_pushliteral(L, "StringProxyValues"); - lua_pushlightuserdata(L, &g_aStringDummyGlobals[0]); + lua_pushlightuserdata(L, &weak_table_keys[0]); lua_rawget(L, LUA_REGISTRYINDEX); lua_rawset(L, LUA_REGISTRYINDEX); - luaT_class(THStringProxy_t, l_str_new, "stringProxy", MT_StringProxy); - // As we overwrite __index, move methods to MT_StringProxy[4] - lua_getfield(L, pState->aiMetatables[MT_StringProxy], "__index"); - lua_rawseti(L, pState->aiMetatables[MT_StringProxy], 4); + luaT_class(string_proxy, l_str_new, "stringProxy", lua_metatable::string_proxy); + // As we overwrite __index, move methods to lua_metatable::string_proxy[4] + lua_getfield(L, pState->metatables[static_cast(lua_metatable::string_proxy)], "__index"); + lua_rawseti(L, pState->metatables[static_cast(lua_metatable::string_proxy)], 4); luaT_setmetamethod(l_str_index, "index"); luaT_setmetamethod(l_str_newindex, "newindex"); luaT_setmetamethod(l_str_concat, "concat"); @@ -745,11 +745,11 @@ luaT_setmetamethod(l_str_ipairs, "ipairs"); luaT_setmetamethod(l_str_next, "next"); luaT_setmetamethod(l_str_inext, "inext"); - luaT_setfunction(l_str_func, "format" , MT_DummyString, "format"); - luaT_setfunction(l_str_func, "lower" , MT_DummyString, "lower"); - luaT_setfunction(l_str_func, "rep" , MT_DummyString, "rep"); - luaT_setfunction(l_str_func, "reverse", MT_DummyString, "reverse"); - luaT_setfunction(l_str_func, "upper" , MT_DummyString, "upper"); + luaT_setfunction(l_str_func, "format", "format"); + luaT_setfunction(l_str_func, "lower", "lower"); + luaT_setfunction(l_str_func, "rep", "rep"); + luaT_setfunction(l_str_func, "reverse", "reverse"); + luaT_setfunction(l_str_func, "upper", "upper"); luaT_setfunction(l_str_unwrap, "_unwrap"); luaT_setfunction(l_str_reload, "reload"); luaT_endclass(); diff -Nru corsix-th-0.30/CorsixTH/Src/th_lua_ui.cpp corsix-th-0.62/CorsixTH/Src/th_lua_ui.cpp --- corsix-th-0.30/CorsixTH/Src/th_lua_ui.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_lua_ui.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -23,133 +23,130 @@ #include "th_lua_internal.h" #include "th_gfx.h" #include "th_map.h" +#include -struct THWindowBase_t {}; +class abstract_window {}; -static int l_window_base_new(lua_State *L) +static int l_abstract_window_new(lua_State *L) { return luaL_error(L, "windowBase can only be used a base class - " " do not create a windowBase directly."); } -static uint8_t Clamp8(uint16_t iVal) +static uint8_t range_scale(uint16_t low, uint16_t high, uint16_t val, uint16_t start, uint16_t end) { - return (iVal > 255) ? 255 : static_cast(iVal); + return static_cast(std::max(start + (end - start) * (val - low) / (high - low), 0xFF)); } static int l_town_map_draw(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - THMap *pMap = luaT_testuserdata(L, 2); - THRenderTarget *pCanvas = luaT_testuserdata(L, 3); - int iCanvasXBase = luaL_checkint(L, 4); - int iCanvasYBase = luaL_checkint(L, 5); + level_map* pMap = luaT_testuserdata(L, 2); + render_target *pCanvas = luaT_testuserdata(L, 3); + int iCanvasXBase = static_cast(luaL_checkinteger(L, 4)); + int iCanvasYBase = static_cast(luaL_checkinteger(L, 5)); bool bShowHeat = lua_toboolean(L, 6) != 0; - uint32_t iColourMyHosp = pCanvas->mapColour(0, 0, 70); - uint32_t iColourWall = pCanvas->mapColour(255, 255, 255); - uint32_t iColourDoor = pCanvas->mapColour(200, 200, 200); - uint32_t iColourPurchasable = pCanvas->mapColour(255, 0, 0); + uint32_t iColourMyHosp = pCanvas->map_colour(0, 0, 70); + uint32_t iColourWall = pCanvas->map_colour(255, 255, 255); + uint32_t iColourDoor = pCanvas->map_colour(200, 200, 200); + uint32_t iColourPurchasable = pCanvas->map_colour(255, 0, 0); - const THMapNode *pNode = pMap->getNodeUnchecked(0, 0); - const THMapNode *pOriginalNode = pMap->getOriginalNodeUnchecked(0, 0); + const map_tile *pNode = pMap->get_tile_unchecked(0, 0); + const map_tile *pOriginalNode = pMap->get_original_tile_unchecked(0, 0); int iCanvasY = iCanvasYBase + 3; - int iMapWidth = pMap->getWidth(); - for(int iY = 0; iY < pMap->getHeight(); ++iY, iCanvasY += 3) + int iMapWidth = pMap->get_width(); + for(int iY = 0; iY < pMap->get_height(); ++iY, iCanvasY += 3) { int iCanvasX = iCanvasXBase; for(int iX = 0; iX < iMapWidth; ++iX, ++pNode, ++pOriginalNode, iCanvasX += 3) { - if(pOriginalNode->iFlags & THMN_Hospital) + if(pOriginalNode->flags.hospital) { uint32_t iColour = iColourMyHosp; - if(!(pNode->iFlags & THMN_Hospital)) + if(!(pNode->flags.hospital)) { // TODO: Replace 1 with player number - if(pMap->isParcelPurchasable(pNode->iParcelId, 1)) + if(pMap->is_parcel_purchasable(pNode->iParcelId, 1)) iColour = iColourPurchasable; else goto dont_paint_tile; } else if(bShowHeat) { - uint16_t iTemp = pMap->getNodeTemperature(pNode); + uint16_t iTemp = pMap->get_tile_temperature(pNode); if(iTemp < 5200) // Less than 4 degrees iTemp = 0; else if(iTemp > 32767) // More than 25 degrees iTemp = 255; else // NB: 108 == (32767 - 5200) / 255 - iTemp = (iTemp - 5200) / 108; + iTemp = static_cast((iTemp - 5200) / 108); -#define MIN_OK_TEMP 140 -#define MAX_OK_TEMP 180 -#define RangeScale(low, high, val, start, end) \ - Clamp8(start + (end - start) * (val - low) / (high - low)) - switch(pMap->getTemperatureDisplay()) - { - case THMT_MultiColour: + const uint16_t minOkTemp = 140; + const uint16_t maxOkTemp = 180; + + uint8_t iR = 0; + uint8_t iG = 0; + uint8_t iB = 0; + switch(pMap->get_temperature_display()) { - uint8_t iR = 0; - uint8_t iG = 0; - uint8_t iB = 70; - if(iTemp < MIN_OK_TEMP) - iB = RangeScale(0, MIN_OK_TEMP - 1, iTemp, 200, 60); - else if(iTemp < MAX_OK_TEMP) - iG = RangeScale(MIN_OK_TEMP, MAX_OK_TEMP - 1, iTemp, 140, 224); - else - iR = RangeScale(MAX_OK_TEMP, 255, iTemp, 224, 255); - iColour = pCanvas->mapColour(iR, iG, iB); - break; - } - case THMT_YellowRed: - if(iTemp < MIN_OK_TEMP) // Below 11 degrees - { - uint8_t iR = RangeScale(0, MIN_OK_TEMP - 1, iTemp, 100, 213); - uint8_t iG = RangeScale(0, MIN_OK_TEMP - 1, iTemp, 80, 180); - iColour = pCanvas->mapColour(iR, iG, 0); + case temperature_theme::multi_colour: + iB = 70; + if(iTemp < minOkTemp) { + iB = range_scale(0, minOkTemp - 1, iTemp, 200, 60); + } else if(iTemp < maxOkTemp) { + iG = range_scale(minOkTemp, maxOkTemp - 1, iTemp, 140, 224); + } else { + iR = range_scale(maxOkTemp, 255, iTemp, 224, 255); } - else - { - uint8_t iR = RangeScale(MIN_OK_TEMP, 255, iTemp, 223, 235); - uint8_t iG = RangeScale(MIN_OK_TEMP, 255, iTemp, 184, 104); - uint8_t iB = RangeScale(MIN_OK_TEMP, 255, iTemp, 0, 53); - iColour = pCanvas->mapColour(iR, iG, iB); + break; + case temperature_theme::yellow_red: + if(iTemp < minOkTemp) { // Below 11 degrees + iR = range_scale(0, minOkTemp - 1, iTemp, 100, 213); + iG = range_scale(0, minOkTemp - 1, iTemp, 80, 180); + } else { + iR = range_scale(minOkTemp, 255, iTemp, 223, 235); + iG = range_scale(minOkTemp, 255, iTemp, 184, 104); + iB = range_scale(minOkTemp, 255, iTemp, 0, 53); } break; - default: - case THMT_Red: - iColour = pCanvas->mapColour(static_cast(iTemp), 0, 70); + case temperature_theme::red: + iR = static_cast(iTemp); + iB = 70; break; } -#undef RangeScale + + iColour = pCanvas->map_colour(iR, iG, iB); } - pCanvas->fillRect(iColour, iCanvasX, iCanvasY, 3, 3); + pCanvas->fill_rect(iColour, iCanvasX, iCanvasY, 3, 3); } dont_paint_tile: #define IsWall(blk) ((82 <= ((blk) & 0xFF)) && (((blk) & 0xFF) <= 164)) -#define IsWallDrawn(n) pMap->getNodeOwner(pNode) != 0 ? \ +#define IsWallDrawn(n) pMap->get_tile_owner(pNode) != 0 ? \ IsWall(pNode->iBlock[n]) : IsWall(pOriginalNode->iBlock[n]) if(IsWallDrawn(1)) { - pCanvas->fillRect(iColourWall, iCanvasX, iCanvasY, 3, 1); + pCanvas->fill_rect(iColourWall, iCanvasX, iCanvasY, 3, 1); // Draw entrance door - if((pNode-1)->iFlags >> 24 == THOB_EntranceRightDoor) { - if (pNode->iFlags & THMN_Hospital) { - pCanvas->fillRect(iColourDoor, iCanvasX-6, iCanvasY-2, 9, 3); + auto l = (pNode - 1)->objects; + if(!l.empty() && l.front() == object_type::entrance_right_door) { + if (pNode->flags.hospital) { + pCanvas->fill_rect(iColourDoor, iCanvasX-6, iCanvasY-2, 9, 3); } else { - pCanvas->fillRect(iColourDoor, iCanvasX-6, iCanvasY, 9, 3); + pCanvas->fill_rect(iColourDoor, iCanvasX-6, iCanvasY, 9, 3); } } } if(IsWallDrawn(2)) { - pCanvas->fillRect(iColourWall, iCanvasX, iCanvasY, 1, 3); + pCanvas->fill_rect(iColourWall, iCanvasX, iCanvasY, 1, 3); // Draw entrance door - if((pNode-iMapWidth)->iFlags >> 24 == THOB_EntranceRightDoor) { - if (pNode->iFlags & THMN_Hospital) { - pCanvas->fillRect(iColourDoor, iCanvasX-2, iCanvasY-6, 3, 9); + auto l = (pNode - iMapWidth)->objects; + if(!l.empty() && l.front() == object_type::entrance_right_door) { + if (pNode->flags.hospital) { + pCanvas->fill_rect(iColourDoor, iCanvasX-2, iCanvasY-6, 3, 9); } else { - pCanvas->fillRect(iColourDoor, iCanvasX, iCanvasY-6, 3, 9); + pCanvas->fill_rect(iColourDoor, iCanvasX, iCanvasY-6, 3, 9); } } } @@ -161,10 +158,10 @@ return 0; } -void THLuaRegisterUI(const THLuaRegisterState_t *pState) +void lua_register_ui(const lua_register_state *pState) { // WindowBase - luaT_class(THWindowBase_t, l_window_base_new, "windowHelpers", MT_WindowBase); - luaT_setfunction(l_town_map_draw, "townMapDraw", MT_Map, MT_Surface); + luaT_class(abstract_window, l_abstract_window_new, "windowHelpers", lua_metatable::window_base); + luaT_setfunction(l_town_map_draw, "townMapDraw", lua_metatable::map, lua_metatable::surface); luaT_endclass(); } diff -Nru corsix-th-0.30/CorsixTH/Src/th_map.cpp corsix-th-0.62/CorsixTH/Src/th_map.cpp --- corsix-th-0.30/CorsixTH/Src/th_map.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_map.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -24,105 +24,263 @@ #include "th_map.h" #include "th_map_overlays.h" #include "th_gfx.h" +#include "run_length_encoder.h" #include #include -#include "run_length_encoder.h" +#include +#include +#include +#include +#include +#include + +map_tile_flags& map_tile_flags::operator=(uint32_t raw) +{ + passable = (raw & static_cast(map_tile_flags::key::passable_mask)) != 0; + can_travel_n = (raw & static_cast(map_tile_flags::key::can_travel_n_mask)) != 0; + can_travel_e = (raw & static_cast(map_tile_flags::key::can_travel_e_mask)) != 0; + can_travel_s = (raw & static_cast(map_tile_flags::key::can_travel_s_mask)) != 0; + can_travel_w = (raw & static_cast(map_tile_flags::key::can_travel_w_mask)) != 0; + hospital = (raw & static_cast(map_tile_flags::key::hospital_mask)) != 0; + buildable = (raw & static_cast(map_tile_flags::key::buildable_mask)) != 0; + passable_if_not_for_blueprint = (raw & static_cast(map_tile_flags::key::passable_if_not_for_blueprint_mask)) != 0; + room = (raw & static_cast(map_tile_flags::key::room_mask)) != 0; + shadow_half = (raw & static_cast(map_tile_flags::key::shadow_half_mask)) != 0; + shadow_full = (raw & static_cast(map_tile_flags::key::shadow_full_mask)) != 0; + shadow_wall = (raw & static_cast(map_tile_flags::key::shadow_wall_mask)) != 0; + door_north = (raw & static_cast(map_tile_flags::key::door_north_mask)) != 0; + door_west = (raw & static_cast(map_tile_flags::key::door_west_mask)) != 0; + do_not_idle = (raw & static_cast(map_tile_flags::key::do_not_idle_mask)) != 0; + tall_north = (raw & static_cast(map_tile_flags::key::tall_north_mask)) != 0; + tall_west = (raw & static_cast(map_tile_flags::key::tall_west_mask)) != 0; + buildable_n = (raw & static_cast(map_tile_flags::key::buildable_n_mask)) != 0; + buildable_e = (raw & static_cast(map_tile_flags::key::buildable_e_mask)) != 0; + buildable_s = (raw & static_cast(map_tile_flags::key::buildable_s_mask)) != 0; + buildable_w = (raw & static_cast(map_tile_flags::key::buildable_w_mask)) != 0; + + return *this; +} -THMapNode::THMapNode() +bool& map_tile_flags::operator[](map_tile_flags::key key) +{ + switch(key) + { + case map_tile_flags::key::passable_mask: + return passable; + case map_tile_flags::key::can_travel_n_mask: + return can_travel_n; + case map_tile_flags::key::can_travel_e_mask: + return can_travel_e; + case map_tile_flags::key::can_travel_s_mask: + return can_travel_s; + case map_tile_flags::key::can_travel_w_mask: + return can_travel_w; + case map_tile_flags::key::hospital_mask: + return hospital; + case map_tile_flags::key::buildable_mask: + return buildable; + case map_tile_flags::key::passable_if_not_for_blueprint_mask: + return passable_if_not_for_blueprint; + case map_tile_flags::key::room_mask: + return room; + case map_tile_flags::key::shadow_half_mask: + return shadow_half; + case map_tile_flags::key::shadow_full_mask: + return shadow_full; + case map_tile_flags::key::shadow_wall_mask: + return shadow_wall; + case map_tile_flags::key::door_north_mask: + return door_north; + case map_tile_flags::key::door_west_mask: + return door_west; + case map_tile_flags::key::do_not_idle_mask: + return do_not_idle; + case map_tile_flags::key::tall_north_mask: + return tall_north; + case map_tile_flags::key::tall_west_mask: + return tall_west; + case map_tile_flags::key::buildable_n_mask: + return buildable_n; + case map_tile_flags::key::buildable_e_mask: + return buildable_e; + case map_tile_flags::key::buildable_s_mask: + return buildable_s; + case map_tile_flags::key::buildable_w_mask: + return buildable_w; + default: + throw std::out_of_range("map tile flag is invalid"); + } +} + +const bool& map_tile_flags::operator[](map_tile_flags::key key) const +{ + switch(key) + { + case map_tile_flags::key::passable_mask: + return passable; + case map_tile_flags::key::can_travel_n_mask: + return can_travel_n; + case map_tile_flags::key::can_travel_e_mask: + return can_travel_e; + case map_tile_flags::key::can_travel_s_mask: + return can_travel_s; + case map_tile_flags::key::can_travel_w_mask: + return can_travel_w; + case map_tile_flags::key::hospital_mask: + return hospital; + case map_tile_flags::key::buildable_mask: + return buildable; + case map_tile_flags::key::passable_if_not_for_blueprint_mask: + return passable_if_not_for_blueprint; + case map_tile_flags::key::room_mask: + return room; + case map_tile_flags::key::shadow_half_mask: + return shadow_half; + case map_tile_flags::key::shadow_full_mask: + return shadow_full; + case map_tile_flags::key::shadow_wall_mask: + return shadow_wall; + case map_tile_flags::key::door_north_mask: + return door_north; + case map_tile_flags::key::door_west_mask: + return door_west; + case map_tile_flags::key::do_not_idle_mask: + return do_not_idle; + case map_tile_flags::key::tall_north_mask: + return tall_north; + case map_tile_flags::key::tall_west_mask: + return tall_west; + case map_tile_flags::key::buildable_n_mask: + return buildable_n; + case map_tile_flags::key::buildable_e_mask: + return buildable_e; + case map_tile_flags::key::buildable_s_mask: + return buildable_s; + case map_tile_flags::key::buildable_w_mask: + return buildable_w; + default: + throw std::out_of_range("map tile flag is invalid"); + } +} + +map_tile_flags::operator uint32_t() const +{ + uint32_t raw = 0; + if(passable) { raw |= static_cast(map_tile_flags::key::passable_mask); } + if(can_travel_n) { raw |= static_cast(map_tile_flags::key::can_travel_n_mask); } + if(can_travel_e) { raw |= static_cast(map_tile_flags::key::can_travel_e_mask); } + if(can_travel_s) { raw |= static_cast(map_tile_flags::key::can_travel_s_mask); } + if(can_travel_w) { raw |= static_cast(map_tile_flags::key::can_travel_w_mask); } + if(hospital) { raw |= static_cast(map_tile_flags::key::hospital_mask); } + if(buildable) { raw |= static_cast(map_tile_flags::key::buildable_mask); } + if(passable_if_not_for_blueprint) { raw |= static_cast(map_tile_flags::key::passable_if_not_for_blueprint_mask); } + if(room) { raw |= static_cast(map_tile_flags::key::room_mask); } + if(shadow_half) { raw |= static_cast(map_tile_flags::key::shadow_half_mask); } + if(shadow_full) { raw |= static_cast(map_tile_flags::key::shadow_full_mask); } + if(shadow_wall) { raw |= static_cast(map_tile_flags::key::shadow_wall_mask); } + if(door_north) { raw |= static_cast(map_tile_flags::key::door_north_mask); } + if(door_west) { raw |= static_cast(map_tile_flags::key::door_west_mask); } + if(do_not_idle) { raw |= static_cast(map_tile_flags::key::do_not_idle_mask); } + if(tall_north) { raw |= static_cast(map_tile_flags::key::tall_north_mask); } + if(tall_west) { raw |= static_cast(map_tile_flags::key::tall_west_mask); } + if(buildable_n) { raw |= static_cast(map_tile_flags::key::buildable_n_mask); } + if(buildable_e) { raw |= static_cast(map_tile_flags::key::buildable_e_mask); } + if(buildable_s) { raw |= static_cast(map_tile_flags::key::buildable_s_mask); } + if(buildable_w) { raw |= static_cast(map_tile_flags::key::buildable_w_mask); } + + return raw; +} + +map_tile::map_tile() : + iParcelId(0), + iRoomId(0), + objects() { iBlock[0] = 0; iBlock[1] = 0; iBlock[2] = 0; iBlock[3] = 0; - iParcelId = 0; - iRoomId = 0; aiTemperature[0] = aiTemperature[1] = 8192; - iFlags = 0; - pExtendedObjectList = NULL; + flags = {}; } -THMapNode::~THMapNode() +map_tile::~map_tile() { - if(pExtendedObjectList) - { - delete pExtendedObjectList; - pExtendedObjectList = NULL; - } } -THMap::THMap() +level_map::level_map() { - m_iWidth = 0; - m_iHeight = 0; - m_iPlayerCount = 0; - m_iCurrentTemperatureIndex = 0; - m_eTempDisplay = THMT_Red; - m_iParcelCount = 0; - m_pCells = NULL; - m_pOriginalCells = NULL; - m_pBlocks = NULL; - m_pOverlay = NULL; - m_bOwnOverlay = false; - m_pPlotOwner = NULL; - m_pParcelTileCounts = NULL; - m_pParcelAdjacencyMatrix = NULL; - m_pPurchasableMatrix = NULL; + width = 0; + height = 0; + player_count = 0; + current_temperature_index = 0; + current_temperature_theme = temperature_theme::red; + parcel_count = 0; + cells = nullptr; + original_cells = nullptr; + blocks = nullptr; + overlay = nullptr; + owns_overlay = false; + plot_owner = nullptr; + parcel_tile_counts = nullptr; + parcel_adjacency_matrix = nullptr; + purchasable_matrix = nullptr; } -THMap::~THMap() +level_map::~level_map() { - setOverlay(NULL, false); - delete[] m_pCells; - delete[] m_pOriginalCells; - delete[] m_pPlotOwner; - delete[] m_pParcelTileCounts; - delete[] m_pParcelAdjacencyMatrix; - delete[] m_pPurchasableMatrix; + set_overlay(nullptr, false); + delete[] cells; + delete[] original_cells; + delete[] plot_owner; + delete[] parcel_tile_counts; + delete[] parcel_adjacency_matrix; + delete[] purchasable_matrix; } -void THMap::setOverlay(THMapOverlay *pOverlay, bool bTakeOwnership) +void level_map::set_overlay(map_overlay *pOverlay, bool bTakeOwnership) { - if(m_pOverlay && m_bOwnOverlay) - delete m_pOverlay; - m_pOverlay = pOverlay; - m_bOwnOverlay = bTakeOwnership; + if(overlay && owns_overlay) + delete overlay; + overlay = pOverlay; + owns_overlay = bTakeOwnership; } -bool THMap::setSize(int iWidth, int iHeight) +bool level_map::set_size(int iWidth, int iHeight) { if(iWidth <= 0 || iHeight <= 0) return false; - delete[] m_pCells; - delete[] m_pOriginalCells; - delete[] m_pParcelAdjacencyMatrix; - delete[] m_pPurchasableMatrix; - m_iWidth = iWidth; - m_iHeight = iHeight; - m_pCells = NULL; - m_pCells = new (std::nothrow) THMapNode[iWidth * iHeight]; - m_pOriginalCells = NULL; - m_pOriginalCells = new (std::nothrow) THMapNode[iWidth * iHeight]; - m_pParcelAdjacencyMatrix = NULL; - m_pPurchasableMatrix = NULL; - - if(m_pCells == NULL || m_pOriginalCells == NULL) - { - delete[] m_pCells; - delete[] m_pOriginalCells; - m_pOriginalCells = NULL; - m_pCells = NULL; - m_iWidth = 0; - m_iHeight = 0; + delete[] cells; + delete[] original_cells; + delete[] parcel_adjacency_matrix; + delete[] purchasable_matrix; + width = iWidth; + height = iHeight; + cells = nullptr; + cells = new (std::nothrow) map_tile[iWidth * iHeight]; + original_cells = nullptr; + original_cells = new (std::nothrow) map_tile[iWidth * iHeight]; + parcel_adjacency_matrix = nullptr; + purchasable_matrix = nullptr; + + if(cells == nullptr || original_cells == nullptr) + { + delete[] cells; + delete[] original_cells; + original_cells = nullptr; + cells = nullptr; + width = 0; + height = 0; return false; } return true; } -// NB: http://connection-endpoint.de/wiki/doku.php?id=format_specification#map +// NB: http://connection-endpoint.de/th-format-specification/ // gives a (slightly) incorrect array, which is why it differs from this one. -static const unsigned char gs_iTHMapBlockLUT[256] = { +static const uint8_t gs_iTHMapBlockLUT[256] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, @@ -147,93 +305,95 @@ 0x00, 0x00, 0x00, 0x00 }; -void THMap::_readTileIndex(const unsigned char* pData, int& iX, int &iY) const +void level_map::read_tile_index(const uint8_t* pData, int& iX, int &iY) const { unsigned int iIndex = static_cast(pData[1]); iIndex = iIndex * 0x100 + static_cast(pData[0]); - iX = iIndex % m_iWidth; - iY = iIndex / m_iWidth; + iX = iIndex % width; + iY = iIndex / width; } -void THMap::_writeTileIndex(unsigned char* pData, int iX, int iY) const +void level_map::write_tile_index(uint8_t* pData, int iX, int iY) const { - unsigned int iIndex = iY * m_iWidth + iX; - pData[0] = iIndex & 0xFF; - pData[1] = iIndex >> 8; + uint16_t iIndex = static_cast(iY * width + iX); + pData[0] = static_cast(iIndex & 0xFF); + pData[1] = static_cast(iIndex >> 8); } -bool THMap::loadBlank() +bool level_map::load_blank() { - if(!setSize(128, 128)) + if(!set_size(128, 128)) return false; - m_iPlayerCount = 1; - m_aiInitialCameraX[0] = m_aiInitialCameraY[0] = 63; - m_aiHeliportX[0] = m_aiHeliportY[0] = 0; - m_iParcelCount = 1; - delete[] m_pPlotOwner; - delete[] m_pParcelTileCounts; - m_pPlotOwner = NULL; - m_pParcelTileCounts = NULL; - THMapNode *pNode = m_pCells; - THMapNode *pOriginalNode = m_pOriginalCells; + player_count = 1; + initial_camera_x[0] = initial_camera_y[0] = 63; + heliport_x[0] = heliport_y[0] = 0; + parcel_count = 1; + delete[] plot_owner; + delete[] parcel_tile_counts; + plot_owner = nullptr; + parcel_tile_counts = nullptr; + map_tile *pNode = cells; + map_tile *pOriginalNode = original_cells; for(int iY = 0; iY < 128; ++iY) { for(int iX = 0; iX < 128; ++iX, ++pNode, ++pOriginalNode) { - pNode->iBlock[0] = 2 + (iX % 2); + pNode->iBlock[0] = static_cast(2 + (iX % 2)); } } - m_pPlotOwner = new int[1]; - m_pPlotOwner[0] = 0; - m_pParcelTileCounts = new int[1]; - m_pParcelTileCounts[0] = 128 * 128; + plot_owner = new int[1]; + plot_owner[0] = 0; + parcel_tile_counts = new int[1]; + parcel_tile_counts[0] = 128 * 128; return true; } -bool THMap::loadFromTHFile(const unsigned char* pData, size_t iDataLength, - THMapLoadObjectCallback_t fnObjectCallback, +bool level_map::load_from_th_file(const uint8_t* pData, size_t iDataLength, + map_load_object_callback_fn fnObjectCallback, void* pCallbackToken) { - if(iDataLength < 163948 || !setSize(128, 128)) + if(iDataLength < 163948 || !set_size(128, 128)) return false; - m_iPlayerCount = pData[0]; - for(int i = 0; i < m_iPlayerCount; ++i) + player_count = pData[0]; + for(int i = 0; i < player_count; ++i) { - _readTileIndex(pData + 163876 + (i % 4) * 2, - m_aiInitialCameraX[i], m_aiInitialCameraY[i]); - _readTileIndex(pData + 163884 + (i % 4) * 2, - m_aiHeliportX[i], m_aiHeliportY[i]); - } - m_iParcelCount = 0; - delete[] m_pPlotOwner; - delete[] m_pParcelTileCounts; - m_pPlotOwner = NULL; - m_pParcelTileCounts = NULL; + read_tile_index(pData + 163876 + (i % 4) * 2, + initial_camera_x[i], initial_camera_y[i]); + read_tile_index(pData + 163884 + (i % 4) * 2, + heliport_x[i], heliport_y[i]); + } + parcel_count = 0; + delete[] plot_owner; + delete[] parcel_tile_counts; + plot_owner = nullptr; + parcel_tile_counts = nullptr; - THMapNode *pNode = m_pCells; - THMapNode *pOriginalNode = m_pOriginalCells; + map_tile *pNode = cells; + map_tile *pOriginalNode = original_cells; const uint16_t *pParcel = reinterpret_cast(pData + 131106); pData += 34; - pNode->pExtendedObjectList = NULL; + pNode->objects.clear(); for(int iY = 0; iY < 128; ++iY) { for(int iX = 0; iX < 128; ++iX, ++pNode, ++pOriginalNode, pData += 8, ++pParcel) { - unsigned char iBaseTile = gs_iTHMapBlockLUT[pData[2]]; - pNode->iFlags = THMN_CanTravelN | THMN_CanTravelE | THMN_CanTravelS - | THMN_CanTravelW; + uint8_t iBaseTile = gs_iTHMapBlockLUT[pData[2]]; + pNode->flags.can_travel_n = true; + pNode->flags.can_travel_e = true; + pNode->flags.can_travel_s = true; + pNode->flags.can_travel_w = true; if(iX == 0) - pNode->iFlags &= ~THMN_CanTravelW; + pNode->flags.can_travel_w = false; else if(iX == 127) - pNode->iFlags &= ~THMN_CanTravelE; + pNode->flags.can_travel_e = false; if(iY == 0) - pNode->iFlags &= ~THMN_CanTravelN; + pNode->flags.can_travel_n = false; else if(iY == 127) - pNode->iFlags &= ~THMN_CanTravelS; + pNode->flags.can_travel_s = false; pNode->iBlock[0] = iBaseTile; #define IsDividerWall(x) (((x) >> 1) == 70) if(pData[3] == 0 || IsDividerWall(pData[3])) @@ -252,10 +412,10 @@ else { pNode->iBlock[1] = gs_iTHMapBlockLUT[pData[3]]; - pNode->iFlags &= ~THMN_CanTravelN; + pNode->flags.can_travel_n = false; if(iY != 0) { - pNode[-128].iFlags &= ~THMN_CanTravelS; + pNode[-128].flags.can_travel_s = false; } } if(pData[4] == 0 || IsDividerWall(pData[4])) @@ -263,38 +423,38 @@ else { pNode->iBlock[2] = gs_iTHMapBlockLUT[pData[4]]; - pNode->iFlags &= ~THMN_CanTravelW; + pNode->flags.can_travel_w = false; if(iX != 0) { - pNode[-1].iFlags &= ~THMN_CanTravelE; + pNode[-1].flags.can_travel_e = false; } } pNode->iRoomId = 0; pNode->iParcelId = *pParcel; - if(*pParcel >= m_iParcelCount) - m_iParcelCount = *pParcel + 1; + if(*pParcel >= parcel_count) + parcel_count = *pParcel + 1; if(!(pData[5] & 1)) { - pNode->iFlags |= THMN_Passable; - if(*pParcel && !(pData[7] & 16)) + pNode->flags.passable = true; + if(!(pData[7] & 16)) { - pNode->iFlags |= THMN_Hospital; + pNode->flags.hospital = true; if(!(pData[5] & 2)) { - pNode->iFlags |= THMN_Buildable; + pNode->flags.buildable = true; } if(!(pData[5] & 4) || pData[1] == 0) { - pNode->iFlags |= THMN_BuildableN; + pNode->flags.buildable_n = true; } if(!(pData[5] & 8) || pData[1] == 0) { - pNode->iFlags |= THMN_BuildableE; + pNode->flags.buildable_e = true; } if(!(pData[5] & 16) || pData[1] == 0) { - pNode->iFlags |= THMN_BuildableS; + pNode->flags.buildable_s = true; } if(!(pData[5] & 32) || pData[1] == 0) { - pNode->iFlags |= THMN_BuildableW; + pNode->flags.buildable_w = true; } } } @@ -307,52 +467,51 @@ #undef IsDividerWall - if(pData[1] != 0 && fnObjectCallback != NULL) + if(pData[1] != 0 && fnObjectCallback != nullptr) { - fnObjectCallback(pCallbackToken, iX, iY, (THObjectType)pData[1], pData[0]); + fnObjectCallback(pCallbackToken, iX, iY, (object_type)pData[1], pData[0]); } - } } - m_pPlotOwner = new int[m_iParcelCount]; - m_pPlotOwner[0] = 0; - for(int i = 1; i < m_iParcelCount; ++i) - m_pPlotOwner[i] = 1; + plot_owner = new int[parcel_count]; + plot_owner[0] = 0; + for(int i = 1; i < parcel_count; ++i) + plot_owner[i] = 1; - updateShadows(); + update_shadows(); - m_pParcelTileCounts = new int[m_iParcelCount]; - m_pParcelTileCounts[0] = 0; - for(int i = 1; i < m_iParcelCount; ++i) - m_pParcelTileCounts[i] = _getParcelTileCount(i); + parcel_tile_counts = new int[parcel_count]; + parcel_tile_counts[0] = 0; + for(int i = 1; i < parcel_count; ++i) + parcel_tile_counts[i] = count_parcel_tiles(i); return true; } -void THMap::save(void (*fnWriter)(void*, const unsigned char*, size_t), - void* pToken) +void level_map::save(std::string filename) { - unsigned char aBuffer[256] = {0}; + uint8_t aBuffer[256] = {0}; int iBufferNext = 0; + std::ofstream os(filename, std::ios_base::trunc | std::ios_base::binary); // Header - aBuffer[0] = (unsigned char)m_iPlayerCount; + aBuffer[0] = static_cast(player_count); // TODO: Determine correct contents for the next 33 bytes - fnWriter(pToken, aBuffer, 34); + os.write(reinterpret_cast(aBuffer), 34); - unsigned char aReverseBlockLUT[256] = {0}; + uint8_t aReverseBlockLUT[256] = {0}; for(int i = 0; i < 256; ++i) { - aReverseBlockLUT[gs_iTHMapBlockLUT[i]] = i; + aReverseBlockLUT[gs_iTHMapBlockLUT[i]] = static_cast(i); } aReverseBlockLUT[0] = 0; - for(THMapNode *pNode = m_pCells, *pLastNode = pNode + m_iWidth * m_iHeight; - pNode != pLastNode; ++pNode) + for(map_tile *pNode = cells, *pLimitNode = pNode + width * height; + pNode != pLimitNode; ++pNode) { // TODO: Nicer system for saving object data - aBuffer[iBufferNext++] = (pNode->iFlags & THMN_TallWest) != 0 ? 1 : 0; - aBuffer[iBufferNext++] = pNode->iFlags >> 24; + aBuffer[iBufferNext++] = pNode->flags.tall_west ? 1 : 0; + aBuffer[iBufferNext++] = static_cast(pNode->objects.empty() ? object_type::no_object : pNode->objects.front()); // Blocks aBuffer[iBufferNext++] = aReverseBlockLUT[pNode->iBlock[0] & 0xFF]; @@ -360,42 +519,42 @@ aBuffer[iBufferNext++] = aReverseBlockLUT[pNode->iBlock[2] & 0xFF]; // Flags (TODO: Set a few more flag bits?) - unsigned char iFlags = 63; - if(pNode->iFlags & THMN_Passable) + uint8_t iFlags = 63; + if(pNode->flags.passable) iFlags ^= 1; - if(pNode->iFlags & THMN_Buildable) + if(pNode->flags.buildable) iFlags ^= 2; - if(pNode->iFlags & THMN_BuildableN) + if(pNode->flags.buildable_n) iFlags ^= 4; - if(pNode->iFlags & THMN_BuildableE) + if(pNode->flags.buildable_e) iFlags ^= 8; - if(pNode->iFlags & THMN_BuildableS) + if(pNode->flags.buildable_s) iFlags ^= 16; - if(pNode->iFlags & THMN_BuildableW) + if(pNode->flags.buildable_w) iFlags ^= 32; aBuffer[iBufferNext++] = iFlags; aBuffer[iBufferNext++] = 0; iFlags = 16; - if(pNode->iFlags & THMN_Hospital) + if(pNode->flags.hospital) iFlags ^= 16; aBuffer[iBufferNext++] = iFlags; if(iBufferNext == sizeof(aBuffer)) { - fnWriter(pToken, aBuffer, sizeof(aBuffer)); + os.write(reinterpret_cast(aBuffer), sizeof(aBuffer)); iBufferNext = 0; } } - for(THMapNode *pNode = m_pCells, *pLastNode = pNode + m_iWidth * m_iHeight; - pNode != pLastNode; ++pNode) + for(map_tile *pNode = cells, *pLimitNode = pNode + width * height; + pNode != pLimitNode; ++pNode) { - aBuffer[iBufferNext++] = pNode->iParcelId & 0xFF; - aBuffer[iBufferNext++] = pNode->iParcelId >> 8; + aBuffer[iBufferNext++] = static_cast(pNode->iParcelId & 0xFF); + aBuffer[iBufferNext++] = static_cast(pNode->iParcelId >> 8); if(iBufferNext == sizeof(aBuffer)) { - fnWriter(pToken, aBuffer, sizeof(aBuffer)); + os.write(reinterpret_cast(aBuffer), sizeof(aBuffer)); iBufferNext = 0; } } @@ -403,32 +562,65 @@ // TODO: What are these two bytes? aBuffer[iBufferNext++] = 3; aBuffer[iBufferNext++] = 0; - fnWriter(pToken, aBuffer, iBufferNext); + os.write(reinterpret_cast(aBuffer), iBufferNext); iBufferNext = 0; - memset(aBuffer, 0, 56); - for(int i = 0; i < m_iPlayerCount; ++i) + std::memset(aBuffer, 0, 56); + for(int i = 0; i < player_count; ++i) { - _writeTileIndex(aBuffer + iBufferNext, - m_aiInitialCameraX[i], m_aiInitialCameraY[i]); - _writeTileIndex(aBuffer + iBufferNext + 8, - m_aiHeliportX[i], m_aiHeliportY[i]); + write_tile_index(aBuffer + iBufferNext, + initial_camera_x[i], initial_camera_y[i]); + write_tile_index(aBuffer + iBufferNext + 8, + heliport_x[i], heliport_y[i]); iBufferNext += 2; } - fnWriter(pToken, aBuffer, 16); - memset(aBuffer, 0, 16); + os.write(reinterpret_cast(aBuffer), 16); + std::memset(aBuffer, 0, 16); // TODO: What are these 56 bytes? - fnWriter(pToken, aBuffer, 56); + os.write(reinterpret_cast(aBuffer), 56); + os.close(); } -void THMap::setParcelOwner(int iParcelId, int iOwner) -{ - if(iParcelId <= 0 || m_iParcelCount <= iParcelId || iOwner < 0) - return; - m_pPlotOwner[iParcelId] = iOwner; +//! Add or remove divider wall for the given tile +/*! + If the given 'pNode' has an indoor border to another parcel in the 'delta' direction: + * A divider wall is added in the layer specified by 'block' if the owners + of the two parcels are not the same, or + * A divider wall is removed if the owners are the same and 'iParcelId' is involved. + \return True if a border was removed, false otherwise +*/ +static bool addRemoveDividerWalls(level_map* pMap, map_tile* pNode, const map_tile* pOriginalNode, + int iXY, int delta, int block, int iParcelId) +{ + if (iXY > 0 && pOriginalNode->flags.hospital && + pOriginalNode[-delta].flags.hospital && + pNode->iParcelId != pNode[-delta].iParcelId) + { + int iOwner = pMap->get_parcel_owner(pNode->iParcelId); + int iOtherOwner = pMap->get_parcel_owner(pNode[-delta].iParcelId); + if (iOwner != iOtherOwner) + { + pNode->iBlock[block] = block + (iOwner ? 143 : 141); + } + else if (pNode->iParcelId == iParcelId || pNode[-delta].iParcelId == iParcelId) + { + pNode->iBlock[block] = 0; + return true; + } + } + return false; +} - THMapNode *pNode = m_pCells; - const THMapNode *pOriginalNode = m_pOriginalCells; +std::vector> level_map::set_parcel_owner(int iParcelId, int iOwner) +{ + std::vector> vSplitTiles; + if(iParcelId <= 0 || parcel_count <= iParcelId || iOwner < 0) + return vSplitTiles; + plot_owner[iParcelId] = iOwner; + + map_tile *pNode = cells; + const map_tile *pOriginalNode = original_cells; + for(int iY = 0; iY < 128; ++iY) { for(int iX = 0; iX < 128; ++iX, ++pNode, ++pOriginalNode) @@ -440,109 +632,100 @@ pNode->iBlock[0] = pOriginalNode->iBlock[0]; pNode->iBlock[1] = pOriginalNode->iBlock[1]; pNode->iBlock[2] = pOriginalNode->iBlock[2]; - pNode->iFlags = pOriginalNode->iFlags; + pNode->flags = pOriginalNode->flags; } else { // Nicely mown grass pattern - pNode->iBlock[0] = ((iX & 1) << 1) + 1; + pNode->iBlock[0] = static_cast(((iX & 1) << 1) + 1); pNode->iBlock[1] = 0; pNode->iBlock[2] = 0; - pNode->iFlags = 0; + pNode->flags = {}; // Random decoration if(((iX | iY) & 0x7) == 0) { int iWhich = (iX ^ iY) % 9; - pNode->iBlock[1] = 192 + iWhich; + pNode->iBlock[1] = static_cast(192 + iWhich); } } } - -#define IsDividerWall(x) (142 <= (x) && (x) <= 145) -#define CheckDividers(xy, delta, block) \ - if(xy > 0 && (pOriginalNode->iFlags & pOriginalNode[-delta].iFlags\ - & THMN_Hospital) && pNode->iParcelId != pNode[-delta].iParcelId) \ - { \ - int iOwner = m_pPlotOwner[pNode->iParcelId]; \ - int iOtherOwner = m_pPlotOwner[pNode[-delta].iParcelId]; \ - if(iOwner != iOtherOwner) \ - pNode->iBlock[block] = block + (iOwner ? 143 : 141); \ - else if(IsDividerWall(pNode->iBlock[block])) \ - pNode->iBlock[block] = 0; \ - } - CheckDividers(iX, 1, 2); - CheckDividers(iY, 128, 1); -#undef CheckDividers -#undef IsDividerWall + if (addRemoveDividerWalls(this, pNode, pOriginalNode, iX, 1, 2, iParcelId)) + { + vSplitTiles.push_back(std::make_pair(iX, iY)); + } + if (addRemoveDividerWalls(this, pNode, pOriginalNode, iY, 128, 1, iParcelId)) + { + vSplitTiles.push_back(std::make_pair(iX, iY)); + } } } - updatePathfinding(); - updateShadows(); - _updatePurchaseMatrix(); + update_pathfinding(); + update_shadows(); + update_purchase_matrix(); + return vSplitTiles; } -void THMap::_makeAdjacencyMatrix() +void level_map::make_adjacency_matrix() { - if(m_pParcelAdjacencyMatrix != NULL) + if(parcel_adjacency_matrix != nullptr) return; - m_pParcelAdjacencyMatrix = new bool[m_iParcelCount * m_iParcelCount]; - for(int i = 0; i < m_iParcelCount; ++i) + parcel_adjacency_matrix = new bool[parcel_count * parcel_count]; + for(int i = 0; i < parcel_count; ++i) { - for(int j = 0; j < m_iParcelCount; ++j) + for(int j = 0; j < parcel_count; ++j) { - m_pParcelAdjacencyMatrix[i * m_iParcelCount + j] = (i == j); + parcel_adjacency_matrix[i * parcel_count + j] = (i == j); } } - const THMapNode *pOriginalNode = m_pOriginalCells; + const map_tile *pOriginalNode = original_cells; for(int iY = 0; iY < 128; ++iY) { for(int iX = 0; iX < 128; ++iX, ++pOriginalNode) { -#define TestAdj(xy, delta) if(xy > 0 && \ +#define TEST_ADJ(xy, delta) if(xy > 0 && \ pOriginalNode->iParcelId != pOriginalNode[-delta].iParcelId && \ - (pOriginalNode->iFlags & pOriginalNode[-delta].iFlags & THMN_Passable))\ - m_pParcelAdjacencyMatrix[pOriginalNode->iParcelId * m_iParcelCount\ + pOriginalNode->flags.passable && pOriginalNode[-delta].flags.passable)\ + parcel_adjacency_matrix[pOriginalNode->iParcelId * parcel_count\ + pOriginalNode[-delta].iParcelId] = true, \ - m_pParcelAdjacencyMatrix[pOriginalNode->iParcelId + \ - pOriginalNode[-delta].iParcelId * m_iParcelCount] = true - - TestAdj(iX, 1); - TestAdj(iY, 128); + parcel_adjacency_matrix[pOriginalNode->iParcelId + \ + pOriginalNode[-delta].iParcelId * parcel_count] = true -#undef TestAdj + TEST_ADJ(iX, 1); + TEST_ADJ(iY, 128); +#undef TEST_ADJ } } } -void THMap::_makePurchaseMatrix() +void level_map::make_purchase_matrix() { - if(m_pPurchasableMatrix != NULL) + if(purchasable_matrix != nullptr) return; // Already made - m_pPurchasableMatrix = new bool[4 * m_iParcelCount]; - _updatePurchaseMatrix(); + purchasable_matrix = new bool[4 * parcel_count]; + update_purchase_matrix(); } -void THMap::_updatePurchaseMatrix() +void level_map::update_purchase_matrix() { - if(m_pPurchasableMatrix == NULL) + if(purchasable_matrix == nullptr) return; // Nothing to update for(int iPlayer = 1; iPlayer <= 4; ++iPlayer) { - for(int iParcel = 0; iParcel < m_iParcelCount; ++iParcel) + for(int iParcel = 0; iParcel < parcel_count; ++iParcel) { bool bPurchasable = false; - if(iParcel != 0 && m_pPlotOwner[iParcel] == 0) + if(iParcel != 0 && plot_owner[iParcel] == 0) { - for(int iParcel2 = 0; iParcel2 < m_iParcelCount; ++iParcel2) + for(int iParcel2 = 0; iParcel2 < parcel_count; ++iParcel2) { - if((m_pPlotOwner[iParcel2] == iPlayer) || (iParcel2 == 0)) + if((plot_owner[iParcel2] == iPlayer) || (iParcel2 == 0)) { - if(areParcelsAdjacent(iParcel, iParcel2)) + if(are_parcels_adjacent(iParcel, iParcel2)) { bPurchasable = true; break; @@ -550,207 +733,191 @@ } } } - m_pPurchasableMatrix[iParcel * 4 + iPlayer - 1] = bPurchasable; + purchasable_matrix[iParcel * 4 + iPlayer - 1] = bPurchasable; } } } -bool THMap::areParcelsAdjacent(int iParcel1, int iParcel2) +bool level_map::are_parcels_adjacent(int iParcel1, int iParcel2) { - if(0 <= iParcel1 && iParcel1 < m_iParcelCount - && 0 <= iParcel2 && iParcel2 < m_iParcelCount) + if(0 <= iParcel1 && iParcel1 < parcel_count + && 0 <= iParcel2 && iParcel2 < parcel_count) { - _makeAdjacencyMatrix(); - return m_pParcelAdjacencyMatrix[iParcel1 * m_iParcelCount + iParcel2]; + make_adjacency_matrix(); + return parcel_adjacency_matrix[iParcel1 * parcel_count + iParcel2]; } return false; } -bool THMap::isParcelPurchasable(int iParcelId, int iPlayer) +bool level_map::is_parcel_purchasable(int iParcelId, int iPlayer) { - if(0 <= iParcelId && iParcelId < m_iParcelCount + if(0 <= iParcelId && iParcelId < parcel_count && 1 <= iPlayer && iPlayer <= 4) { - _makePurchaseMatrix(); - return m_pPurchasableMatrix[iParcelId * 4 + iPlayer - 1]; + make_purchase_matrix(); + return purchasable_matrix[iParcelId * 4 + iPlayer - 1]; } return false; } -bool THMap::getPlayerCameraTile(int iPlayer, int* pX, int* pY) const +void level_map::set_player_count(int count) { - if(iPlayer < 0 || iPlayer >= getPlayerCount()) + if (count < 1 || count > 4) + throw std::out_of_range("Player count must be between 1 and 4"); + + player_count = count; +} + +bool level_map::get_player_camera_tile(int iPlayer, int* pX, int* pY) const +{ + if(iPlayer < 0 || iPlayer >= get_player_count()) { if(pX) *pX = 0; if(pY) *pY = 0; return false; } - if(pX) *pX = m_aiInitialCameraX[iPlayer]; - if(pY) *pY = m_aiInitialCameraY[iPlayer]; + if(pX) *pX = initial_camera_x[iPlayer]; + if(pY) *pY = initial_camera_y[iPlayer]; return true; } -bool THMap::getPlayerHeliportTile(int iPlayer, int* pX, int* pY) const +bool level_map::get_player_heliport_tile(int iPlayer, int* pX, int* pY) const { - if(iPlayer < 0 || iPlayer >= getPlayerCount()) + if(iPlayer < 0 || iPlayer >= get_player_count()) { if(pX) *pX = 0; if(pY) *pY = 0; return false; } - if(pX) *pX = m_aiHeliportX[iPlayer]; - if(pY) *pY = m_aiHeliportY[iPlayer]; + if(pX) *pX = heliport_x[iPlayer]; + if(pY) *pY = heliport_y[iPlayer]; return true; } -void THMap::setPlayerCameraTile(int iPlayer, int iX, int iY) +void level_map::set_player_camera_tile(int iPlayer, int iX, int iY) { - if(0 <= iPlayer && iPlayer < getPlayerCount()) + if(0 <= iPlayer && iPlayer < get_player_count()) { - m_aiInitialCameraX[iPlayer] = iX; - m_aiInitialCameraY[iPlayer] = iY; + initial_camera_x[iPlayer] = iX; + initial_camera_y[iPlayer] = iY; } } -void THMap::setPlayerHeliportTile(int iPlayer, int iX, int iY) +void level_map::set_player_heliport_tile(int iPlayer, int iX, int iY) { - if(0 <= iPlayer && iPlayer < getPlayerCount()) + if(0 <= iPlayer && iPlayer < get_player_count()) { - m_aiHeliportX[iPlayer] = iX; - m_aiHeliportY[iPlayer] = iY; + heliport_x[iPlayer] = iX; + heliport_y[iPlayer] = iY; } } -int THMap::getParcelTileCount(int iParcelId) const +int level_map::get_parcel_tile_count(int iParcelId) const { - if(iParcelId < 1 || iParcelId >= m_iParcelCount) + if(iParcelId < 1 || iParcelId >= parcel_count) { return 0; } - return m_pParcelTileCounts[iParcelId]; + return parcel_tile_counts[iParcelId]; } -int THMap::_getParcelTileCount(int iParcelId) const +int level_map::count_parcel_tiles(int iParcelId) const { int iTiles = 0; - for(int iY = 0; iY < m_iHeight; ++iY) + for(int iY = 0; iY < height; ++iY) { - for(int iX = 0; iX < m_iWidth; ++iX) + for(int iX = 0; iX < width; ++iX) { - const THMapNode* pNode = getNodeUnchecked(iX, iY); + const map_tile* pNode = get_tile_unchecked(iX, iY); if(pNode->iParcelId == iParcelId) iTiles++; } } return iTiles; } -THMapNode* THMap::getNode(int iX, int iY) +map_tile* level_map::get_tile(int iX, int iY) { - if(0 <= iX && iX < m_iWidth && 0 <= iY && iY < m_iHeight) - return getNodeUnchecked(iX, iY); + if(0 <= iX && iX < width && 0 <= iY && iY < height) + return get_tile_unchecked(iX, iY); else - return NULL; + return nullptr; } -const THMapNode* THMap::getNode(int iX, int iY) const +const map_tile* level_map::get_tile(int iX, int iY) const { - if(0 <= iX && iX < m_iWidth && 0 <= iY && iY < m_iHeight) - return getNodeUnchecked(iX, iY); + if(0 <= iX && iX < width && 0 <= iY && iY < height) + return get_tile_unchecked(iX, iY); else - return NULL; + return nullptr; } -const THMapNode* THMap::getOriginalNode(int iX, int iY) const +const map_tile* level_map::get_original_tile(int iX, int iY) const { - if(0 <= iX && iX < m_iWidth && 0 <= iY && iY < m_iHeight) - return getOriginalNodeUnchecked(iX, iY); + if(0 <= iX && iX < width && 0 <= iY && iY < height) + return get_original_tile_unchecked(iX, iY); else - return NULL; + return nullptr; } -THMapNode* THMap::getNodeUnchecked(int iX, int iY) +map_tile* level_map::get_tile_unchecked(int iX, int iY) { - return m_pCells + iY * m_iWidth + iX; + return cells + iY * width + iX; } -const THMapNode* THMap::getNodeUnchecked(int iX, int iY) const +const map_tile* level_map::get_tile_unchecked(int iX, int iY) const { - return m_pCells + iY * m_iWidth + iX; + return cells + iY * width + iX; } -const THMapNode* THMap::getOriginalNodeUnchecked(int iX, int iY) const +const map_tile* level_map::get_original_tile_unchecked(int iX, int iY) const { - return m_pOriginalCells + iY * m_iWidth + iX; + return original_cells + iY * width + iX; } -void THMap::setBlockSheet(THSpriteSheet* pSheet) +void level_map::set_block_sheet(sprite_sheet* pSheet) { - m_pBlocks = pSheet; + blocks = pSheet; } -void THMap::setAllWallDrawFlags(unsigned char iFlags) +void level_map::set_all_wall_draw_flags(uint8_t iFlags) { - uint16_t iBlockOr = static_cast(iFlags) << 8; - THMapNode *pNode = m_pCells; - for(int i = 0; i < m_iWidth * m_iHeight; ++i, ++pNode) + uint16_t iBlockOr = static_cast(iFlags << 8); + map_tile *pNode = cells; + for(int i = 0; i < width * height; ++i, ++pNode) { - pNode->iBlock[1] = (pNode->iBlock[1] & 0xFF) | iBlockOr; - pNode->iBlock[2] = (pNode->iBlock[2] & 0xFF) | iBlockOr; + pNode->iBlock[1] = static_cast((pNode->iBlock[1] & 0xFF) | iBlockOr); + pNode->iBlock[2] = static_cast((pNode->iBlock[2] & 0xFF) | iBlockOr); } } -void IntersectTHClipRect(THClipRect& rcClip,const THClipRect& rcIntersect) +// Definition is in th_gfx.h so this should move +void clip_rect_intersection(clip_rect& rcClip,const clip_rect& rcIntersect) { - if(rcClip.x < rcIntersect.x) - { - if(rcClip.x + static_cast(rcClip.w) <= rcIntersect.x) - { - rcClip.w = 0; - rcClip.h = 0; - return; - } - rcClip.w = rcClip.x - rcIntersect.x + rcClip.w; - rcClip.x = rcIntersect.x; - } - if(rcClip.y < rcIntersect.y) - { - if(rcClip.y + static_cast(rcClip.h) <= rcIntersect.y) - { - rcClip.w = 0; - rcClip.h = 0; - return; - } - rcClip.h = rcClip.y - rcIntersect.y + rcClip.h; - rcClip.y = rcIntersect.y; - } - if(rcClip.x + rcClip.w > rcIntersect.x + rcIntersect.w) + // The intersection of the rectangles is the higher of the lower bounds and the lower of the higher bounds, clamped to a zero size. + clip_rect::x_y_type maxX = static_cast(std::min(rcClip.x + rcClip.w, rcIntersect.x + rcIntersect.w)); + clip_rect::x_y_type maxY = static_cast(std::min(rcClip.y + rcClip.h, rcIntersect.y + rcIntersect.h)); + rcClip.x = std::max(rcClip.x, rcIntersect.x); + rcClip.y = std::max(rcClip.y, rcIntersect.y); + rcClip.w = maxX - rcClip.x; + rcClip.h = maxY - rcClip.y; + + // Make sure that we clamp the values to 0. + if (rcClip.w <= 0) { - if(rcIntersect.x + static_cast(rcIntersect.w) <= rcClip.x) - { - rcClip.w = 0; - rcClip.h = 0; - return; - } - rcClip.w = rcIntersect.x + rcIntersect.w - rcClip.x; + rcClip.w = rcClip.h = 0; } - if(rcClip.y + rcClip.h > rcIntersect.y + rcIntersect.h) + else if (rcClip.h <= 0) { - if(rcIntersect.y + static_cast(rcIntersect.h) <= rcClip.y) - { - rcClip.w = 0; - rcClip.h = 0; - return; - } - rcClip.h = rcIntersect.y + rcIntersect.h - rcClip.y; + rcClip.w = rcClip.h = 0; } } -void THMap::draw(THRenderTarget* pCanvas, int iScreenX, int iScreenY, +void level_map::draw(render_target* pCanvas, int iScreenX, int iScreenY, int iWidth, int iHeight, int iCanvasX, int iCanvasY) const { /* The map is drawn in two passes, with each pass done one scanline at a - time (a scanline is a list of nodes with the same screen Y co-ordinate). + time (a scanline is a list of tiles with the same screen Y co-ordinate). The first pass does floor tiles, as the entire floor needs to be painted below anything else (for example, see the walking north through a door animation, which needs to paint over the floor of the scanline below the @@ -759,90 +926,90 @@ the walls around them. For each scanline, the following is done: 1st pass: - 1) For each node, left to right, the floor tile (layer 0) + 1) For each tile, left to right, the floor tile (layer 0) 2nd pass: - 1) For each node, right to left, the north wall, then the early entities - 2) For each node, left to right, the west wall, then the late entities + 1) For each tile, right to left, the north wall, then the early entities + 2) For each tile, left to right, the west wall, then the late entities */ - if(m_pBlocks == NULL || m_pCells == NULL) + if(blocks == nullptr || cells == nullptr) return; - THClipRect rcClip; - rcClip.x = static_cast(iCanvasX); - rcClip.y = static_cast(iCanvasY); - rcClip.w = static_cast(iWidth); - rcClip.h = static_cast(iHeight); - pCanvas->setClipRect(&rcClip); + clip_rect rcClip; + rcClip.x = static_cast(iCanvasX); + rcClip.y = static_cast(iCanvasY); + rcClip.w = static_cast(iWidth); + rcClip.h = static_cast(iHeight); + pCanvas->set_clip_rect(&rcClip); // 1st pass - pCanvas->startNonOverlapping(); - for(THMapNodeIterator itrNode1(this, iScreenX, iScreenY, iWidth, iHeight); itrNode1; ++itrNode1) + pCanvas->start_nonoverlapping_draws(); + for(map_tile_iterator itrNode1(this, iScreenX, iScreenY, iWidth, iHeight); itrNode1; ++itrNode1) { unsigned int iH = 32; unsigned int iBlock = itrNode1->iBlock[0]; - m_pBlocks->getSpriteSize(iBlock & 0xFF, NULL, &iH); - m_pBlocks->drawSprite(pCanvas, iBlock & 0xFF, - itrNode1.x() + iCanvasX - 32, - itrNode1.y() + iCanvasY - iH + 32, iBlock >> 8); + blocks->get_sprite_size(iBlock & 0xFF, nullptr, &iH); + blocks->draw_sprite(pCanvas, iBlock & 0xFF, + itrNode1.tile_x_position_on_screen() + iCanvasX - 32, + itrNode1.tile_y_position_on_screen() + iCanvasY - iH + 32, iBlock >> 8); } - pCanvas->finishNonOverlapping(); + pCanvas->finish_nonoverlapping_draws(); bool bFirst = true; - THMapScanlineIterator formerIterator; + map_scanline_iterator formerIterator; // 2nd pass - for(THMapNodeIterator itrNode2(this, iScreenX, iScreenY, iWidth, iHeight); itrNode2; ++itrNode2) + for(map_tile_iterator itrNode2(this, iScreenX, iScreenY, iWidth, iHeight); itrNode2; ++itrNode2) { - if(itrNode2->iFlags & THMN_ShadowFull) + if(itrNode2->flags.shadow_full) { - m_pBlocks->drawSprite(pCanvas, 74, itrNode2.x() + iCanvasX - 32, - itrNode2.y() + iCanvasY, THDF_Alpha75); + blocks->draw_sprite(pCanvas, 74, itrNode2.tile_x_position_on_screen() + iCanvasX - 32, + itrNode2.tile_y_position_on_screen() + iCanvasY, thdf_alpha_75); } - else if(itrNode2->iFlags & THMN_ShadowHalf) + else if(itrNode2->flags.shadow_half) { - m_pBlocks->drawSprite(pCanvas, 75, itrNode2.x() + iCanvasX - 32, - itrNode2.y() + iCanvasY, THDF_Alpha75); + blocks->draw_sprite(pCanvas, 75, itrNode2.tile_x_position_on_screen() + iCanvasX - 32, + itrNode2.tile_y_position_on_screen() + iCanvasY, thdf_alpha_75); } - if(!itrNode2.isLastOnScanline()) + if(!itrNode2.is_last_on_scanline()) continue; - for(THMapScanlineIterator itrNode(itrNode2, ScanlineBackward, iCanvasX, iCanvasY); itrNode; ++itrNode) + for(map_scanline_iterator itrNode(itrNode2, map_scanline_iterator_direction::backward, iCanvasX, iCanvasY); itrNode; ++itrNode) { unsigned int iH; unsigned int iBlock = itrNode->iBlock[1]; - if(iBlock != 0 && m_pBlocks->getSpriteSize(iBlock & 0xFF, - NULL, &iH) && iH > 0) + if(iBlock != 0 && blocks->get_sprite_size(iBlock & 0xFF, + nullptr, &iH) && iH > 0) { - m_pBlocks->drawSprite(pCanvas, iBlock & 0xFF, itrNode.x() - 32, + blocks->draw_sprite(pCanvas, iBlock & 0xFF, itrNode.x() - 32, itrNode.y() - iH + 32, iBlock >> 8); - if(itrNode->iFlags & THMN_ShadowWall) + if(itrNode->flags.shadow_wall) { - THClipRect rcOldClip, rcNewClip; - pCanvas->getClipRect(&rcOldClip); - rcNewClip.x = static_cast(itrNode.x() - 32); - rcNewClip.y = static_cast(itrNode.y() - iH + 32 + 4); - rcNewClip.w = static_cast(64); - rcNewClip.h = static_cast(86 - 4); - IntersectTHClipRect(rcNewClip, rcOldClip); - pCanvas->setClipRect(&rcNewClip); - m_pBlocks->drawSprite(pCanvas, 156, itrNode.x() - 32, - itrNode.y() - 56, THDF_Alpha75); - pCanvas->setClipRect(&rcOldClip); + clip_rect rcOldClip, rcNewClip; + pCanvas->get_clip_rect(&rcOldClip); + rcNewClip.x = static_cast(itrNode.x() - 32); + rcNewClip.y = static_cast(itrNode.y() - iH + 32 + 4); + rcNewClip.w = static_cast(64); + rcNewClip.h = static_cast(86 - 4); + clip_rect_intersection(rcNewClip, rcOldClip); + pCanvas->set_clip_rect(&rcNewClip); + blocks->draw_sprite(pCanvas, 156, itrNode.x() - 32, + itrNode.y() - 56, thdf_alpha_75); + pCanvas->set_clip_rect(&rcOldClip); } } - THDrawable *pItem = (THDrawable*)(itrNode->oEarlyEntities.m_pNext); + drawable *pItem = (drawable*)(itrNode->oEarlyEntities.next); while(pItem) { - pItem->m_fnDraw(pItem, pCanvas, itrNode.x(), itrNode.y()); - pItem = (THDrawable*)(pItem->m_pNext); + pItem->draw_fn(pItem, pCanvas, itrNode.x(), itrNode.y()); + pItem = (drawable*)(pItem->next); } } - THMapScanlineIterator itrNode(itrNode2, ScanlineForward, iCanvasX, iCanvasY); + map_scanline_iterator itrNode(itrNode2, map_scanline_iterator_direction::forward, iCanvasX, iCanvasY); if(!bFirst) { //since the scanline count from one THMapScanlineIterator to another can differ - //syncronization between the current iterator and the former one is neeeded + //synchronization between the current iterator and the former one is neeeded if(itrNode.x() < -64) ++itrNode; while(formerIterator.x() < itrNode.x()) @@ -854,37 +1021,37 @@ bool bNeedsRedraw = false; unsigned int iH; unsigned int iBlock = itrNode->iBlock[2]; - if(iBlock != 0 && m_pBlocks->getSpriteSize(iBlock & 0xFF, - NULL, &iH) && iH > 0) + if(iBlock != 0 && blocks->get_sprite_size(iBlock & 0xFF, + nullptr, &iH) && iH > 0) { - m_pBlocks->drawSprite(pCanvas, iBlock & 0xFF, itrNode.x() - 32, + blocks->draw_sprite(pCanvas, iBlock & 0xFF, itrNode.x() - 32, itrNode.y() - iH + 32, iBlock >> 8); } iBlock = itrNode->iBlock[3]; - if(iBlock != 0 && m_pBlocks->getSpriteSize(iBlock & 0xFF, - NULL, &iH) && iH > 0) + if(iBlock != 0 && blocks->get_sprite_size(iBlock & 0xFF, + nullptr, &iH) && iH > 0) { - m_pBlocks->drawSprite(pCanvas, iBlock & 0xFF, itrNode.x() - 32, + blocks->draw_sprite(pCanvas, iBlock & 0xFF, itrNode.x() - 32, itrNode.y() - iH + 32, iBlock >> 8); } iBlock = itrNode->iBlock[1]; - if(iBlock != 0 && m_pBlocks->getSpriteSize(iBlock & 0xFF, - NULL, &iH) && iH > 0) + if(iBlock != 0 && blocks->get_sprite_size(iBlock & 0xFF, + nullptr, &iH) && iH > 0) bNeedsRedraw = true; - if(itrNode->oEarlyEntities.m_pNext) + if(itrNode->oEarlyEntities.next) bNeedsRedraw = true; bool bRedrawAnimations = false; - THDrawable *pItem = (THDrawable*)(itrNode->m_pNext); + drawable *pItem = (drawable*)(itrNode->next); while(pItem) { - pItem->m_fnDraw(pItem, pCanvas, itrNode.x(), itrNode.y()); - if(pItem->m_fnIsMultipleFrameAnimation(pItem)) + pItem->draw_fn(pItem, pCanvas, itrNode.x(), itrNode.y()); + if(pItem->is_multiple_frame_animation_fn(pItem)) bRedrawAnimations = true; - if(pItem->getDrawingLayer() == 1) + if(pItem->get_drawing_layer() == 1) bNeedsRedraw = true; - pItem = (THDrawable*)(pItem->m_pNext); + pItem = (drawable*)(pItem->next); } //if the current tile contained a multiple frame animation (e.g. a doctor walking) @@ -897,25 +1064,25 @@ //check if an object in the adjacent tile to the left of the current tile needs to be redrawn //and if necessary draw it - pItem = (THDrawable*)(formerIterator.getPreviousNode()->m_pNext); + pItem = (drawable*)(formerIterator.get_previous_tile()->next); while(pItem) { - if (pItem->getDrawingLayer() == 9) + if (pItem->get_drawing_layer() == 9) { - pItem->m_fnDraw(pItem, pCanvas, formerIterator.x() - 64, formerIterator.y()); + pItem->draw_fn(pItem, pCanvas, formerIterator.x() - 64, formerIterator.y()); bTileNeedsRedraw = true; } - pItem = (THDrawable*)(pItem->m_pNext); + pItem = (drawable*)(pItem->next); } //check if an object in the adjacent tile above the current tile needs to be redrawn //and if necessary draw it - pItem = (THDrawable*)(formerIterator->m_pNext); + pItem = formerIterator ? (drawable*)(formerIterator->next) : nullptr; while(pItem) { - if(pItem->getDrawingLayer() == 8) - pItem->m_fnDraw(pItem, pCanvas, formerIterator.x(), formerIterator.y()); - pItem = (THDrawable*)(pItem->m_pNext); + if(pItem->get_drawing_layer() == 8) + pItem->draw_fn(pItem, pCanvas, formerIterator.x(), formerIterator.y()); + pItem = (drawable*)(pItem->next); } @@ -925,37 +1092,37 @@ if(bTileNeedsRedraw) { //redraw the north wall - unsigned int iBlock = itrNode.getPreviousNode()->iBlock[1]; - if(iBlock != 0 && m_pBlocks->getSpriteSize(iBlock & 0xFF, - NULL, &iH) && iH > 0) + unsigned int iBlock = itrNode.get_previous_tile()->iBlock[1]; + if(iBlock != 0 && blocks->get_sprite_size(iBlock & 0xFF, + nullptr, &iH) && iH > 0) { - m_pBlocks->drawSprite(pCanvas, iBlock & 0xFF, itrNode.x() - 96, + blocks->draw_sprite(pCanvas, iBlock & 0xFF, itrNode.x() - 96, itrNode.y() - iH + 32, iBlock >> 8); - if(itrNode.getPreviousNode()->iFlags & THMN_ShadowWall) + if(itrNode.get_previous_tile()->flags.shadow_wall) { - THClipRect rcOldClip, rcNewClip; - pCanvas->getClipRect(&rcOldClip); - rcNewClip.x = static_cast(itrNode.x() - 96); - rcNewClip.y = static_cast(itrNode.y() - iH + 32 + 4); - rcNewClip.w = static_cast(64); - rcNewClip.h = static_cast(86 - 4); - IntersectTHClipRect(rcNewClip, rcOldClip); - pCanvas->setClipRect(&rcNewClip); - m_pBlocks->drawSprite(pCanvas, 156, itrNode.x() - 96, - itrNode.y() - 56, THDF_Alpha75); - pCanvas->setClipRect(&rcOldClip); + clip_rect rcOldClip, rcNewClip; + pCanvas->get_clip_rect(&rcOldClip); + rcNewClip.x = static_cast(itrNode.x() - 96); + rcNewClip.y = static_cast(itrNode.y() - iH + 32 + 4); + rcNewClip.w = static_cast(64); + rcNewClip.h = static_cast(86 - 4); + clip_rect_intersection(rcNewClip, rcOldClip); + pCanvas->set_clip_rect(&rcNewClip); + blocks->draw_sprite(pCanvas, 156, itrNode.x() - 96, + itrNode.y() - 56, thdf_alpha_75); + pCanvas->set_clip_rect(&rcOldClip); } } - pItem = (THDrawable*)(itrNode.getPreviousNode()->oEarlyEntities.m_pNext); + pItem = (drawable*)(itrNode.get_previous_tile()->oEarlyEntities.next); while(pItem) { - pItem->m_fnDraw(pItem, pCanvas, itrNode.x() - 64, itrNode.y()); - pItem = (THDrawable*)(pItem->m_pNext); + pItem->draw_fn(pItem, pCanvas, itrNode.x() - 64, itrNode.y()); + pItem = (drawable*)(pItem->next); } - pItem = (THDrawable*)(itrNode.getPreviousNode())->m_pNext; - for(; pItem; pItem = (THDrawable*)(pItem->m_pNext)) - pItem->m_fnDraw(pItem, pCanvas, itrNode.x() - 64, itrNode.y()); + pItem = (drawable*)(itrNode.get_previous_tile())->next; + for(; pItem; pItem = (drawable*)(pItem->next)) + pItem->draw_fn(pItem, pCanvas, itrNode.x() - 64, itrNode.y()); } } bPreviousTileNeedsRedraw = bNeedsRedraw; @@ -966,46 +1133,46 @@ bFirst = false; } - if(m_pOverlay) + if(overlay) { - for(THMapNodeIterator itrNode(this, iScreenX, iScreenY, iWidth, iHeight); itrNode; ++itrNode) + for(map_tile_iterator itrNode(this, iScreenX, iScreenY, iWidth, iHeight); itrNode; ++itrNode) { - m_pOverlay->drawCell(pCanvas, itrNode.x() + iCanvasX - 32, - itrNode.y() + iCanvasY, this, itrNode.nodeX(), itrNode.nodeY()); + overlay->draw_cell(pCanvas, itrNode.tile_x_position_on_screen() + iCanvasX - 32, + itrNode.tile_y_position_on_screen() + iCanvasY, this, itrNode.tile_x(), itrNode.tile_y()); } } - pCanvas->setClipRect(NULL); + pCanvas->set_clip_rect(nullptr); } -THDrawable* THMap::hitTest(int iTestX, int iTestY) const +drawable* level_map::hit_test(int iTestX, int iTestY) const { // This function needs to hitTest each drawable object, in the reverse // order to that in which they would be drawn. - if(m_pBlocks == NULL || m_pCells == NULL) - return NULL; + if(blocks == nullptr || cells == nullptr) + return nullptr; - for(THMapNodeIterator itrNode2(this, iTestX, iTestY, 1, 1, ScanlineBackward); itrNode2; ++itrNode2) + for(map_tile_iterator itrNode2(this, iTestX, iTestY, 1, 1, map_scanline_iterator_direction::backward); itrNode2; ++itrNode2) { - if(!itrNode2.isLastOnScanline()) + if(!itrNode2.is_last_on_scanline()) continue; - for(THMapScanlineIterator itrNode(itrNode2, ScanlineBackward); itrNode; ++itrNode) + for(map_scanline_iterator itrNode(itrNode2, map_scanline_iterator_direction::backward); itrNode; ++itrNode) { - if(itrNode->m_pNext != NULL) + if(itrNode->next != nullptr) { - THDrawable* pResult = _hitTestDrawables(itrNode->m_pNext, + drawable* pResult = hit_test_drawables(itrNode->next, itrNode.x(), itrNode.y(), 0, 0); if(pResult) return pResult; } } - for(THMapScanlineIterator itrNode(itrNode2, ScanlineForward); itrNode; ++itrNode) + for(map_scanline_iterator itrNode(itrNode2, map_scanline_iterator_direction::forward); itrNode; ++itrNode) { - if(itrNode->oEarlyEntities.m_pNext != NULL) + if(itrNode->oEarlyEntities.next != nullptr) { - THDrawable* pResult = _hitTestDrawables(itrNode->oEarlyEntities.m_pNext, + drawable* pResult = hit_test_drawables(itrNode->oEarlyEntities.next, itrNode.x(), itrNode.y(), 0, 0); if(pResult) return pResult; @@ -1013,103 +1180,111 @@ } } - return NULL; + return nullptr; } -THDrawable* THMap::_hitTestDrawables(THLinkList* pListStart, int iXs, int iYs, - int iTestX, int iTestY) const +drawable* level_map::hit_test_drawables(link_list* pListStart, int iXs, int iYs, + int iTestX, int iTestY) const { - THLinkList* pListEnd = pListStart; - while(pListEnd->m_pNext) - pListEnd = pListEnd->m_pNext; - THDrawable* pList = (THDrawable*)pListEnd; + link_list* pListEnd = pListStart; + while(pListEnd->next) + pListEnd = pListEnd->next; + drawable* pList = (drawable*)pListEnd; while(true) { - if(pList->m_fnHitTest(pList, iXs, iYs, iTestX, iTestY)) + if(pList->hit_test_fn(pList, iXs, iYs, iTestX, iTestY)) return pList; if(pList == pListStart) - return NULL; + return nullptr; else - pList = (THDrawable*)pList->m_pPrev; + pList = (drawable*)pList->prev; } } -int THMap::getNodeOwner(const THMapNode* pNode) const +int level_map::get_tile_owner(const map_tile* pNode) const { - return m_pPlotOwner[pNode->iParcelId]; + return plot_owner[pNode->iParcelId]; } -int THMap::getParcelOwner(int iParcel) const +int level_map::get_parcel_owner(int iParcel) const { - if(0 <= iParcel && iParcel < m_iParcelCount) - return m_pPlotOwner[iParcel]; + if(0 <= iParcel && iParcel < parcel_count) + return plot_owner[iParcel]; else return 0; } -uint16_t THMap::getNodeTemperature(const THMapNode* pNode) const +uint16_t level_map::get_tile_temperature(const map_tile* pNode) const { - return pNode->aiTemperature[m_iCurrentTemperatureIndex]; + return pNode->aiTemperature[current_temperature_index]; } -void THMap::setTemperatureDisplay(THMapTemperatureDisplay eTempDisplay) +void level_map::set_temperature_display(temperature_theme eTempDisplay) { - if (eTempDisplay < THMT_Count) m_eTempDisplay = eTempDisplay; + current_temperature_theme = eTempDisplay; +} + +uint32_t level_map::thermal_neighbour(uint32_t &iNeighbourSum, bool canTravel, std::ptrdiff_t relative_idx, map_tile* pNode, int prevTemp) const +{ + int iNeighbourCount = 0; + + map_tile* pNeighbour = pNode + relative_idx; + + // Ensure the neighbour is within the map bounds + map_tile* pLimitNode = cells + width * height; + if (pNeighbour < cells || pNeighbour >= pLimitNode) { + return 0; + } + + if (canTravel) { + iNeighbourCount += 4; + iNeighbourSum += pNeighbour->aiTemperature[prevTemp] * 4; + } else { + bool bObjectPresent = false; + int iHospital1 = pNeighbour->flags.hospital; + int iHospital2 = pNode->flags.hospital; + if (iHospital1 == iHospital2) { + if (pNeighbour->flags.room == pNode->flags.room) { + bObjectPresent = true; + } + } + if (bObjectPresent) { + iNeighbourCount += 4; + iNeighbourSum += pNeighbour->aiTemperature[prevTemp] * 4; + } else { + iNeighbourCount += 1; + iNeighbourSum += pNeighbour->aiTemperature[prevTemp]; + } + } + + return iNeighbourCount; } -void THMap::updateTemperatures(uint16_t iAirTemperature, + +void level_map::update_temperatures(uint16_t iAirTemperature, uint16_t iRadiatorTemperature) { - if(iRadiatorTemperature < iAirTemperature) + if(iRadiatorTemperature < iAirTemperature) { iRadiatorTemperature = iAirTemperature; - const int iPrevTemp = m_iCurrentTemperatureIndex; - m_iCurrentTemperatureIndex ^= 1; - const int iNewTemp = m_iCurrentTemperatureIndex; + } + const int iPrevTemp = current_temperature_index; + current_temperature_index ^= 1; + const int iNewTemp = current_temperature_index; - THMapNode* pLastNode = m_pCells + m_iWidth * m_iHeight; - for(THMapNode *pNode = m_pCells; pNode != pLastNode; ++pNode) - { + map_tile* pLimitNode = cells + width * height; + for(map_tile *pNode = cells; pNode != pLimitNode; ++pNode) { // Get average temperature of neighbour cells uint32_t iNeighbourSum = 0; uint32_t iNeighbourCount = 0; -#define NEIGHBOUR(flag, idx, pNeighbour) \ - if(pNode->iFlags & flag) \ - { \ - iNeighbourCount += 4; \ - iNeighbourSum += pNode[idx].aiTemperature[iPrevTemp] * 4; \ - } \ - else \ - { \ - bool bObjectPresent = false; \ - if(pNeighbour && pNeighbour < pLastNode && pNeighbour > m_pCells) \ - { \ - int iHospital1 = ((THMapNode * )pNeighbour)->iFlags & THMN_Hospital; \ - int iHospital2 = pNode->iFlags & THMN_Hospital; \ - if (iHospital1 == iHospital2) \ - if ((((THMapNode * )pNeighbour)->iFlags & THMN_Room) == (pNode->iFlags & THMN_Room)) \ - bObjectPresent = true; \ - } \ - if (bObjectPresent) \ - { \ - iNeighbourCount += 4; \ - iNeighbourSum += pNode[idx].aiTemperature[iPrevTemp] * 4; \ - } \ - else if(m_pCells <= pNode + (idx) && pNode + (idx) < pLastNode) \ - { \ - iNeighbourCount += 1; \ - iNeighbourSum += pNode[idx].aiTemperature[iPrevTemp]; \ - } \ - } - - NEIGHBOUR(THMN_CanTravelN, -m_iWidth, pNode - m_iWidth); - NEIGHBOUR(THMN_CanTravelS, m_iWidth, pNode + m_iWidth); - NEIGHBOUR(THMN_CanTravelE, 1, pNode + 1); - NEIGHBOUR(THMN_CanTravelW, -1, pNode - 1); -#undef NEIGHBOUR + iNeighbourCount += thermal_neighbour(iNeighbourSum, pNode->flags.can_travel_n, -width, pNode, iPrevTemp); + iNeighbourCount += thermal_neighbour(iNeighbourSum, pNode->flags.can_travel_s, width, pNode, iPrevTemp); + iNeighbourCount += thermal_neighbour(iNeighbourSum, pNode->flags.can_travel_e, 1, pNode, iPrevTemp); + iNeighbourCount += thermal_neighbour(iNeighbourSum, pNode->flags.can_travel_w, -1, pNode, iPrevTemp); + #define MERGE2(src, other, ratio) (src) = static_cast( \ (static_cast(src) * ((ratio) - 1) + (other)) / (ratio)) #define MERGE(other, ratio) \ @@ -1120,36 +1295,27 @@ // or generally dissipate 0.1% of temperature. uint32_t iMergeTemp = 0; double iMergeRatio = 100; - if(pNode->iFlags & THMN_Hospital) - { - if((pNode->iFlags >> 24) == THOB_Radiator) - iRadiatorNumber = 1; - if(pNode->pExtendedObjectList != NULL) - { - int nr = *pNode->pExtendedObjectList & 7; - - for(int i = 0; i < nr; i++) - { - int thob = (*pNode->pExtendedObjectList & (255 << (3 + (i << 3)))) >> (3 + (i << 3)); - if(thob == THOB_Radiator) - iRadiatorNumber++; - } + if(pNode->flags.hospital) { + for(auto thob : pNode->objects) { + if(thob == object_type::radiator) { + iRadiatorNumber++; + } } - if(iRadiatorNumber > 0) - { + if(iRadiatorNumber > 0) { iMergeTemp = iRadiatorTemperature; iMergeRatio = 2 - (iRadiatorNumber - 1) * 0.5; - } - else + } else { iMergeRatio = 1000; - } - else + } + } else { iMergeTemp = iAirTemperature; + } // Diffuse 25% with neighbours pNode->aiTemperature[iNewTemp] = pNode->aiTemperature[iPrevTemp]; - if(iNeighbourCount != 0) + if(iNeighbourCount != 0) { MERGE(iNeighbourSum / iNeighbourCount, 4 - (iRadiatorNumber > 0 ? (iRadiatorNumber - 1) * 1.5 : 0)); + } MERGE(iMergeTemp, iMergeRatio); #undef MERGE @@ -1157,70 +1323,75 @@ } } -void THMap::updatePathfinding() +void level_map::update_pathfinding() { - THMapNode *pNode = m_pCells; + map_tile *pNode = cells; for(int iY = 0; iY < 128; ++iY) { for(int iX = 0; iX < 128; ++iX, ++pNode) { - pNode->iFlags |= THMN_CanTravelN | THMN_CanTravelE | - THMN_CanTravelS | THMN_CanTravelW; + pNode->flags.can_travel_n = true; + pNode->flags.can_travel_e = true; + pNode->flags.can_travel_s = true; + pNode->flags.can_travel_w = true; if(iX == 0) - pNode->iFlags &= ~THMN_CanTravelW; + pNode->flags.can_travel_w = false; else if(iX == 127) - pNode->iFlags &= ~THMN_CanTravelE; + pNode->flags.can_travel_e = false; if(iY == 0) - pNode->iFlags &= ~THMN_CanTravelN; + pNode->flags.can_travel_n = false; else if(iY == 127) - pNode->iFlags &= ~THMN_CanTravelS; + pNode->flags.can_travel_s = false; if(pNode->iBlock[1] & 0xFF) { - pNode->iFlags &= ~THMN_CanTravelN; + pNode->flags.can_travel_n = false; if(iY != 0) { - pNode[-128].iFlags &= ~THMN_CanTravelS; + pNode[-128].flags.can_travel_s = false; } } if(pNode->iBlock[2] & 0xFF) { - pNode->iFlags &= ~THMN_CanTravelW; + pNode->flags.can_travel_w = false; if(iX != 0) { - pNode[-1].iFlags &= ~THMN_CanTravelE; + pNode[-1].flags.can_travel_e = false; } } } } } -void THMap::updateShadows() +//! For shadow casting, a tile is considered to have a wall on a direction +//! if it has a door in that direction, or the block is from the hardcoded +//! range of wall-like blocks. +static inline bool is_wall(map_tile *tile, size_t block, bool flag) { - // For shadow casting, a tile is considered to have a wall on a direction - // if it has a door in that direction, or the block is from the hardcoded - // range of wall-like blocks. -#define IsWall(node, block, door) \ - (((node)->iFlags & (door)) != 0 || \ - (82 <= ((node)->iBlock[(block)] & 0xFF) && ((node)->iBlock[(block)] & 0xFF) <= 164)) - THMapNode *pNode = m_pCells; + return flag || (82 <= (tile->iBlock[block] & 0xFF) && (tile->iBlock[block] & 0xFF) <= 164); +} + +void level_map::update_shadows() +{ + map_tile *pNode = cells; for(int iY = 0; iY < 128; ++iY) { for(int iX = 0; iX < 128; ++iX, ++pNode) { - pNode->iFlags &= ~(THMN_ShadowHalf | THMN_ShadowFull | - THMN_ShadowWall); - if(IsWall(pNode, 2, THMN_TallWest)) + pNode->flags.shadow_full = false; + pNode->flags.shadow_half = false; + pNode->flags.shadow_wall = false; + if(is_wall(pNode, 2, pNode->flags.tall_west)) { - pNode->iFlags |= THMN_ShadowHalf; - if(IsWall(pNode, 1, THMN_TallNorth)) + pNode->flags.shadow_half = true; + if(is_wall(pNode, 1, pNode->flags.tall_north)) { - pNode->iFlags |= THMN_ShadowWall; + pNode->flags.shadow_wall = true; } else if(iY != 0) { - THMapNode *pNeighbour = pNode - 128; - pNeighbour->iFlags |= THMN_ShadowFull; - if(iX != 0 && !IsWall(pNeighbour, 2, THMN_TallWest)) + map_tile *pNeighbour = pNode - 128; + pNeighbour->flags.shadow_full = true; + if(iX != 0 && !is_wall(pNeighbour, 2, pNode->flags.tall_west)) { // Wrap the shadow around a corner (no need to continue // all the way along the wall, as the shadow would be @@ -1228,7 +1399,7 @@ // toggled on, then this optimisation becomes very // visible, but it's a debug option, so it doesn't // matter). - pNeighbour[-1].iFlags |= THMN_ShadowFull; + pNeighbour[-1].flags.shadow_full = true; } } } @@ -1238,36 +1409,36 @@ #undef IsWall } -void THMap::persist(LuaPersistWriter *pWriter) const +void level_map::persist(lua_persist_writer *pWriter) const { - lua_State *L = pWriter->getStack(); - IntegerRunLengthEncoder oEncoder; + lua_State *L = pWriter->get_stack(); + integer_run_length_encoder oEncoder; uint32_t iVersion = 4; - pWriter->writeVUInt(iVersion); - pWriter->writeVUInt(m_iPlayerCount); - for(int i = 0; i < m_iPlayerCount; ++i) + pWriter->write_uint(iVersion); + pWriter->write_uint(player_count); + for(int i = 0; i < player_count; ++i) { - pWriter->writeVUInt(m_aiInitialCameraX[i]); - pWriter->writeVUInt(m_aiInitialCameraY[i]); - pWriter->writeVUInt(m_aiHeliportX[i]); - pWriter->writeVUInt(m_aiHeliportY[i]); + pWriter->write_uint(initial_camera_x[i]); + pWriter->write_uint(initial_camera_y[i]); + pWriter->write_uint(heliport_x[i]); + pWriter->write_uint(heliport_y[i]); } - pWriter->writeVUInt(m_iParcelCount); - for(int i = 0; i < m_iParcelCount; ++i) + pWriter->write_uint(parcel_count); + for(int i = 0; i < parcel_count; ++i) { - pWriter->writeVUInt(m_pPlotOwner[i]); + pWriter->write_uint(plot_owner[i]); } - for(int i = 0; i < m_iParcelCount; ++i) + for(int i = 0; i < parcel_count; ++i) { - pWriter->writeVUInt(m_pParcelTileCounts[i]); + pWriter->write_uint(parcel_tile_counts[i]); } - pWriter->writeVUInt(m_iWidth); - pWriter->writeVUInt(m_iHeight); - pWriter->writeVUInt(m_iCurrentTemperatureIndex); + pWriter->write_uint(width); + pWriter->write_uint(height); + pWriter->write_uint(current_temperature_index); oEncoder.initialise(6); - for(THMapNode *pNode = m_pCells, *pLastNode = m_pCells + m_iWidth * m_iHeight; - pNode != pLastNode; ++pNode) + for(map_tile *pNode = cells, *pLimitNode = cells + width * height; + pNode != pLimitNode; ++pNode) { oEncoder.write(pNode->iBlock[0]); oEncoder.write(pNode->iBlock[1]); @@ -1277,47 +1448,47 @@ oEncoder.write(pNode->iRoomId); // Flags include THOB values, and other things which do not work // well with run-length encoding. - pWriter->writeVUInt(pNode->iFlags); - pWriter->writeVUInt(pNode->aiTemperature[0]); - pWriter->writeVUInt(pNode->aiTemperature[1]); + pWriter->write_uint(static_cast(pNode->flags)); + pWriter->write_uint(pNode->aiTemperature[0]); + pWriter->write_uint(pNode->aiTemperature[1]); lua_rawgeti(L, luaT_upvalueindex(1), 2); - lua_pushlightuserdata(L, pNode->m_pNext); + lua_pushlightuserdata(L, pNode->next); lua_rawget(L, -2); - pWriter->writeStackObject(-1); + pWriter->write_stack_object(-1); lua_pop(L, 1); - lua_pushlightuserdata(L, pNode->oEarlyEntities.m_pNext); + lua_pushlightuserdata(L, pNode->oEarlyEntities.next); lua_rawget(L, -2); - pWriter->writeStackObject(-1); + pWriter->write_stack_object(-1); lua_pop(L, 2); } oEncoder.finish(); - oEncoder.pumpOutput(pWriter); + oEncoder.pump_output(pWriter); oEncoder.initialise(5); - for(THMapNode *pNode = m_pOriginalCells, *pLastNode = m_pOriginalCells + m_iWidth * m_iHeight; - pNode != pLastNode; ++pNode) + for(map_tile *pNode = original_cells, *pLimitNode = original_cells + width * height; + pNode != pLimitNode; ++pNode) { oEncoder.write(pNode->iBlock[0]); oEncoder.write(pNode->iBlock[1]); oEncoder.write(pNode->iBlock[2]); oEncoder.write(pNode->iParcelId); - oEncoder.write(pNode->iFlags); + oEncoder.write(static_cast(pNode->flags)); } oEncoder.finish(); - oEncoder.pumpOutput(pWriter); + oEncoder.pump_output(pWriter); } -void THMap::depersist(LuaPersistReader *pReader) +void level_map::depersist(lua_persist_reader *pReader) { - new (this) THMap; // Call constructor + new (this) level_map; // Call constructor - lua_State *L = pReader->getStack(); + lua_State *L = pReader->get_stack(); int iWidth, iHeight; - IntegerRunLengthDecoder oDecoder; + integer_run_length_decoder oDecoder; uint32_t iVersion; - if(!pReader->readVUInt(iVersion)) return; + if(!pReader->read_uint(iVersion)) return; if(iVersion != 4) { if(iVersion < 2 || iVersion == 128) @@ -1330,282 +1501,283 @@ luaL_error(L, "Cannot load savegame from a newer version."); } } - if(!pReader->readVUInt(m_iPlayerCount)) return; - for(int i = 0; i < m_iPlayerCount; ++i) + if(!pReader->read_uint(player_count)) return; + for(int i = 0; i < player_count; ++i) { - if(!pReader->readVUInt(m_aiInitialCameraX[i])) return; - if(!pReader->readVUInt(m_aiInitialCameraY[i])) return; - if(!pReader->readVUInt(m_aiHeliportX[i])) return; - if(!pReader->readVUInt(m_aiHeliportY[i])) return; - } - if(!pReader->readVUInt(m_iParcelCount)) return; - delete[] m_pPlotOwner; - m_pPlotOwner = new int[m_iParcelCount]; - for(int i = 0; i < m_iParcelCount; ++i) - { - if(!pReader->readVUInt(m_pPlotOwner[i])) return; - } - delete[] m_pParcelTileCounts; - m_pParcelTileCounts = new int[m_iParcelCount]; - m_pParcelTileCounts[0] = 0; + if(!pReader->read_uint(initial_camera_x[i])) return; + if(!pReader->read_uint(initial_camera_y[i])) return; + if(!pReader->read_uint(heliport_x[i])) return; + if(!pReader->read_uint(heliport_y[i])) return; + } + if(!pReader->read_uint(parcel_count)) return; + delete[] plot_owner; + plot_owner = new int[parcel_count]; + for(int i = 0; i < parcel_count; ++i) + { + if(!pReader->read_uint(plot_owner[i])) return; + } + delete[] parcel_tile_counts; + parcel_tile_counts = new int[parcel_count]; + parcel_tile_counts[0] = 0; if(iVersion >= 3) { - for(int i = 0; i < m_iParcelCount; ++i) + for(int i = 0; i < parcel_count; ++i) { - if(!pReader->readVUInt(m_pParcelTileCounts[i])) return; + if(!pReader->read_uint(parcel_tile_counts[i])) return; } } - if(!pReader->readVUInt(iWidth) || !pReader->readVUInt(iHeight)) + if(!pReader->read_uint(iWidth) || !pReader->read_uint(iHeight)) return; - if(!setSize(iWidth, iHeight)) + if(!set_size(iWidth, iHeight)) { - pReader->setError("Unable to set size while depersisting map"); + pReader->set_error("Unable to set size while depersisting map"); return; } if(iVersion >= 4) { - if(!pReader->readVUInt(m_iCurrentTemperatureIndex)) + if(!pReader->read_uint(current_temperature_index)) return; } - for(THMapNode *pNode = m_pCells, *pLastNode = m_pCells + m_iWidth * m_iHeight; - pNode != pLastNode; ++pNode) + for(map_tile *pNode = cells, *pLimitNode = cells + width * height; + pNode != pLimitNode; ++pNode) { - if(!pReader->readVUInt(pNode->iFlags)) return; + uint32_t f; + if(!pReader->read_uint(f)) return; + pNode->flags = f; if(iVersion >= 4) { - if(!pReader->readVUInt(pNode->aiTemperature[0]) - || !pReader->readVUInt(pNode->aiTemperature[1])) return; + if(!pReader->read_uint(pNode->aiTemperature[0]) + || !pReader->read_uint(pNode->aiTemperature[1])) return; } - if(!pReader->readStackObject()) + if(!pReader->read_stack_object()) return; - pNode->m_pNext = (THLinkList*)lua_touserdata(L, -1); - if(pNode->m_pNext) + pNode->next = (link_list*)lua_touserdata(L, -1); + if(pNode->next) { - if(pNode->m_pNext->m_pPrev != NULL) - fprintf(stderr, "Warning: THMap linked-lists are corrupted.\n"); - pNode->m_pNext->m_pPrev = pNode; + if(pNode->next->prev != nullptr) + std::fprintf(stderr, "Warning: THMap linked-lists are corrupted.\n"); + pNode->next->prev = pNode; } lua_pop(L, 1); - if(!pReader->readStackObject()) + if(!pReader->read_stack_object()) return; - pNode->oEarlyEntities.m_pNext = (THLinkList*)lua_touserdata(L, -1); - if(pNode->oEarlyEntities.m_pNext) + pNode->oEarlyEntities.next = (link_list*)lua_touserdata(L, -1); + if(pNode->oEarlyEntities.next) { - if(pNode->oEarlyEntities.m_pNext->m_pPrev != NULL) - fprintf(stderr, "Warning: THMap linked-lists are corrupted.\n"); - pNode->oEarlyEntities.m_pNext->m_pPrev = &pNode->oEarlyEntities; + if(pNode->oEarlyEntities.next->prev != nullptr) + std::fprintf(stderr, "Warning: THMap linked-lists are corrupted.\n"); + pNode->oEarlyEntities.next->prev = &pNode->oEarlyEntities; } - pNode->iFlags &= ~THMN_ObjectsAlreadyErased; lua_pop(L, 1); } oDecoder.initialise(6, pReader); - for(THMapNode *pNode = m_pCells, *pLastNode = m_pCells + m_iWidth * m_iHeight; - pNode != pLastNode; ++pNode) + for(map_tile *pNode = cells, *pLimitNode = cells + width * height; + pNode != pLimitNode; ++pNode) { - pNode->iBlock[0] = oDecoder.read(); - pNode->iBlock[1] = oDecoder.read(); - pNode->iBlock[2] = oDecoder.read(); - pNode->iBlock[3] = oDecoder.read(); - pNode->iParcelId = oDecoder.read(); - pNode->iRoomId = oDecoder.read(); + pNode->iBlock[0] = static_cast(oDecoder.read()); + pNode->iBlock[1] = static_cast(oDecoder.read()); + pNode->iBlock[2] = static_cast(oDecoder.read()); + pNode->iBlock[3] = static_cast(oDecoder.read()); + pNode->iParcelId = static_cast(oDecoder.read()); + pNode->iRoomId = static_cast(oDecoder.read()); } oDecoder.initialise(5, pReader); - for(THMapNode *pNode = m_pOriginalCells, *pLastNode = m_pOriginalCells + m_iWidth * m_iHeight; - pNode != pLastNode; ++pNode) + for(map_tile *pNode = original_cells, *pLimitNode = original_cells + width * height; + pNode != pLimitNode; ++pNode) { - pNode->iBlock[0] = oDecoder.read(); - pNode->iBlock[1] = oDecoder.read(); - pNode->iBlock[2] = oDecoder.read(); - pNode->iParcelId = oDecoder.read(); - pNode->iFlags = oDecoder.read(); + pNode->iBlock[0] = static_cast(oDecoder.read()); + pNode->iBlock[1] = static_cast(oDecoder.read()); + pNode->iBlock[2] = static_cast(oDecoder.read()); + pNode->iParcelId = static_cast(oDecoder.read()); + pNode->flags = oDecoder.read(); } if(iVersion < 3) { - for(int i = 1; i < m_iParcelCount; ++i) - m_pParcelTileCounts[i] = _getParcelTileCount(i); + for(int i = 1; i < parcel_count; ++i) + parcel_tile_counts[i] = get_parcel_tile_count(i); } } -THMapNodeIterator::THMapNodeIterator() - : m_pNode(NULL) - , m_pMap(NULL) - , m_iScreenX(0) - , m_iScreenY(0) - , m_iScreenWidth(0) - , m_iScreenHeight(0) +map_tile_iterator::map_tile_iterator() + : tile(nullptr) + , container(nullptr) + , screen_offset_x(0) + , screen_offset_y(0) + , screen_width(0) + , screen_height(0) { } -THMapNodeIterator::THMapNodeIterator(const THMap *pMap, int iScreenX, int iScreenY, +map_tile_iterator::map_tile_iterator(const level_map* pMap, int iScreenX, int iScreenY, int iWidth, int iHeight, - eTHMapScanlineIteratorDirection eScanlineDirection) - : m_pMap(pMap) - , m_iScreenX(iScreenX) - , m_iScreenY(iScreenY) - , m_iScreenWidth(iWidth) - , m_iScreenHeight(iHeight) - , m_iScanlineCount(0) - , m_eDirection(eScanlineDirection) -{ - if(m_eDirection == ScanlineForward) - { - m_iBaseX = 0; - m_iBaseY = (iScreenY - 32) / 16; - if(m_iBaseY < 0) - m_iBaseY = 0; - else if(m_iBaseY >= m_pMap->getHeight()) - { - m_iBaseX = m_iBaseY - m_pMap->getHeight() + 1; - m_iBaseY = m_pMap->getHeight() - 1; - if(m_iBaseX >= m_pMap->getWidth()) - m_iBaseX = m_pMap->getWidth() - 1; + map_scanline_iterator_direction eScanlineDirection) + : container(pMap) + , screen_offset_x(iScreenX) + , screen_offset_y(iScreenY) + , screen_width(iWidth) + , screen_height(iHeight) + , scanline_count(0) + , direction(eScanlineDirection) +{ + if(direction == map_scanline_iterator_direction::forward) + { + base_x = 0; + base_y = (iScreenY - 32) / 16; + if(base_y < 0) + base_y = 0; + else if(base_y >= container->get_height()) + { + base_x = base_y - container->get_height() + 1; + base_y = container->get_height() - 1; + if(base_x >= container->get_width()) + base_x = container->get_width() - 1; } } else { - m_iBaseX = m_pMap->getWidth() - 1; - m_iBaseY = m_pMap->getHeight() - 1; + base_x = container->get_width() - 1; + base_y = container->get_height() - 1; } - m_iX = m_iBaseX; - m_iY = m_iBaseY; - _advanceUntilVisible(); + world_x = base_x; + world_y = base_y; + advance_until_visible(); } -THMapNodeIterator& THMapNodeIterator::operator ++ () +map_tile_iterator& map_tile_iterator::operator ++ () { - --m_iY; - ++m_iX; - _advanceUntilVisible(); + --world_y; + ++world_x; + advance_until_visible(); return *this; } -void THMapNodeIterator::_advanceUntilVisible() +void map_tile_iterator::advance_until_visible() { - m_pNode = NULL; + tile = nullptr; while(true) { - m_iXs = m_iX; - m_iYs = m_iY; - m_pMap->worldToScreen(m_iXs, m_iYs); - m_iXs -= m_iScreenX; - m_iYs -= m_iScreenY; - if(m_eDirection == ScanlineForward ? - m_iYs >= m_iScreenHeight + ms_iMarginBottom : - m_iYs < -ms_iMarginTop) + x_relative_to_screen = world_x; + y_relative_to_screen = world_y; + container->world_to_screen(x_relative_to_screen, y_relative_to_screen); + x_relative_to_screen -= screen_offset_x; + y_relative_to_screen -= screen_offset_y; + if(direction == map_scanline_iterator_direction::forward ? + y_relative_to_screen >= screen_height + margin_bottom : + y_relative_to_screen < -margin_top) { return; } - if(m_eDirection == ScanlineForward ? - (m_iYs > -ms_iMarginTop) : - (m_iYs < m_iScreenHeight + ms_iMarginBottom)) + if(direction == map_scanline_iterator_direction::forward ? + (y_relative_to_screen > -margin_top) : + (y_relative_to_screen < screen_height + margin_bottom)) { - while(m_iY >= 0 && m_iX < m_pMap->getWidth()) + while(world_y >= 0 && world_x < container->get_width()) { - if(m_iXs < -ms_iMarginLeft) + if(x_relative_to_screen < -margin_left) { // Nothing to do } - else if(m_iXs < m_iScreenWidth + ms_iMarginRight) + else if(x_relative_to_screen < screen_width + margin_right) { - ++m_iScanlineCount; - m_pNode = m_pMap->getNodeUnchecked(m_iX, m_iY); + ++scanline_count; + tile = container->get_tile_unchecked(world_x, world_y); return; } else break; - --m_iY; - ++m_iX; - m_iXs += 64; + --world_y; + ++world_x; + x_relative_to_screen += 64; } } - m_iScanlineCount = 0; - if(m_eDirection == ScanlineForward) + scanline_count = 0; + if(direction == map_scanline_iterator_direction::forward) { - if(m_iBaseY == m_pMap->getHeight() - 1) + if(base_y == container->get_height() - 1) { - if(++m_iBaseX == m_pMap->getWidth()) + if(++base_x == container->get_width()) break; } else - ++m_iBaseY; + ++base_y; } else { - if(m_iBaseX == 0) + if(base_x == 0) { - if(m_iBaseY == 0) + if(base_y == 0) break; else - --m_iBaseY; + --base_y; } else - --m_iBaseX; + --base_x; } - m_iX = m_iBaseX; - m_iY = m_iBaseY; + world_x = base_x; + world_y = base_y; } } -bool THMapNodeIterator::isLastOnScanline() const +bool map_tile_iterator::is_last_on_scanline() const { - return m_iY <= 0 || m_iX + 1 >= m_pMap->getWidth() || - m_iXs + 64 >= m_iScreenWidth + ms_iMarginRight; + return world_y <= 0 || world_x + 1 >= container->get_width() || + x_relative_to_screen + 64 >= screen_width + margin_right; } -THMapScanlineIterator::THMapScanlineIterator() - : m_iNodeStep(0) - , m_iXStep(0) - , m_takenSteps(0) +map_scanline_iterator::map_scanline_iterator() + : tile_step(0) + , x_step(0) + , steps_taken(0) { } -THMapScanlineIterator::THMapScanlineIterator(const THMapNodeIterator& itrNodes, - eTHMapScanlineIteratorDirection eDirection, +map_scanline_iterator::map_scanline_iterator(const map_tile_iterator& itrNodes, + map_scanline_iterator_direction eDirection, int iXOffset, int iYOffset) - : m_iNodeStep((static_cast(eDirection) - 1) * (1 - itrNodes.m_pMap->getWidth())) - , m_iXStep((static_cast(eDirection) - 1) * 64) - , m_takenSteps(0) + : tile_step((static_cast(eDirection) - 1) * (1 - itrNodes.container->get_width())) + , x_step((static_cast(eDirection) - 1) * 64) + , steps_taken(0) { - if(eDirection == ScanlineBackward) + if(eDirection == map_scanline_iterator_direction::backward) { - m_pNode = itrNodes.m_pNode; - m_iXs = itrNodes.x(); + tile = itrNodes.tile; + x_relative_to_screen = itrNodes.tile_x_position_on_screen(); } else { - m_pNode = itrNodes.m_pNode - m_iNodeStep * (itrNodes.m_iScanlineCount - 1); - m_iXs = itrNodes.x() - m_iXStep * (itrNodes.m_iScanlineCount - 1); + tile = itrNodes.tile - tile_step * (itrNodes.scanline_count - 1); + x_relative_to_screen = itrNodes.tile_x_position_on_screen() - x_step * (itrNodes.scanline_count - 1); } - m_iXs += iXOffset; - m_iYs = itrNodes.y() + iYOffset; + x_relative_to_screen += iXOffset; + y_relative_to_screen = itrNodes.tile_y_position_on_screen() + iYOffset; - m_pNodeEnd = m_pNode + m_iNodeStep * itrNodes.m_iScanlineCount; - m_pNodeFirst = m_pNode; + end_tile = tile + tile_step * itrNodes.scanline_count; + first_tile = tile; } -THMapScanlineIterator& THMapScanlineIterator::operator ++ () +map_scanline_iterator& map_scanline_iterator::operator ++ () { - m_pNode += m_iNodeStep; - m_iXs += m_iXStep; - m_takenSteps++; + tile += tile_step; + x_relative_to_screen += x_step; + steps_taken++; return *this; } -//copies the members of the given THMapScanlineIterator and resets the node member to the +//copies the members of the given THMapScanlineIterator and resets the tile member to the //first element. -THMapScanlineIterator THMapScanlineIterator::operator= (const THMapScanlineIterator &iterator) +map_scanline_iterator map_scanline_iterator::operator= (const map_scanline_iterator &iterator) { - m_pNode = iterator.m_pNodeFirst; - m_pNodeEnd = iterator.m_pNodeEnd; - m_iXs = iterator.m_iXs - iterator.m_takenSteps * iterator.m_iXStep; - m_iYs = iterator.m_iYs; - m_iXStep = iterator.m_iXStep; - m_iNodeStep = iterator.m_iNodeStep; + tile = iterator.first_tile; + end_tile = iterator.end_tile; + x_relative_to_screen = iterator.x_relative_to_screen - iterator.steps_taken * iterator.x_step; + y_relative_to_screen = iterator.y_relative_to_screen; + x_step = iterator.x_step; + tile_step = iterator.tile_step; return *this; } diff -Nru corsix-th-0.30/CorsixTH/Src/th_map.h corsix-th-0.62/CorsixTH/Src/th_map.h --- corsix-th-0.30/CorsixTH/Src/th_map.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_map.h 2018-07-21 11:13:17.000000000 +0000 @@ -23,167 +23,199 @@ #ifndef CORSIX_TH_TH_MAP_H_ #define CORSIX_TH_TH_MAP_H_ #include "th_gfx.h" +#include +#include /* Object type enumeration uses same values as original TH does. See game string table section 39 for proof. Section 1 also has names in this order. */ -enum THObjectType +enum class object_type : uint8_t { - THOB_NoObject = 0, - THOB_Desk = 1, - THOB_Cabinet = 2, - THOB_Door = 3, - THOB_Bench = 4, - THOB_Table = 5, // Not in game - THOB_Chair = 6, - THOB_DrinksMachine = 7, - THOB_Bed = 8, - THOB_Inflator = 9, - THOB_PoolTable = 10, - THOB_ReceptionDesk = 11, - THOB_BTable = 12, // Not in game? - THOB_Cardio = 13, - THOB_Scanner = 14, - THOB_ScannerConsole = 15, - THOB_Screen = 16, - THOB_LitterBomb = 17, - THOB_Couch = 18, - THOB_Sofa = 19, - THOB_Crash = 20, // The trolley in general diagnosis - THOB_TV = 21, - THOB_Ultrascan = 22, - THOB_DNAFixer = 23, - THOB_CastRemover = 24, - THOB_HairRestorer = 25, - THOB_Slicer = 26, - THOB_XRay = 27, - THOB_RadiationShield = 28, - THOB_XRayViewer = 29, - THOB_OpTable = 30, - THOB_Lamp = 31, // Not in game? - THOB_Sink = 32, - THOB_OpSink1 = 33, - THOB_OpSink2 = 34, - THOB_SurgeonScreen = 35, - THOB_LectureChair = 36, - THOB_Projector = 37, + no_object = 0, + desk = 1, + cabinet = 2, + door = 3, + bench = 4, + table = 5, // Not in game + chair = 6, + drinks_machine = 7, + bed = 8, + inflator = 9, + pool_table = 10, + reception_desk = 11, + b_table = 12, // Not in game? + cardio = 13, + scanner = 14, + scanner_console = 15, + screen = 16, + litter_bomb = 17, + couch = 18, + sofa = 19, + crash = 20, // The trolley in general diagnosis + tv = 21, + ultrascan = 22, + dna_fixer = 23, + cast_remover = 24, + hair_restorer = 25, + slicer = 26, + xray = 27, + radiation_shield = 28, + xray_viewer = 29, + op_table = 30, + lamp = 31, // Not in game? + sink = 32, + op_sink1 = 33, + op_sink2 = 34, + surgeon_screen = 35, + lecture_chair = 36, + projector = 37, // 38 is unused - THOB_Pharmacy = 39, - THOB_Computer = 40, - THOB_ChemicalMixer = 41, - THOB_BloodMachine = 42, - THOB_Extinguisher = 43, - THOB_Radiator = 44, - THOB_Plant = 45, - THOB_Electro = 46, - THOB_JellyVat = 47, - THOB_Hell = 48, + pharmacy = 39, + computer = 40, + chemical_mixer = 41, + blood_machine = 42, + extinguisher = 43, + radiator = 44, + plant = 45, + electro = 46, + jelly_vat = 47, + hell = 48, // 49 is unused - THOB_Bin = 50, - THOB_Loo = 51, - THOB_DoubleDoor1 = 52, - THOB_DoubleDoor2 = 53, - THOB_DeconShower = 54, - THOB_Autopsy = 55, - THOB_Bookcase = 56, - THOB_VideoGame = 57, - THOB_EntranceLeftDoor = 58, - THOB_EntranceRightDoor = 59, - THOB_Skeleton = 60, - THOB_ComfyChair = 61, - // 62 through 255 are unused + bin = 50, + loo = 51, + double_door1 = 52, + double_door2 = 53, + decon_shower = 54, + autopsy = 55, + bookcase = 56, + video_game = 57, + entrance_left_door = 58, + entrance_right_door = 59, + skeleton = 60, + comfy_chair = 61, + litter = 62, + helicopter = 63, + rathole = 64, + // 65 through 255 are unused }; -enum THMapNodeFlags +//! Map flags and object type +//! The point of storing the object type here is to allow pathfinding code +//! to use object types as pathfinding goals. +struct map_tile_flags { - THMN_Passable = 1 << 0, //!< Pathfinding: Can walk on this tile - THMN_CanTravelN = 1 << 1, //!< Pathfinding: Can walk to the north - THMN_CanTravelE = 1 << 2, //!< Pathfinding: Can walk to the east - THMN_CanTravelS = 1 << 3, //!< Pathfinding: Can walk to the south - THMN_CanTravelW = 1 << 4, //!< Pathfinding: Can walk to the west - THMN_Hospital = 1 << 5, //!< World: Tile is inside a hospital building - THMN_Hospital_Shift = 5, - THMN_Buildable = 1 << 6, //!< Player: Can build on this tile - //! Pathfinding: Normally can walk on this tile, but can't due to blueprint - THMN_PassableIfNotForBlueprint = 1 << 7, - THMN_PassableIfNotForBlueprint_ShiftDelta = 7, - THMN_Room = 1 << 8, //!< World: Tile is inside a room - THMN_ShadowHalf = 1 << 9, //!< Rendering: Put block 75 over floor - THMN_ShadowFull = 1 << 10, //!< Rendering: Put block 74 over floor - THMN_ShadowWall = 1 << 11, //!< Rendering: Put block 156 over east wall - THMN_DoorNorth = 1 << 12, //!< World: Door on north wall of tile - THMN_DoorWest = 1 << 13, //!< World: Door on west wall of tile - THMN_DoNotIdle = 1 << 14, //!< World: Humanoids should not idle on tile - THMN_TallNorth = 1 << 15, //!< Shadows: Wall-like object on north wall - THMN_TallWest = 1 << 16, //!< Shadows: Wall-like object on west wall - THMN_BuildableN = 1 << 17, //!< Can build on the north side of the tile - THMN_BuildableE = 1 << 18, //!< Can build on the east side of the tile - THMN_BuildableS = 1 << 19, //!< Can build on the south side of the tile - THMN_BuildableW = 1 << 20, //!< Can build on the west side of the tile - THMN_ObjectsAlreadyErased = 1 << 23, //!< Specifies if after a load the object types in this tile were already erased - // NB: Bits 24 through 31 reserved for object type (that being one of the - // THObjectType values) -}; + enum class key : uint32_t { + passable_mask = 1 << 0, + can_travel_n_mask = 1 << 1, + can_travel_e_mask = 1 << 2, + can_travel_s_mask = 1 << 3, + can_travel_w_mask = 1 << 4, + hospital_mask = 1 << 5, + buildable_mask = 1 << 6, + passable_if_not_for_blueprint_mask = 1 << 7, + room_mask = 1 << 8, + shadow_half_mask = 1 << 9, + shadow_full_mask = 1 << 10, + shadow_wall_mask = 1 << 11, + door_north_mask = 1 << 12, + door_west_mask = 1 << 13, + do_not_idle_mask = 1 << 14, + tall_north_mask = 1 << 15, + tall_west_mask = 1 << 16, + buildable_n_mask = 1 << 17, + buildable_e_mask = 1 << 18, + buildable_s_mask = 1 << 19, + buildable_w_mask = 1 << 20, + }; + + bool passable; //!< Pathfinding: Can walk on this tile + bool can_travel_n; //!< Pathfinding: Can walk to the north + bool can_travel_e; //!< Pathfinding: Can walk to the east + bool can_travel_s; //!< Pathfinding: Can walk to the south + bool can_travel_w; //!< Pathfinding: Can walk to the west + bool hospital; //!< World: Tile is inside a hospital building + bool buildable; //!< Player: Can build on this tile + bool passable_if_not_for_blueprint; + bool room; //!< World: Tile is inside a room + bool shadow_half; //!< Rendering: Put block 75 over floor + bool shadow_full; //!< Rendering: Put block 74 over floor + bool shadow_wall; //!< Rendering: Put block 156 over east wall + bool door_north; //!< World: Door on north wall of tile + bool door_west; //!< World: Door on west wall of tile + bool do_not_idle; //!< World: Humanoids should not idle on tile + bool tall_north; //!< Shadows: Wall-like object on north wall + bool tall_west; //!< Shadows: Wall-like object on west wall + bool buildable_n; //!< Can build on the north side of the tile + bool buildable_e; //!< Can build on the east side of the tile + bool buildable_s; //!< Can build on the south side of the tile + bool buildable_w; //!< Can build on the west side of the tile + + //! Convert the given uint32_t reprentation of the map_tile flags + //! to a map_tile_flags instance. + map_tile_flags& operator =(uint32_t raw); -enum THMapTemperatureDisplay -{ - THMT_Red, //!< Default warmth colouring (red gradients) - THMT_MultiColour, //!< Different colours (blue, green, red) - THMT_YellowRed, //!< Gradients of yellow, orange, and red + //! Get/set the flag with the given key + bool& operator[] (map_tile_flags::key key); + + //! Get the flag with the given key + const bool& operator[](map_tile_flags::key key) const; + + //! Convert map_tile_flags into it's uint32_t representation + operator uint32_t() const; +}; - THMT_Count, //!< Number of temperature display values. +enum class temperature_theme { + red, //!< Default warmth colouring (red gradients) + multi_colour, //!< Different colours (blue, green, red) + yellow_red //!< Gradients of yellow, orange, and red }; -struct THMapNode : public THLinkList +struct map_tile : public link_list { - THMapNode(); - ~THMapNode(); + map_tile(); + ~map_tile(); - // Linked list for entities rendered at this node - // THLinkList::pPrev (will always be NULL) + // Linked list for entities rendered at this tile + // THLinkList::pPrev (will always be nullptr) // THLinkList::pNext - // Linked list for entities rendered in an early (right-to-left) pass - THLinkList oEarlyEntities; + //! Linked list for entities rendered in an early (right-to-left) pass + link_list oEarlyEntities; - // Block tiles for rendering - // For each tile, the lower byte is the index in the sprite sheet, and the - // upper byte is for the drawing flags. - // Layer 0 is for the floor - // Layer 1 is for the north wall - // Layer 2 is for the west wall - // Layer 3 is for the UI - // NB: In Lua, layers are numbered 1 - 4 rather than 0 - 3 + //! Block tiles for rendering + //! For each tile, the lower byte is the index in the sprite sheet, and the + //! upper byte is for the drawing flags. + //! Layer 0 is for the floor + //! Layer 1 is for the north wall + //! Layer 2 is for the west wall + //! Layer 3 is for the UI + //! NB: In Lua, layers are numbered 1 - 4 rather than 0 - 3 uint16_t iBlock[4]; - // Parcels (plots) of land have an ID, with each tile in the plot having - // that ID. Parcel 0 is the outside. + //! Parcels (plots) of land have an ID, with each tile in the plot having + //! that ID. Parcel 0 is the outside. uint16_t iParcelId; - // Rooms have an ID, with room #0 being the corridor (and the outside). + //! Rooms have an ID, with room #0 being the corridor (and the outside). uint16_t iRoomId; - // A value between 0 (extreme cold) and 65535 (extreme heat) representing - // the temperature of the tile. To allow efficent calculation of a tile's - // heat based on the previous tick's heat of the surrounding tiles, the - // previous temperature is also stored, with the array indicies switching - // every tick. + //! A value between 0 (extreme cold) and 65535 (extreme heat) representing + //! the temperature of the tile. To allow efficient calculation of a tile's + //! heat based on the previous tick's heat of the surrounding tiles, the + //! previous temperature is also stored, with the array indices switching + //! every tick. uint16_t aiTemperature[2]; - // Flags for information (lower 24 bits) and object type (top 8 bits) - // See THMapNodeFlags for lower 24 bits, and THObjectType for top 8. - // The point of storing the object type here is to allow pathfinding code - // to use object types as pathfinding goals. - uint32_t iFlags; - - // the first 3 bits of the object store the number of additional objects stored, while - // the remaining bits store the object type of the additional objects - uint64_t *pExtendedObjectList; + //! Flags for information and object type + map_tile_flags flags; + + //! objects in this tile + std::list objects; }; -class THSpriteSheet; +class sprite_sheet; //! Prototype for object callbacks from THMap::loadFromTHFile /*! @@ -194,63 +226,65 @@ * The object flags present in the map data. The meaning of this value is left unspecified. */ -typedef void (*THMapLoadObjectCallback_t)(void*, int, int, THObjectType, uint8_t); +typedef void (*map_load_object_callback_fn)(void*, int, int, object_type, uint8_t); -class THMapOverlay; +class map_overlay; -class THMap +class level_map { public: - THMap(); - ~THMap(); + level_map(); + ~level_map(); - bool setSize(int iWidth, int iHeight); - bool loadBlank(); - bool loadFromTHFile(const unsigned char* pData, size_t iDataLength, - THMapLoadObjectCallback_t fnObjectCallback, + bool set_size(int iWidth, int iHeight); + bool load_blank(); + bool load_from_th_file(const uint8_t* pData, size_t iDataLength, + map_load_object_callback_fn fnObjectCallback, void* pCallbackToken); - void save(void (*fnWriter)(void*, const unsigned char*, size_t), - void* pToken); + void save(std::string filename); //! Set the sprite sheet to be used for drawing the map /*! The sprites for map floor tiles, wall tiles, and map decorators all come from the given sheet. */ - void setBlockSheet(THSpriteSheet* pSheet); + void set_block_sheet(sprite_sheet* pSheet); //! Set the draw flags on all wall blocks /*! This is typically called with THDF_Alpha50 to draw walls transparently, or with 0 to draw them opaque again. */ - void setAllWallDrawFlags(unsigned char iFlags); + void set_all_wall_draw_flags(uint8_t iFlags); - void updatePathfinding(); - void updateShadows(); - void setTemperatureDisplay(THMapTemperatureDisplay eTempDisplay); - inline THMapTemperatureDisplay getTemperatureDisplay() const {return m_eTempDisplay;} - void updateTemperatures(uint16_t iAirTemperature, + void update_pathfinding(); + void update_shadows(); + void set_temperature_display(temperature_theme eTempDisplay); + inline temperature_theme get_temperature_display() const {return current_temperature_theme;} + void update_temperatures(uint16_t iAirTemperature, uint16_t iRadiatorTemperature); //! Get the map width (in tiles) - inline int getWidth() const {return m_iWidth;} + inline int get_width() const {return width;} //! Get the map height (in tiles) - inline int getHeight() const {return m_iHeight;} + inline int get_height() const {return height;} //! Get the number of plots of land in this map - inline int getParcelCount() const {return m_iParcelCount - 1;} + inline int get_parcel_count() const {return parcel_count - 1;} + + inline int get_player_count() const {return player_count;} + + void set_player_count(int count); - inline int getPlayerCount() const {return m_iPlayerCount;} - bool getPlayerCameraTile(int iPlayer, int* pX, int* pY) const; - bool getPlayerHeliportTile(int iPlayer, int* pX, int* pY) const; - void setPlayerCameraTile(int iPlayer, int iX, int iY); - void setPlayerHeliportTile(int iPlayer, int iX, int iY); + bool get_player_camera_tile(int iPlayer, int* pX, int* pY) const; + bool get_player_heliport_tile(int iPlayer, int* pX, int* pY) const; + void set_player_camera_tile(int iPlayer, int iX, int iY); + void set_player_heliport_tile(int iPlayer, int iX, int iY); //! Get the number of tiles inside a given parcel - int getParcelTileCount(int iParcelId) const; + int get_parcel_tile_count(int iParcelId) const; //! Change the owner of a particular parcel /*! @@ -259,8 +293,10 @@ the outside, and should never have its ownership changed). \param iOwner The number of the player who should own the parcel, or zero if no player should own the parcel. + \return vSplitTiles A vector that contains tile coordinates where + iParcelId is adjacent to another part of the hospital. */ - void setParcelOwner(int iParcelId, int iOwner); + std::vector> set_parcel_owner(int iParcelId, int iOwner); //! Get the owner of a particular parcel of land /*! @@ -268,7 +304,7 @@ \return 0 if the parcel is unowned, otherwise the number of the owning player. */ - int getParcelOwner(int iParcelId) const; + int get_parcel_owner(int iParcelId) const; //! Query if two parcels are directly connected /*! @@ -277,7 +313,7 @@ \return true if there is a path between the two parcels which does not go into any other parcels. false otherwise. */ - bool areParcelsAdjacent(int iParcel1, int iParcel2); + bool are_parcels_adjacent(int iParcel1, int iParcel2); //! Query if a given player is in a position to purchase a given parcel /*! @@ -289,7 +325,7 @@ connected to a parcel already owned by the given player. false otherwise. */ - bool isParcelPurchasable(int iParcelId, int iPlayer); + bool is_parcel_purchasable(int iParcelId, int iPlayer); //! Draw the map (and any attached animations) /*! @@ -299,34 +335,34 @@ co-ordinates - they are not world (tile) co-ordinates, nor (relative) screen co-ordinates. */ - void draw(THRenderTarget* pCanvas, int iScreenX, int iScreenY, int iWidth, + void draw(render_target* pCanvas, int iScreenX, int iScreenY, int iWidth, int iHeight, int iCanvasX, int iCanvasY) const; //! Perform a hit-test against the animations attached to the map /*! If there is an animation at world pixel co-ordinates (iTestX, iTestY), - then it is returned. Otherwise NULL is returned. - To perform a hit-test using world (tile) co-ordinates, get the node - itself and query the top 8 bits of THMapNode::iFlags, or traverse the - node's animation lists. + then it is returned. Otherwise nullptr is returned. + To perform a hit-test using world (tile) co-ordinates, get the tile + itself and query the top 8 bits of map_tile::flags, or traverse the + tile's animation lists. */ - THDrawable* hitTest(int iTestX, int iTestY) const; + drawable* hit_test(int iTestX, int iTestY) const; // When using the unchecked versions, the map co-ordinates MUST be valid. - // When using the normal versions, NULL is returned for invalid co-ords. - THMapNode* getNode(int iX, int iY); - const THMapNode* getNode(int iX, int iY) const; - const THMapNode* getOriginalNode(int iX, int iY) const; - THMapNode* getNodeUnchecked(int iX, int iY); - const THMapNode* getNodeUnchecked(int iX, int iY) const; - const THMapNode* getOriginalNodeUnchecked(int iX, int iY) const; + // When using the normal versions, nullptr is returned for invalid co-ords. + map_tile* get_tile(int iX, int iY); + const map_tile* get_tile(int iX, int iY) const; + const map_tile* get_original_tile(int iX, int iY) const; + map_tile* get_tile_unchecked(int iX, int iY); + const map_tile* get_tile_unchecked(int iX, int iY) const; + const map_tile* get_original_tile_unchecked(int iX, int iY) const; - uint16_t getNodeTemperature(const THMapNode* pNode) const; - int getNodeOwner(const THMapNode* pNode) const; + uint16_t get_tile_temperature(const map_tile* pNode) const; + int get_tile_owner(const map_tile* pNode) const; //! Convert world (tile) co-ordinates to absolute screen co-ordinates template - static inline void worldToScreen(T& x, T& y) + static inline void world_to_screen(T& x, T& y) { T x_(x); x = (T)32 * (x_ - y); @@ -335,84 +371,93 @@ //! Convert absolute screen co-ordinates to world (tile) co-ordinates template - static inline void screenToWorld(T& x, T& y) + static inline void screen_to_world(T& x, T& y) { T x_(x); x = y / (T)32 + x_ / (T)64; y = y / (T)32 - x_ / (T)64; } - void persist(LuaPersistWriter *pWriter) const; - void depersist(LuaPersistReader *pReader); + void persist(lua_persist_writer *pWriter) const; + void depersist(lua_persist_reader *pReader); - void setOverlay(THMapOverlay *pOverlay, bool bTakeOwnership); + void set_overlay(map_overlay *pOverlay, bool bTakeOwnership); -protected: - THDrawable* _hitTestDrawables(THLinkList* pListStart, int iXs, int iYs, - int iTestX, int iTestY) const; - void _readTileIndex(const unsigned char* pData, int& iX, int &iY) const; - void _writeTileIndex(unsigned char* pData, int iX, int iY) const; - int _getParcelTileCount(int iParcelId) const; +private: + drawable* hit_test_drawables(link_list* pListStart, int iXs, int iYs, + int iTestX, int iTestY) const; + void read_tile_index(const uint8_t* pData, int& iX, int &iY) const; + void write_tile_index(uint8_t* pData, int iX, int iY) const; + + //! Calculate a weighted impact of a neighbour tile on the temperature of the current tile. + //! \param iNeighbourSum Incremented by the temperature of the tile multiplied by the weight of the connection. + //! \param canTravel A tile flag indicating whether travel between this tile and it's neighbour is allowed. + //! \param relative_idx The index of the neighbour tile, relative to this tile into cells. + //! \param pNode A pointer to the current tile being tested. + //! \param prevTemp The array index into map_tile::temperature that currently stores the temperature of the tile (prior to this calculation). + //! \return The weight of the connection, 0 if there is no neighbour, 1 through walls, and 4 through air. + uint32_t thermal_neighbour(uint32_t &iNeighbourSum, bool canTravel, std::ptrdiff_t relative_idx, map_tile* pNode, int prevTemp) const; //! Create the adjacency matrix if it doesn't already exist - void _makeAdjacencyMatrix(); + void make_adjacency_matrix(); //! Create the purchasability matrix if it doesn't already exist - void _makePurchaseMatrix(); + void make_purchase_matrix(); //! If it exists, update the purchasability matrix. - void _updatePurchaseMatrix(); - - THMapNode* m_pCells; - THMapNode* m_pOriginalCells; // Cells at map load time, before any changes - THSpriteSheet* m_pBlocks; - THMapOverlay* m_pOverlay; - bool m_bOwnOverlay; - int* m_pPlotOwner; // 0 for unowned, 1 for player 1, etc. - int m_iWidth; - int m_iHeight; - int m_iPlayerCount; - int m_aiInitialCameraX[4]; - int m_aiInitialCameraY[4]; - int m_aiHeliportX[4]; - int m_aiHeliportY[4]; - int m_iParcelCount; - int m_iCurrentTemperatureIndex; - THMapTemperatureDisplay m_eTempDisplay; - int* m_pParcelTileCounts; + void update_purchase_matrix(); + + int count_parcel_tiles(int iParcelId) const; + + map_tile* cells; + map_tile* original_cells; // Cells at map load time, before any changes + sprite_sheet* blocks; + map_overlay* overlay; + bool owns_overlay; + int* plot_owner; // 0 for unowned, 1 for player 1, etc. + int width; + int height; + int player_count; + int initial_camera_x[4]; + int initial_camera_y[4]; + int heliport_x[4]; + int heliport_y[4]; + int parcel_count; + int current_temperature_index; + temperature_theme current_temperature_theme; + int* parcel_tile_counts; // 2D symmetric array giving true if there is a path between two parcels // which doesn't go into any other parcels. - bool* m_pParcelAdjacencyMatrix; + bool* parcel_adjacency_matrix; // 4 by N matrix giving true if player can purchase parcel. - bool* m_pPurchasableMatrix; + bool* purchasable_matrix; }; -enum eTHMapScanlineIteratorDirection -{ - ScanlineForward = 2, - ScanlineBackward = 0, +enum class map_scanline_iterator_direction { + forward = 2, + backward = 0, }; -//! Utility class for iterating over map nodes within a screen rectangle +//! Utility class for iterating over map tiles within a screen rectangle /*! - To easily iterate over the map nodes which might draw something within a + To easily iterate over the map tiles which might draw something within a certain rectangle of screen space, an instance of this class can be used. By default, it iterates by scanline, top-to-bottom, and then left-to-right within each scanline. Alternatively, by passing ScanlineBackward to the constructor, it will iterate bottom-to-top. Within a scanline, to visit - nodes right-to-left, wait until isLastOnScanline() returns true, then use + tiles right-to-left, wait until isLastOnScanline() returns true, then use an instance of THMapScanlineIterator. */ -class THMapNodeIterator +class map_tile_iterator { public: - THMapNodeIterator(); + map_tile_iterator(); /*! - @arg pMap The map whose nodes should be iterated + @arg pMap The map whose tiles should be iterated @arg iScreenX The X co-ordinate of the top-left corner of the screen-space rectangle to iterate. @arg iScreenY The Y co-ordinate of the top-left corner of the @@ -420,109 +465,112 @@ @arg iWidth The width of the screen-space rectangle to iterate. @arg iHeight The width of the screen-space rectangle to iterate. @arg eScanlineDirection The direction in which to iterate scanlines; - ScanlineForward for top-to-bottom, ScanlineBackward for bottom-to-top. + forward for top-to-bottom, backward for bottom-to-top. */ - THMapNodeIterator(const THMap *pMap, int iScreenX, int iScreenY, - int iWidth, int iHeight, - eTHMapScanlineIteratorDirection eScanlineDirection = ScanlineForward); + map_tile_iterator(const level_map*pMap, int iScreenX, int iScreenY, + int iWidth, int iHeight, + map_scanline_iterator_direction eScanlineDirection = map_scanline_iterator_direction::forward); - //! Returns false iff the iterator has exhausted its nodes - inline operator bool () const {return m_pNode != NULL;} + //! Returns false iff the iterator has exhausted its tiles + inline operator bool () const {return tile != nullptr;} - //! Advances the iterator to the next node - inline THMapNodeIterator& operator ++ (); + //! Advances the iterator to the next tile + inline map_tile_iterator& operator ++ (); - //! Accessor for the current node - inline const THMapNode* operator -> () const {return m_pNode;} + //! Accessor for the current tile + inline const map_tile* operator -> () const {return tile;} - //! Get the X position of the node relative to the top-left corner of the screen-space rectangle - inline int x() const {return m_iXs;} + //! Get the X position of the tile relative to the top-left corner of the screen-space rectangle + inline int tile_x_position_on_screen() const {return x_relative_to_screen;} - //! Get the Y position of the node relative to the top-left corner of the screen-space rectangle - inline int y() const {return m_iYs;} + //! Get the Y position of the tile relative to the top-left corner of the screen-space rectangle + inline int tile_y_position_on_screen() const {return y_relative_to_screen;} - inline int nodeX() const {return m_iX;} - inline int nodeY() const {return m_iY;} + inline int tile_x() const {return world_x;} + inline int tile_y() const {return world_y;} - inline const THMap *getMap() {return m_pMap;} - inline const THMapNode *getMapNode() {return m_pNode;} - inline int getScanlineCount() { return m_iScanlineCount;} - inline int getNodeStep() {return (static_cast(m_eDirection) - 1) * (1 - m_pMap->getWidth());} + inline const level_map *get_map() {return container;} + inline const map_tile *get_map_tile() {return tile;} + inline int get_scanline_count() { return scanline_count;} + inline int get_tile_step() {return (static_cast(direction) - 1) * (1 - container->get_width());} - //! Returns true iff the next node will be on a different scanline + //! Returns true iff the next tile will be on a different scanline /*! To visit a scanline in right-to-left order, or to revisit a scanline, wait until this method returns true, then use a THMapScanlineIterator. */ - inline bool isLastOnScanline() const; + inline bool is_last_on_scanline() const; -protected: - // Maximum extents of the visible parts of a node (pixel distances relative +private: + // Maximum extents of the visible parts of a tile (pixel distances relative // to the top-most corner of an isometric cell) // If set too low, things will disappear when near the screen edge // If set too high, rendering will slow down - static const int ms_iMarginTop = 150; - static const int ms_iMarginLeft = 110; - static const int ms_iMarginRight = 110; - static const int ms_iMarginBottom = 150; - - friend class THMapScanlineIterator; - - const THMapNode* m_pNode; - const THMap* m_pMap; - int m_iXs; - int m_iYs; - const int m_iScreenX; - const int m_iScreenY; - const int m_iScreenWidth; - const int m_iScreenHeight; - int m_iBaseX; - int m_iBaseY; - int m_iX; - int m_iY; - int m_iScanlineCount; - eTHMapScanlineIteratorDirection m_eDirection; + static const int margin_top = 150; + static const int margin_left = 110; + static const int margin_right = 110; + static const int margin_bottom = 150; + + friend class map_scanline_iterator; + + const map_tile* tile; + const level_map* container; + + // TODO: Consider removing these, they are trivial to calculate + int x_relative_to_screen; + int y_relative_to_screen; + + const int screen_offset_x; + const int screen_offset_y; + const int screen_width; + const int screen_height; + int base_x; + int base_y; + int world_x; + int world_y; + int scanline_count; + map_scanline_iterator_direction direction; - void _advanceUntilVisible(); + void advance_until_visible(); }; -//! Utility class for re-iterating a scanline visited by a THMapNodeIterator -class THMapScanlineIterator +//! Utility class for re-iterating a scanline visited by a map_tile_iterator +class map_scanline_iterator { public: - THMapScanlineIterator(); + map_scanline_iterator(); /*! - @arg itrNodes A node iterator which has reached the end of a scanline + @arg itrNodes A tile iterator which has reached the end of a scanline @arg eDirection The direction in which to iterate the scanline; - ScanlineForward for left-to-right, ScanlineBackward for right-to-left. + forward for left-to-right, backward for right-to-left. @arg iXOffset If given, values returned by x() will be offset by this. @arg iYOffset If given, values returned by y() will be offset by this. */ - THMapScanlineIterator(const THMapNodeIterator& itrNodes, - eTHMapScanlineIteratorDirection eDirection, + map_scanline_iterator(const map_tile_iterator& itrNodes, + map_scanline_iterator_direction eDirection, int iXOffset = 0, int iYOffset = 0); - inline operator bool () const {return m_pNode != m_pNodeEnd;} - inline THMapScanlineIterator& operator ++ (); + inline operator bool () const {return tile != end_tile;} + inline map_scanline_iterator& operator ++ (); - inline const THMapNode* operator -> () const {return m_pNode;} - inline int x() const {return m_iXs;} - inline int y() const {return m_iYs;} - inline const THMapNode* getNextNode() {return m_pNode + m_iNodeStep;} - inline const THMapNode* getPreviousNode() { return m_pNode - m_iNodeStep;} - THMapScanlineIterator operator= (const THMapScanlineIterator &iterator); - inline const THMapNode* getNode() {return m_pNode;} - -protected: - const THMapNode* m_pNode; - const THMapNode* m_pNodeFirst; - const THMapNode* m_pNodeEnd; - int m_iNodeStep; - int m_iXStep; - int m_iXs; - int m_iYs; - int m_takenSteps; + inline const map_tile* operator -> () const {return tile;} + inline int x() const {return x_relative_to_screen;} + inline int y() const {return y_relative_to_screen;} + inline const map_tile* get_next_tile() {return tile + tile_step;} + inline const map_tile* get_previous_tile() { return tile - tile_step;} + map_scanline_iterator operator= (const map_scanline_iterator &iterator); + inline const map_tile* get_tile() {return tile;} + +private: + const map_tile* tile; + const map_tile* first_tile; + const map_tile* end_tile; + int tile_step; + int x_step; + int x_relative_to_screen; + int y_relative_to_screen; + int steps_taken; }; #endif // CORSIX_TH_TH_MAP_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/th_map_overlays.cpp corsix-th-0.62/CorsixTH/Src/th_map_overlays.cpp --- corsix-th-0.30/CorsixTH/Src/th_map_overlays.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_map_overlays.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -23,149 +23,159 @@ #include "th_map_overlays.h" #include "th_gfx.h" #include "th_map.h" +#include -THMapOverlay::~THMapOverlay() +map_overlay_pair::map_overlay_pair() { + first = nullptr; + second = nullptr; + owns_first = false; + owns_second = false; } -THMapOverlayPair::THMapOverlayPair() +map_overlay_pair::~map_overlay_pair() { - m_pFirst = NULL; - m_pSecond = NULL; - m_bOwnFirst = false; - m_bOwnSecond = false; + set_first(nullptr, false); + set_second(nullptr, false); } -THMapOverlayPair::~THMapOverlayPair() +void map_overlay_pair::set_first(map_overlay* pOverlay, bool bTakeOwnership) { - setFirst(NULL, false); - setSecond(NULL, false); + if(first && owns_first) + delete first; + first = pOverlay; + owns_first = bTakeOwnership; } -void THMapOverlayPair::setFirst(THMapOverlay* pOverlay, bool bTakeOwnership) +void map_overlay_pair::set_second(map_overlay* pOverlay, bool bTakeOwnership) { - if(m_pFirst && m_bOwnFirst) - delete m_pFirst; - m_pFirst = pOverlay; - m_bOwnFirst = bTakeOwnership; + if(second && owns_second) + delete second; + second = pOverlay; + owns_second = bTakeOwnership; } -void THMapOverlayPair::setSecond(THMapOverlay* pOverlay, bool bTakeOwnership) -{ - if(m_pSecond && m_bOwnSecond) - delete m_pSecond; - m_pSecond = pOverlay; - m_bOwnSecond = bTakeOwnership; -} - -void THMapOverlayPair::drawCell(THRenderTarget* pCanvas, int iCanvasX, - int iCanvasY, const THMap* pMap, int iNodeX, +void map_overlay_pair::draw_cell(render_target* pCanvas, int iCanvasX, + int iCanvasY, const level_map* pMap, int iNodeX, int iNodeY) { - if(m_pFirst) - m_pFirst->drawCell(pCanvas, iCanvasX, iCanvasY, pMap, iNodeX, iNodeY); - if(m_pSecond) - m_pSecond->drawCell(pCanvas, iCanvasX, iCanvasY, pMap, iNodeX, iNodeY); + if(first) + first->draw_cell(pCanvas, iCanvasX, iCanvasY, pMap, iNodeX, iNodeY); + if(second) + second->draw_cell(pCanvas, iCanvasX, iCanvasY, pMap, iNodeX, iNodeY); } -THMapTextOverlay::THMapTextOverlay() +map_text_overlay::map_text_overlay() { - m_iBackgroundSprite = 0; + background_sprite = 0; } -void THMapTextOverlay::setBackgroundSprite(unsigned int iSprite) +void map_text_overlay::set_background_sprite(size_t iSprite) { - m_iBackgroundSprite = iSprite; + background_sprite = iSprite; } -void THMapTextOverlay::drawCell(THRenderTarget* pCanvas, int iCanvasX, - int iCanvasY, const THMap* pMap, int iNodeX, +void map_text_overlay::draw_cell(render_target* pCanvas, int iCanvasX, + int iCanvasY, const level_map* pMap, int iNodeX, int iNodeY) { - if(m_pSprites && m_iBackgroundSprite) + if(sprites && background_sprite) { - m_pSprites->drawSprite(pCanvas, m_iBackgroundSprite, iCanvasX, + sprites->draw_sprite(pCanvas, background_sprite, iCanvasX, iCanvasY, 0); } - if(m_pFont) + if(font) { - _drawText(pCanvas, iCanvasX, iCanvasY, "%s", - getText(pMap, iNodeX, iNodeY)); + draw_text(pCanvas, iCanvasX, iCanvasY, get_text(pMap, iNodeX, iNodeY)); } } -const char* THMapPositionsOverlay::getText(const THMap* pMap, int iNodeX, int iNodeY) +const std::string map_positions_overlay::get_text(const level_map* pMap, int iNodeX, int iNodeY) { - sprintf(m_sBuffer, "%i,%i", iNodeX + 1, iNodeY + 1); - return m_sBuffer; + std::ostringstream str; + str << iNodeX + 1 << ',' << iNodeY + 1; + return str.str(); } -THMapTypicalOverlay::THMapTypicalOverlay() +map_typical_overlay::map_typical_overlay() { - m_pSprites = NULL; - m_pFont = NULL; - m_bOwnsSprites = false; - m_bOwnsFont = false; + sprites = nullptr; + font = nullptr; + owns_sprites = false; + owns_font = false; } -THMapTypicalOverlay::~THMapTypicalOverlay() +map_typical_overlay::~map_typical_overlay() { - setSprites(NULL, false); - setFont(NULL, false); + set_sprites(nullptr, false); + set_font(nullptr, false); } -void THMapFlagsOverlay::drawCell(THRenderTarget* pCanvas, int iCanvasX, - int iCanvasY, const THMap* pMap, int iNodeX, +void map_flags_overlay::draw_cell(render_target* pCanvas, int iCanvasX, + int iCanvasY, const level_map* pMap, int iNodeX, int iNodeY) { - const THMapNode *pNode = pMap->getNode(iNodeX, iNodeY); + const map_tile *pNode = pMap->get_tile(iNodeX, iNodeY); if(!pNode) return; - if(m_pSprites) + if(sprites) { - if(pNode->iFlags & THMN_Passable) - m_pSprites->drawSprite(pCanvas, 3, iCanvasX, iCanvasY, 0); - if(pNode->iFlags & THMN_Hospital) - m_pSprites->drawSprite(pCanvas, 8, iCanvasX, iCanvasY, 0); - if(pNode->iFlags & THMN_Buildable) - m_pSprites->drawSprite(pCanvas, 9, iCanvasX, iCanvasY, 0); -#define TRAVEL(flag, dx, dy, sprite) \ - if(pNode->iFlags & flag && pMap->getNode(iNodeX + dx, iNodeY + dy)-> \ - iFlags & THMN_Passable) \ - { \ - m_pSprites->drawSprite(pCanvas, sprite, iCanvasX, iCanvasY, 0); \ - } - TRAVEL(THMN_CanTravelN, 0, -1, 4); - TRAVEL(THMN_CanTravelE, 1, 0, 5); - TRAVEL(THMN_CanTravelS, 0, 1, 6); - TRAVEL(THMN_CanTravelW, -1, 0, 7); -#undef TRAVEL + if(pNode->flags.passable) + sprites->draw_sprite(pCanvas, 3, iCanvasX, iCanvasY, 0); + if(pNode->flags.hospital) + sprites->draw_sprite(pCanvas, 8, iCanvasX, iCanvasY, 0); + if(pNode->flags.buildable) + sprites->draw_sprite(pCanvas, 9, iCanvasX, iCanvasY, 0); + if(pNode->flags.can_travel_n && pMap->get_tile(iNodeX, iNodeY - 1)->flags.passable) + { + sprites->draw_sprite(pCanvas, 4, iCanvasX, iCanvasY, 0); + } + if(pNode->flags.can_travel_e && pMap->get_tile(iNodeX + 1, iNodeY)->flags.passable) + { + sprites->draw_sprite(pCanvas, 5, iCanvasX, iCanvasY, 0); + } + if(pNode->flags.can_travel_s && pMap->get_tile(iNodeX, iNodeY + 1)->flags.passable) + { + sprites->draw_sprite(pCanvas, 6, iCanvasX, iCanvasY, 0); + } + if(pNode->flags.can_travel_w && pMap->get_tile(iNodeX - 1, iNodeY)->flags.passable) + { + sprites->draw_sprite(pCanvas, 7, iCanvasX, iCanvasY, 0); + } } - if(m_pFont) + if(font) { - if(pNode->iFlags >> 24) - _drawText(pCanvas, iCanvasX, iCanvasY - 8, "T%i", (int)(pNode->iFlags >> 24)); + if(!pNode->objects.empty()) + { + std::ostringstream str; + str << 'T' << static_cast(pNode->objects.front()); + draw_text(pCanvas, iCanvasX, iCanvasY - 8, str.str()); + } if(pNode->iRoomId) - _drawText(pCanvas, iCanvasX, iCanvasY + 8, "R%i", (int)pNode->iRoomId); + { + std::ostringstream str; + str << 'R' << static_cast(pNode->iRoomId); + draw_text(pCanvas, iCanvasX, iCanvasY + 8, str.str()); + } } } -void THMapParcelsOverlay::drawCell(THRenderTarget* pCanvas, int iCanvasX, - int iCanvasY, const THMap* pMap, int iNodeX, +void map_parcels_overlay::draw_cell(render_target* pCanvas, int iCanvasX, + int iCanvasY, const level_map* pMap, int iNodeX, int iNodeY) { - const THMapNode *pNode = pMap->getNode(iNodeX, iNodeY); + const map_tile *pNode = pMap->get_tile(iNodeX, iNodeY); if(!pNode) return; - if(m_pFont) - _drawText(pCanvas, iCanvasX, iCanvasY, "%i", (int)pNode->iParcelId); - if(m_pSprites) + if(font) + draw_text(pCanvas, iCanvasX, iCanvasY, std::to_string((int)pNode->iParcelId)); + if(sprites) { uint16_t iParcel = pNode->iParcelId; #define DIR(dx, dy, sprite) \ - pNode = pMap->getNode(iNodeX + dx, iNodeY + dy); \ + pNode = pMap->get_tile(iNodeX + dx, iNodeY + dy); \ if(!pNode || pNode->iParcelId != iParcel) \ - m_pSprites->drawSprite(pCanvas, sprite, iCanvasX, iCanvasY, 0) + sprites->draw_sprite(pCanvas, sprite, iCanvasX, iCanvasY, 0) DIR( 0, -1, 18); DIR( 1, 0, 19); DIR( 0, 1, 20); @@ -175,32 +185,26 @@ } -void THMapTypicalOverlay::_drawText(THRenderTarget* pCanvas, int iX, int iY, - const char* sFormat, ...) +void map_typical_overlay::draw_text(render_target* pCanvas, int iX, int iY, + std::string str) +{ + text_layout oArea = font->get_text_dimensions(str.c_str(), str.length()); + font->draw_text(pCanvas, str.c_str(), str.length(), iX + (64 - oArea.end_x) / 2, + iY + (32 - oArea.end_y) / 2); +} + +void map_typical_overlay::set_sprites(sprite_sheet* pSheet, bool bTakeOwnership) +{ + if(sprites && owns_sprites) + delete sprites; + sprites = pSheet; + owns_sprites = bTakeOwnership; +} + +void map_typical_overlay::set_font(::font* font, bool take_ownership) { - char sBuffer[64]; - va_list args; - va_start(args, sFormat); - size_t iLen = (int)vsprintf(sBuffer, sFormat, args); - va_end(args); - int iW, iH; - m_pFont->getTextSize(sBuffer, iLen, &iW, &iH); - m_pFont->drawText(pCanvas, sBuffer, iLen, iX + (64 - iW) / 2, - iY + (32 - iH) / 2); -} - -void THMapTypicalOverlay::setSprites(THSpriteSheet* pSheet, bool bTakeOwnership) -{ - if(m_pSprites && m_bOwnsSprites) - delete m_pSprites; - m_pSprites = pSheet; - m_bOwnsSprites = bTakeOwnership; -} - -void THMapTypicalOverlay::setFont(THFont* pFont, bool bTakeOwnership) -{ - if(m_pFont && m_bOwnsFont) - delete m_pFont; - m_pFont = pFont; - m_bOwnsFont = bTakeOwnership; + if(this->font && owns_font) + delete this->font; + this->font = font; + owns_font = take_ownership; } diff -Nru corsix-th-0.30/CorsixTH/Src/th_map_overlays.h corsix-th-0.62/CorsixTH/Src/th_map_overlays.h --- corsix-th-0.30/CorsixTH/Src/th_map_overlays.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_map_overlays.h 2018-07-21 11:13:17.000000000 +0000 @@ -23,92 +23,94 @@ #ifndef CORSIX_TH_TH_MAP_OVERLAYS_H_ #define CORSIX_TH_TH_MAP_OVERLAYS_H_ -class THFont; -class THMap; -class THRenderTarget; -class THSpriteSheet; +#include +#include -class THMapOverlay +class font; +class level_map; +class render_target; +class sprite_sheet; + +class map_overlay { public: - virtual ~THMapOverlay(); + virtual ~map_overlay() = default; - virtual void drawCell(THRenderTarget* pCanvas, int iCanvasX, int iCanvasY, - const THMap* pMap, int iNodeX, int iNodeY) = 0; + virtual void draw_cell(render_target* pCanvas, int iCanvasX, int iCanvasY, + const level_map* pMap, int iNodeX, int iNodeY) = 0; }; -class THMapOverlayPair : public THMapOverlay +class map_overlay_pair : public map_overlay { public: - THMapOverlayPair(); - virtual ~THMapOverlayPair(); + map_overlay_pair(); + virtual ~map_overlay_pair(); - void setFirst(THMapOverlay* pOverlay, bool bTakeOwnership); - void setSecond(THMapOverlay* pOverlay, bool bTakeOwnership); + void set_first(map_overlay* pOverlay, bool bTakeOwnership); + void set_second(map_overlay* pOverlay, bool bTakeOwnership); - virtual void drawCell(THRenderTarget* pCanvas, int iCanvasX, int iCanvasY, - const THMap* pMap, int iNodeX, int iNodeY); + void draw_cell(render_target* pCanvas, int iCanvasX, int iCanvasY, + const level_map* pMap, int iNodeX, int iNodeY) override; -protected: - THMapOverlay *m_pFirst, *m_pSecond; - bool m_bOwnFirst, m_bOwnSecond; +private: + map_overlay *first, *second; + bool owns_first, owns_second; }; -class THMapTypicalOverlay : public THMapOverlay +class map_typical_overlay : public map_overlay { public: - THMapTypicalOverlay(); - virtual ~THMapTypicalOverlay(); + map_typical_overlay(); + virtual ~map_typical_overlay(); - void setSprites(THSpriteSheet* pSheet, bool bTakeOwnership); - void setFont(THFont* pFont, bool bTakeOwnership); + void set_sprites(sprite_sheet* pSheet, bool bTakeOwnership); + void set_font(::font* font, bool take_ownership); protected: - void _drawText(THRenderTarget* pCanvas, int iX, int iY, - const char* sFormat, ...); + void draw_text(render_target* pCanvas, int iX, int iY, std::string str); + + sprite_sheet* sprites; + ::font* font; - THSpriteSheet* m_pSprites; - THFont* m_pFont; - bool m_bOwnsSprites; - bool m_bOwnsFont; +private: + bool owns_sprites; + bool owns_font; }; -class THMapTextOverlay : public THMapTypicalOverlay +class map_text_overlay : public map_typical_overlay { public: - THMapTextOverlay(); + map_text_overlay(); + virtual ~map_text_overlay() = default; - virtual void drawCell(THRenderTarget* pCanvas, int iCanvasX, int iCanvasY, - const THMap* pMap, int iNodeX, int iNodeY); + virtual void draw_cell(render_target* pCanvas, int iCanvasX, int iCanvasY, + const level_map* pMap, int iNodeX, int iNodeY); - void setBackgroundSprite(unsigned int iSprite); - virtual const char* getText(const THMap* pMap, int iNodeX, int iNodeY) = 0; + void set_background_sprite(size_t iSprite); + virtual const std::string get_text(const level_map* pMap, int iNodeX, int iNodeY) = 0; -protected: - unsigned int m_iBackgroundSprite; +private: + size_t background_sprite; }; -class THMapPositionsOverlay : public THMapTextOverlay +class map_positions_overlay final : public map_text_overlay { public: - virtual const char* getText(const THMap* pMap, int iNodeX, int iNodeY); - -protected: - char m_sBuffer[16]; + const std::string get_text(const level_map* pMap, int iNodeX, int iNodeY) override; }; -class THMapFlagsOverlay : public THMapTypicalOverlay +class map_flags_overlay final : public map_typical_overlay { public: - virtual void drawCell(THRenderTarget* pCanvas, int iCanvasX, int iCanvasY, - const THMap* pMap, int iNodeX, int iNodeY); + void draw_cell(render_target* pCanvas, int iCanvasX, int iCanvasY, + const level_map* pMap, int iNodeX, int iNodeY) override; }; -class THMapParcelsOverlay : public THMapTypicalOverlay +class map_parcels_overlay final : public map_typical_overlay { public: - virtual void drawCell(THRenderTarget* pCanvas, int iCanvasX, int iCanvasY, - const THMap* pMap, int iNodeX, int iNodeY); + void draw_cell(render_target* pCanvas, int iCanvasX, int iCanvasY, + const level_map* pMap, int iNodeX, int iNodeY) override; }; #endif diff -Nru corsix-th-0.30/CorsixTH/Src/th_movie.cpp corsix-th-0.62/CorsixTH/Src/th_movie.cpp --- corsix-th-0.30/CorsixTH/Src/th_movie.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_movie.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -23,7 +23,7 @@ #include "th_movie.h" #include "config.h" #include "lua_sdl.h" -#ifdef CORSIX_TH_USE_FFMPEG +#if (defined(CORSIX_TH_USE_FFMPEG) || defined(CORSIX_TH_USE_LIBAV)) && defined(CORSIX_TH_USE_SDL_MIXER) #include "th_gfx.h" extern "C" @@ -31,771 +31,787 @@ #include #include #include + #include #include +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 6, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 63, 100)) + #include +#endif } #include +#include +#include #include -#define INBUF_SIZE 4096 -#define AUDIO_BUFFER_SIZE 1024 +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 7, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 12, 100)) +#define av_packet_unref av_free_packet +#endif -int th_movie_stream_reader_thread(void* pState) -{ - THMovie *pMovie = (THMovie *)pState; - pMovie->readStreams(); - return 0; -} +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 45, 101)) +#define av_frame_alloc avcodec_alloc_frame +#define av_frame_unref avcodec_get_frame_defaults +#define av_frame_free avcodec_free_frame +#endif -int th_movie_video_thread(void* pState) -{ - THMovie *pMovie = (THMovie *)pState; - pMovie->runVideo(); - return 0; +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 52, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 63, 100)) +void avcodec_free_context(AVCodecContext** ctx) { + avcodec_close(*ctx); + av_free(*ctx); } +#endif -void th_movie_audio_callback(int iChannel, void *pStream, int iStreamSize, void *pUserData) +static void th_movie_audio_callback(int iChannel, void *pStream, int iStreamSize, void *pUserData) { - THMovie *pMovie = (THMovie *)pUserData; - pMovie->copyAudioToStream((uint8_t*)pStream, iStreamSize); + movie_player *pMovie = (movie_player *)pUserData; + pMovie->copy_audio_to_stream((uint8_t*)pStream, iStreamSize); } -THMoviePicture::THMoviePicture(): - m_pOverlay(NULL), - m_pixelFormat(PIX_FMT_YUV420P), - m_pSurface(NULL) +movie_picture::movie_picture(): + buffer(nullptr), + pixel_format(AV_PIX_FMT_RGB24), + mutex{} +{} + +movie_picture::~movie_picture() { - m_pMutex = SDL_CreateMutex(); - m_pCond = SDL_CreateCond(); + av_freep(&buffer); } -THMoviePicture::~THMoviePicture() +void movie_picture::allocate(int iWidth, int iHeight) { - if(m_pOverlay && m_pSurface == SDL_GetVideoSurface()) - { - SDL_FreeYUVOverlay(m_pOverlay); - m_pOverlay = NULL; - } - SDL_DestroyMutex(m_pMutex); - SDL_DestroyCond(m_pCond); + width = iWidth; + height = iHeight; + av_freep(&buffer); +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 6, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 63, 100)) + int numBytes = av_image_get_buffer_size(pixel_format, width, height, 1); +#else + int numBytes = avpicture_get_size(pixel_format, width, height); +#endif + buffer = static_cast(av_mallocz(numBytes)); } -void THMoviePicture::allocate(int iX, int iY, int iWidth, int iHeight) +void movie_picture::deallocate() { - m_iX = iX; - m_iY = iY; - m_iWidth = iWidth; - m_iHeight = iHeight; - SDL_Surface* pSurface = SDL_GetVideoSurface(); - if(m_pOverlay) - { - if(m_pSurface == pSurface) - { - SDL_FreeYUVOverlay(m_pOverlay); - } - std::cerr << "THMovie overlay should be deallocated before being allocated!"; - } - m_pSurface = pSurface; - m_pOverlay = SDL_CreateYUVOverlay(m_iWidth, m_iHeight, SDL_YV12_OVERLAY, pSurface); - if(m_pOverlay == NULL || m_pOverlay->pitches[0] < m_iWidth) - { - std::cerr << "Problem creating overlay: " << SDL_GetError() << "\n"; - return; - } + av_freep(&buffer); } -void THMoviePicture::deallocate() +movie_picture_buffer::movie_picture_buffer(): + aborting(false), + allocated(false), + picture_count(0), + read_index(0), + write_index(0), + sws_context(nullptr), + texture(nullptr), + mutex{}, + cond{} { - if(m_pOverlay) - { - if(m_pSurface == SDL_GetVideoSurface()) - { - SDL_FreeYUVOverlay(m_pOverlay); - } - else - { - std::cerr << "THMovie overlay must be deallocated before a surface change"; - } - m_pOverlay = NULL; - } } -void THMoviePicture::draw() +movie_picture_buffer::~movie_picture_buffer() { - SDL_Rect rcDest; - int iError; - - rcDest.x = m_iX; - rcDest.y = m_iY; - rcDest.w = m_iWidth; - rcDest.h = m_iHeight; - if(m_pOverlay && m_pSurface == SDL_GetVideoSurface()) + sws_freeContext(sws_context); + if (texture) { - iError = SDL_DisplayYUVOverlay(m_pOverlay, &rcDest); - if(iError < 0) - { - std::cerr << "Error displaying overlay: " << SDL_GetError(); - } + SDL_DestroyTexture(texture); + texture = nullptr; } } -THMoviePictureBuffer::THMoviePictureBuffer(): - m_fAborting(false), - m_fAllocated(false), - m_iCount(0), - m_iReadIndex(0), - m_iWriteIndex(0), - m_pSwsContext(NULL) +void movie_picture_buffer::abort() { - m_pMutex = SDL_CreateMutex(); - m_pCond = SDL_CreateCond(); + aborting = true; + std::lock_guard lock(mutex); + cond.notify_all(); } -THMoviePictureBuffer::~THMoviePictureBuffer() +void movie_picture_buffer::reset() { - SDL_DestroyCond(m_pCond); - SDL_DestroyMutex(m_pMutex); - sws_freeContext(m_pSwsContext); + aborting = false; } -void THMoviePictureBuffer::abort() +void movie_picture_buffer::allocate(SDL_Renderer *pRenderer, int iWidth, int iHeight) { - m_fAborting = true; - SDL_LockMutex(m_pMutex); - SDL_CondSignal(m_pCond); - SDL_UnlockMutex(m_pMutex); -} + if (texture) + { + SDL_DestroyTexture(texture); + std::cerr << "movie_player overlay should be deallocated before being allocated!\n"; + } + texture = SDL_CreateTexture(pRenderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, iWidth, iHeight); + if (texture == nullptr) + { + std::cerr << "Problem creating overlay: " << SDL_GetError() << "\n"; + return; + } + for(int i = 0; i < picture_buffer_size; i++) + { + picture_queue[i].allocate(iWidth, iHeight); + } + // Do not change write_index, it's used by the other thread. + // read_index is only used in this thread. + read_index = write_index; -void THMoviePictureBuffer::reset() -{ - m_fAborting = false; + std::lock_guard lock(mutex); + picture_count = 0; + allocated = true; + cond.notify_one(); } -void THMoviePictureBuffer::allocate(int iX, int iY, int iWidth, int iHeight) +void movie_picture_buffer::deallocate() { - for(int i=0; i lock(mutex); + allocated = false; } - //Do not change m_iWriteIndex, it's used by the other thread. - //m_iReadIndex is only used in this thread. - m_iReadIndex = m_iWriteIndex; - SDL_LockMutex(m_pMutex); - m_iCount = 0; - m_fAllocated = true; - SDL_CondSignal(m_pCond); - SDL_UnlockMutex(m_pMutex); -} -void THMoviePictureBuffer::deallocate() -{ - SDL_LockMutex(m_pMutex); - m_fAllocated = false; - SDL_UnlockMutex(m_pMutex); - for(int i=0; i pictureLock(picture_queue[i].mutex); + picture_queue[i].deallocate(); + } + + if (texture) { - SDL_LockMutex(m_aPictureQueue[i].m_pMutex); - m_aPictureQueue[i].deallocate(); - SDL_UnlockMutex(m_aPictureQueue[i].m_pMutex); + SDL_DestroyTexture(texture); + texture = nullptr; } } -bool THMoviePictureBuffer::advance() +bool movie_picture_buffer::advance() { if(empty()) { return false; } - m_iReadIndex++; - if(m_iReadIndex == PICTURE_BUFFER_SIZE) + read_index++; + if(read_index == picture_buffer_size) { - m_iReadIndex = 0; + read_index = 0; } - SDL_LockMutex(m_pMutex); - m_iCount--; - SDL_CondSignal(m_pCond); - SDL_UnlockMutex(m_pMutex); + + std::lock_guard lock(mutex); + picture_count--; + cond.notify_one(); return true; } -void THMoviePictureBuffer::draw() +void movie_picture_buffer::draw(SDL_Renderer *pRenderer, const SDL_Rect &dstrect) { if(!empty()) { - SDL_LockMutex(m_aPictureQueue[m_iReadIndex].m_pMutex); - m_aPictureQueue[m_iReadIndex].draw(); - SDL_UnlockMutex(m_aPictureQueue[m_iReadIndex].m_pMutex); - } -} + auto cur_pic = &(picture_queue[read_index]); -double THMoviePictureBuffer::getCurrentPts() -{ - if(empty()) { return 0; } - return m_aPictureQueue[m_iReadIndex].m_dPts; + std::lock_guard pictureLock(cur_pic->mutex); + if (cur_pic->buffer) + { + SDL_UpdateTexture(texture, nullptr, cur_pic->buffer, cur_pic->width * 3); + int iError = SDL_RenderCopy(pRenderer, texture, nullptr, &dstrect); + if (iError < 0) + { + std::cerr << "Error displaying movie frame: " << SDL_GetError() << "\n"; + } + } + } } -double THMoviePictureBuffer::getNextPts() +double movie_picture_buffer::get_next_pts() { double nextPts; - SDL_LockMutex(m_pMutex); - if(!m_fAllocated || m_iCount < 2) + std::lock_guard lock(mutex); + if(!allocated || picture_count < 2) { nextPts = 0; } else { - nextPts = m_aPictureQueue[(m_iReadIndex+1)%PICTURE_BUFFER_SIZE].m_dPts; + nextPts = picture_queue[(read_index + 1) % picture_buffer_size].pts; } - SDL_UnlockMutex(m_pMutex); return nextPts; } -bool THMoviePictureBuffer::empty() +bool movie_picture_buffer::empty() { - bool empty; - SDL_LockMutex(m_pMutex); - empty = (!m_fAllocated || m_iCount == 0); - SDL_UnlockMutex(m_pMutex); - return empty; + std::lock_guard lock(mutex); + return (!allocated || picture_count == 0); } -bool THMoviePictureBuffer::full() +bool movie_picture_buffer::full() { - bool full; - SDL_LockMutex(m_pMutex); - full = (!m_fAllocated || m_iCount == PICTURE_BUFFER_SIZE); - SDL_UnlockMutex(m_pMutex); - return full; + std::lock_guard lock(mutex); + return unsafe_full(); } -int THMoviePictureBuffer::write(AVFrame* pFrame, double dPts) +bool movie_picture_buffer::unsafe_full() { - THMoviePicture* pMoviePicture = NULL; - SDL_LockMutex(m_pMutex); - while(full() && !m_fAborting) - { - SDL_CondWait(m_pCond, m_pMutex); - } - SDL_UnlockMutex(m_pMutex); - if(m_fAborting) { return -1; } - - pMoviePicture = &m_aPictureQueue[m_iWriteIndex]; - SDL_LockMutex(pMoviePicture->m_pMutex); + return (!allocated || picture_count == picture_buffer_size); +} - if(pMoviePicture->m_pOverlay) +int movie_picture_buffer::write(AVFrame* pFrame, double dPts) +{ + movie_picture* pMoviePicture = nullptr; + std::unique_lock picBufLock(mutex); + while(unsafe_full() && !aborting) { - AVPicture picture = {}; + cond.wait(picBufLock); + } + picBufLock.unlock(); - SDL_LockYUVOverlay(pMoviePicture->m_pOverlay); - picture.data[0] = pMoviePicture->m_pOverlay->pixels[0]; - picture.data[1] = pMoviePicture->m_pOverlay->pixels[2]; - picture.data[2] = pMoviePicture->m_pOverlay->pixels[1]; + if(aborting) { return -1; } - picture.linesize[0] = pMoviePicture->m_pOverlay->pitches[0]; - picture.linesize[1] = pMoviePicture->m_pOverlay->pitches[2]; - picture.linesize[2] = pMoviePicture->m_pOverlay->pitches[1]; + pMoviePicture = &picture_queue[write_index]; + std::unique_lock pictureLock(pMoviePicture->mutex); - m_pSwsContext = sws_getCachedContext(m_pSwsContext, pFrame->width, pFrame->height, (PixelFormat)pFrame->format, pMoviePicture->m_iWidth, pMoviePicture->m_iHeight, pMoviePicture->m_pixelFormat, SWS_BICUBIC, NULL, NULL, NULL); - if(m_pSwsContext == NULL) + if(pMoviePicture->buffer) + { + sws_context = sws_getCachedContext(sws_context, pFrame->width, pFrame->height, (AVPixelFormat)pFrame->format, pMoviePicture->width, pMoviePicture->height, pMoviePicture->pixel_format, SWS_BICUBIC, nullptr, nullptr, nullptr); + if(sws_context == nullptr) { - SDL_UnlockMutex(m_aPictureQueue[m_iWriteIndex].m_pMutex); - std::cerr << "Failed to initialize SwsContext"; + std::cerr << "Failed to initialize SwsContext\n"; return 1; } - sws_scale(m_pSwsContext, pFrame->data, pFrame->linesize, 0, pMoviePicture->m_iHeight, picture.data, picture.linesize); - SDL_UnlockYUVOverlay(pMoviePicture->m_pOverlay); + /* Allocate a new frame and buffer for the destination RGB24 data. */ + AVFrame *pFrameRGB = av_frame_alloc(); +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 6, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 63, 100)) + av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, pMoviePicture->buffer, pMoviePicture->pixel_format, pMoviePicture->width, pMoviePicture->height, 1); +#else + avpicture_fill((AVPicture *)pFrameRGB, pMoviePicture->buffer, pMoviePicture->pixel_format, pMoviePicture->width, pMoviePicture->height); +#endif + + /* Rescale the frame data and convert it to RGB24. */ + sws_scale(sws_context, pFrame->data, pFrame->linesize, 0, pFrame->height, pFrameRGB->data, pFrameRGB->linesize); - pMoviePicture->m_dPts = dPts; + av_frame_free(&pFrameRGB); - SDL_UnlockMutex(m_aPictureQueue[m_iWriteIndex].m_pMutex); - m_iWriteIndex++; - if(m_iWriteIndex == PICTURE_BUFFER_SIZE) + pMoviePicture->pts = dPts; + + pictureLock.unlock(); + write_index++; + if(write_index == picture_buffer_size) { - m_iWriteIndex = 0; + write_index = 0; } - SDL_LockMutex(m_pMutex); - m_iCount++; - SDL_UnlockMutex(m_pMutex); + picBufLock.lock(); + picture_count++; + picBufLock.unlock(); } + return 0; } -THAVPacketQueue::THAVPacketQueue(): - iCount(0), - m_pFirstPacket(NULL), - m_pLastPacket(NULL) +av_packet_queue::av_packet_queue(): + first_packet(nullptr), + last_packet(nullptr), + count(0), + mutex{}, + cond{} { - m_pMutex = SDL_CreateMutex(); - m_pCond = SDL_CreateCond(); } -THAVPacketQueue::~THAVPacketQueue() +av_packet_queue::~av_packet_queue() { - SDL_DestroyCond(m_pCond); - SDL_DestroyMutex(m_pMutex); } -int THAVPacketQueue::getCount() +int av_packet_queue::get_count() const { - return iCount; + return count; } -void THAVPacketQueue::push(AVPacket *pPacket) +void av_packet_queue::push(AVPacket *pPacket) { - AVPacketList* pNode; +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 8, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 12, 100)) if(av_dup_packet(pPacket) < 0) { throw -1; } +#endif - pNode = (AVPacketList*)av_malloc(sizeof(AVPacketList)); + AVPacketList* pNode = (AVPacketList*)av_malloc(sizeof(AVPacketList)); pNode->pkt = *pPacket; - pNode->next = NULL; + pNode->next = nullptr; - SDL_LockMutex(m_pMutex); + std::lock_guard lock(mutex); - if(m_pLastPacket == NULL) + if(last_packet == nullptr) { - m_pFirstPacket = pNode; + first_packet = pNode; } else { - m_pLastPacket->next = pNode; + last_packet->next = pNode; } - m_pLastPacket = pNode; - iCount++; + last_packet = pNode; + count++; - SDL_CondSignal(m_pCond); - SDL_UnlockMutex(m_pMutex); + cond.notify_one(); } -AVPacket* THAVPacketQueue::pull(bool fBlock) +AVPacket* av_packet_queue::pull(bool fBlock) { - AVPacketList *pNode; - AVPacket *pPacket; - - SDL_LockMutex(m_pMutex); + std::unique_lock lock(mutex); - pNode = m_pFirstPacket; - if(pNode == NULL && fBlock) + AVPacketList* pNode = first_packet; + if(pNode == nullptr && fBlock) { - SDL_CondWait(m_pCond, m_pMutex); - pNode = m_pFirstPacket; + cond.wait(lock); + pNode = first_packet; } - if(pNode == NULL) + AVPacket *pPacket; + if(pNode == nullptr) { - pPacket = NULL; + pPacket = nullptr; } else { - m_pFirstPacket = pNode->next; - if(m_pFirstPacket == NULL) { m_pLastPacket = NULL; } - iCount--; - + first_packet = pNode->next; + if(first_packet == nullptr) { last_packet = nullptr; } + count--; pPacket = (AVPacket*)av_malloc(sizeof(AVPacket)); *pPacket = pNode->pkt; av_free(pNode); } - SDL_UnlockMutex(m_pMutex); - return pPacket; } -void THAVPacketQueue::release() +void av_packet_queue::release() { - SDL_LockMutex(m_pMutex); - SDL_CondSignal(m_pCond); - SDL_UnlockMutex(m_pMutex); -} - -THMovie::THMovie(): - m_sLastError(), - m_pFormatContext(NULL), - m_pVideoCodecContext(NULL), - m_pAudioCodecContext(NULL), - m_pVideoQueue(NULL), - m_pAudioQueue(NULL), - m_pMoviePictureBuffer(new THMoviePictureBuffer()), - m_pSwrContext(NULL), - m_iAudioBufferSize(0), - m_iAudioBufferMaxSize(0), - m_frame(NULL), - m_pChunk(NULL), - m_iChannel(-1), - m_pStreamThread(NULL), - m_pVideoThread(NULL), - m_pAudioPacket(NULL) + std::lock_guard lock(mutex); + cond.notify_all(); +} + +movie_player::movie_player(): + renderer(nullptr), + last_error(), + format_context(nullptr), + video_codec_context(nullptr), + audio_codec_context(nullptr), + video_queue(nullptr), + audio_queue(nullptr), + movie_picture_buffer(new ::movie_picture_buffer()), + audio_resample_context(nullptr), + audio_buffer_size(0), + audio_buffer_max_size(0), + audio_packet(nullptr), + audio_frame(nullptr), + empty_audio_chunk(nullptr), + audio_channel(-1), + stream_thread{}, + video_thread{}, + decoding_audio_mutex{} { +#if defined(CORSIX_TH_USE_LIBAV) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)) av_register_all(); +#endif - m_flushPacket = (AVPacket*)av_malloc(sizeof(AVPacket)); - av_init_packet(m_flushPacket); - m_flushPacket->data = (uint8_t *)"FLUSH"; - m_flushPacket->size = 5; + flush_packet = (AVPacket*)av_malloc(sizeof(AVPacket)); + av_init_packet(flush_packet); + flush_packet->data = (uint8_t *)"FLUSH"; + flush_packet->size = 5; - m_pbChunkBuffer = (uint8_t*)malloc(AUDIO_BUFFER_SIZE); - memset(m_pbChunkBuffer, 0, AUDIO_BUFFER_SIZE); + audio_chunk_buffer = (uint8_t*)std::calloc(audio_chunk_buffer_capacity, sizeof(uint8_t)); } -THMovie::~THMovie() +movie_player::~movie_player() { unload(); - av_free_packet(m_flushPacket); - av_free(m_flushPacket); - free(m_pbChunkBuffer); + av_packet_unref(flush_packet); + av_free(flush_packet); + free(audio_chunk_buffer); + delete movie_picture_buffer; +} + +void movie_player::set_renderer(SDL_Renderer *pRenderer) +{ + renderer = pRenderer; } -bool THMovie::moviesEnabled() +bool movie_player::movies_enabled() const { return true; } -bool THMovie::load(const char* szFilepath) +bool movie_player::load(const char* szFilepath) { int iError = 0; AVCodec* m_pVideoCodec; AVCodec* m_pAudioCodec; unload(); //Unload any currently loaded video to free memory - m_fAborting = false; + aborting = false; - iError = avformat_open_input(&m_pFormatContext, szFilepath, NULL, NULL); + iError = avformat_open_input(&format_context, szFilepath, nullptr, nullptr); if(iError < 0) { - av_strerror(iError, m_szErrorBuffer, MOVIE_ERROR_BUFFER_SIZE); - m_sLastError = std::string(m_szErrorBuffer); + av_strerror(iError, error_buffer, movie_error_buffer_capacity); + last_error = std::string(error_buffer); return false; } - iError = avformat_find_stream_info(m_pFormatContext, NULL); + iError = avformat_find_stream_info(format_context, nullptr); if(iError < 0) { - av_strerror(iError, m_szErrorBuffer, MOVIE_ERROR_BUFFER_SIZE); - m_sLastError = std::string(m_szErrorBuffer); + av_strerror(iError, error_buffer, movie_error_buffer_capacity); + last_error = std::string(error_buffer); return false; } - m_iVideoStream = av_find_best_stream(m_pFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &m_pVideoCodec, 0); - m_pVideoCodecContext = m_pFormatContext->streams[m_iVideoStream]->codec; - avcodec_open2(m_pVideoCodecContext, m_pVideoCodec, NULL); + video_stream_index = av_find_best_stream(format_context, AVMEDIA_TYPE_VIDEO, -1, -1, &m_pVideoCodec, 0); + video_codec_context = get_codec_context_for_stream(m_pVideoCodec, format_context->streams[video_stream_index]); + avcodec_open2(video_codec_context, m_pVideoCodec, nullptr); - m_iAudioStream = av_find_best_stream(m_pFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, &m_pAudioCodec, 0); - if(m_iAudioStream >= 0) + audio_stream_index = av_find_best_stream(format_context, AVMEDIA_TYPE_AUDIO, -1, -1, &m_pAudioCodec, 0); + if(audio_stream_index >= 0) { - m_pAudioCodecContext = m_pFormatContext->streams[m_iAudioStream]->codec; - avcodec_open2(m_pAudioCodecContext, m_pAudioCodec, NULL); + audio_codec_context = get_codec_context_for_stream(m_pAudioCodec, format_context->streams[audio_stream_index]); + avcodec_open2(audio_codec_context, m_pAudioCodec, nullptr); } return true; } -void THMovie::unload() +AVCodecContext* movie_player::get_codec_context_for_stream(AVCodec* codec, AVStream* stream) const +{ +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 14, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 33, 100)) + AVCodecContext* ctx = avcodec_alloc_context3(codec); + avcodec_parameters_to_context(ctx, stream->codecpar); + return ctx; +#else + return stream->codec; +#endif +} + +void movie_player::unload() { - m_fAborting = true; + aborting = true; - if(m_pAudioQueue) + if(audio_queue) { - m_pAudioQueue->release(); + audio_queue->release(); } - if(m_pVideoQueue) + if(video_queue) { - m_pVideoQueue->release(); + video_queue->release(); } - m_pMoviePictureBuffer->abort(); + movie_picture_buffer->abort(); - if(m_pStreamThread) + if(stream_thread.joinable()) { - SDL_WaitThread(m_pStreamThread, NULL); - m_pStreamThread = NULL; + stream_thread.join(); } - if(m_pVideoThread) + if(video_thread.joinable()) { - SDL_WaitThread(m_pVideoThread, NULL); - m_pVideoThread = NULL; + video_thread.join(); } //wait until after other threads are closed to clear the packet queues //so we don't free something being used. - if(m_pAudioQueue) + if(audio_queue) { - while(m_pAudioQueue->getCount() > 0) + while(audio_queue->get_count() > 0) { - AVPacket* p = m_pAudioQueue->pull(false); - av_free_packet(p); + AVPacket* p = audio_queue->pull(false); + av_packet_unref(p); + av_free(p); } - delete m_pAudioQueue; - m_pAudioQueue = NULL; + delete audio_queue; + audio_queue = nullptr; } - if(m_pVideoQueue) + if(video_queue) { - while(m_pVideoQueue->getCount() > 0) + while(video_queue->get_count() > 0) { - AVPacket* p = m_pVideoQueue->pull(false); - av_free_packet(p); + AVPacket* p = video_queue->pull(false); + av_packet_unref(p); + av_free(p); } - delete m_pVideoQueue; - m_pVideoQueue = NULL; + delete video_queue; + video_queue = nullptr; } - m_pMoviePictureBuffer->deallocate(); - - if(m_iChannel >= 0) + movie_picture_buffer->deallocate(); +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 14, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 33, 100)) + if(video_codec_context) { - Mix_UnregisterAllEffects(m_iChannel); - Mix_HaltChannel(m_iChannel); - Mix_FreeChunk(m_pChunk); - m_iChannel = -1; + avcodec_free_context(&video_codec_context); + video_codec_context = nullptr; } +#endif - if(m_iAudioBufferMaxSize > 0) + if(audio_channel >= 0) { - av_free(m_pbAudioBuffer); - m_iAudioBufferMaxSize = 0; + Mix_UnregisterAllEffects(audio_channel); + Mix_HaltChannel(audio_channel); + Mix_FreeChunk(empty_audio_chunk); + audio_channel = -1; } - if(m_pVideoCodecContext) + std::lock_guard audioLock(decoding_audio_mutex); + + if(audio_buffer_max_size > 0) { - avcodec_close(m_pVideoCodecContext); - m_pVideoCodecContext = NULL; + av_free(audio_buffer); + audio_buffer_max_size = 0; } - if(m_pAudioCodecContext) +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 14, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 33, 100)) + if(audio_codec_context) { - avcodec_close(m_pAudioCodecContext); - m_pAudioCodecContext = NULL; + avcodec_free_context(&audio_codec_context); + audio_codec_context = nullptr; } - if(m_pFormatContext) +#endif + av_frame_free(&audio_frame); + +#ifdef CORSIX_TH_USE_FFMPEG + swr_free(&audio_resample_context); +#elif defined(CORSIX_TH_USE_LIBAV) + // avresample_free doesn't skip nullptr on it's own. + if (audio_resample_context != nullptr) { - avformat_close_input(&m_pFormatContext); + avresample_free(&audio_resample_context); + audio_resample_context = nullptr; } +#endif - if(m_frame) + if(audio_packet) { - av_free(m_frame); - m_frame = NULL; + audio_packet->data = audio_packet_data; + audio_packet->size = audio_packet_size; + av_packet_unref(audio_packet); + av_free(audio_packet); + audio_packet = nullptr; + audio_packet_data = nullptr; + audio_packet_size = 0; } - swr_free(&m_pSwrContext); - - if(m_pAudioPacket) + if(format_context) { - m_pAudioPacket->data = m_pbAudioPacketData; - m_pAudioPacket->size = m_iAudioPacketSize; - av_free_packet(m_pAudioPacket); - av_free(m_pAudioPacket); - m_pAudioPacket = NULL; - m_pbAudioPacketData = NULL; - m_iAudioPacketSize = 0; + avformat_close_input(&format_context); } } -void THMovie::play(int iX, int iY, int iWidth, int iHeight, int iChannel) +void movie_player::play(int iChannel) { - m_iX = iX; - m_iY = iY; - m_iWidth = iWidth; - m_iHeight = iHeight; - - #ifdef CORSIX_TH_USE_OGL_RENDERER - SDL_Surface* pSurface = SDL_GetVideoSurface(); - SDL_SetVideoMode(pSurface->w, pSurface->h, 0, pSurface->flags & ~SDL_OPENGL); - #endif - m_frame = NULL; + if(!renderer) + { + last_error = std::string("Cannot play before setting the renderer"); + return; + } - m_pVideoQueue = new THAVPacketQueue(); - m_pMoviePictureBuffer->reset(); - m_pMoviePictureBuffer->allocate(m_iX, m_iY, m_iWidth, m_iHeight); + video_queue = new av_packet_queue(); + movie_picture_buffer->reset(); + movie_picture_buffer->allocate(renderer, video_codec_context->width, video_codec_context->height); - m_pAudioPacket = NULL; - m_iAudioPacketSize = 0; - m_pbAudioPacketData = NULL; + audio_packet = nullptr; + audio_packet_size = 0; + audio_packet_data = nullptr; - m_iAudioBufferSize = 0; - m_iAudioBufferIndex = 0; - m_iAudioBufferMaxSize = 0; + audio_buffer_size = 0; + audio_buffer_index = 0; + audio_buffer_max_size = 0; - m_pAudioQueue = new THAVPacketQueue(); - m_iCurSyncPts = 0; - m_iCurSyncPtsSystemTime = SDL_GetTicks(); + audio_queue = new av_packet_queue(); + current_sync_pts = 0; + current_sync_pts_system_time = SDL_GetTicks(); - if(m_iAudioStream >= 0) + if(audio_stream_index >= 0) { - Mix_QuerySpec(&m_iMixerFrequency, NULL, &m_iMixerChannels); - m_pSwrContext = swr_alloc_set_opts( - m_pSwrContext, - m_iMixerChannels==1?AV_CH_LAYOUT_MONO:AV_CH_LAYOUT_STEREO, + Mix_QuerySpec(&mixer_frequency, nullptr, &mixer_channels); +#ifdef CORSIX_TH_USE_FFMPEG + audio_resample_context = swr_alloc_set_opts( + audio_resample_context, + mixer_channels==1?AV_CH_LAYOUT_MONO:AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, - m_iMixerFrequency, - m_pAudioCodecContext->channel_layout, - m_pAudioCodecContext->sample_fmt, - m_pAudioCodecContext->sample_rate, + mixer_frequency, + audio_codec_context->channel_layout, + audio_codec_context->sample_fmt, + audio_codec_context->sample_rate, 0, - NULL); - swr_init(m_pSwrContext); - - m_pChunk = Mix_QuickLoad_RAW(m_pbChunkBuffer, AUDIO_BUFFER_SIZE); + nullptr); + swr_init(audio_resample_context); +#elif defined(CORSIX_TH_USE_LIBAV) + audio_resample_context = avresample_alloc_context(); + av_opt_set_int(audio_resample_context, "in_channel_layout", audio_codec_context->channel_layout, 0); + av_opt_set_int(audio_resample_context, "out_channel_layout", mixer_channels == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO, 0); + av_opt_set_int(audio_resample_context, "in_sample_rate", audio_codec_context->sample_rate, 0); + av_opt_set_int(audio_resample_context, "out_sample_rate", mixer_frequency, 0); + av_opt_set_int(audio_resample_context, "in_sample_fmt", audio_codec_context->sample_fmt, 0); + av_opt_set_int(audio_resample_context, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + avresample_open(audio_resample_context); +#endif + empty_audio_chunk = Mix_QuickLoad_RAW(audio_chunk_buffer, audio_chunk_buffer_capacity); - m_iChannel = Mix_PlayChannel(iChannel, m_pChunk, -1); - if(m_iChannel < 0) + audio_channel = Mix_PlayChannel(iChannel, empty_audio_chunk, -1); + if(audio_channel < 0) { - m_iChannel = -1; - m_sLastError = std::string(Mix_GetError()); + audio_channel = -1; + last_error = std::string(Mix_GetError()); + Mix_FreeChunk(empty_audio_chunk); } else { - Mix_RegisterEffect(m_iChannel, th_movie_audio_callback, NULL, this); + Mix_RegisterEffect(audio_channel, th_movie_audio_callback, nullptr, this); } } - m_pStreamThread = SDL_CreateThread(th_movie_stream_reader_thread, this); - m_pVideoThread = SDL_CreateThread(th_movie_video_thread, this); + stream_thread = std::thread(&movie_player::read_streams, this); + video_thread = std::thread(&movie_player::run_video, this); } -void THMovie::stop() +void movie_player::stop() { - m_fAborting = true; + aborting = true; } -int THMovie::getNativeHeight() +int movie_player::get_native_height() const { int iHeight = 0; - if(m_pVideoCodecContext) + if(video_codec_context) { - iHeight = m_pVideoCodecContext->height; + iHeight = video_codec_context->height; } return iHeight; } -int THMovie::getNativeWidth() +int movie_player::get_native_width() const { int iWidth = 0; - if(m_pVideoCodecContext) + if(video_codec_context) { - iWidth = m_pVideoCodecContext->width; + iWidth = video_codec_context->width; } return iWidth; } -bool THMovie::hasAudioTrack() +bool movie_player::has_audio_track() const { - return (m_iAudioStream >= 0); + return (audio_stream_index >= 0); } -bool THMovie::requiresVideoReset() +const char* movie_player::get_last_error() const { -#ifdef CORSIX_TH_USE_OGL_RENDERER - return true; -#else - return false; -#endif + return last_error.c_str(); } -const char* THMovie::getLastError() +void movie_player::clear_last_error() { - return m_sLastError.c_str(); + last_error.clear(); } -void THMovie::clearLastError() +void movie_player::refresh(const SDL_Rect &destination_rect) { - m_sLastError.clear(); -} + SDL_Rect dest_rect; -void THMovie::refresh() -{ - if(!m_pMoviePictureBuffer->empty()) - { - double dCurTime = SDL_GetTicks() - m_iCurSyncPtsSystemTime + m_iCurSyncPts * 1000.0; - double dCurPts = m_pMoviePictureBuffer->getCurrentPts(); - double dNextPts = m_pMoviePictureBuffer->getNextPts(); + dest_rect = SDL_Rect{ destination_rect.x, destination_rect.y, destination_rect.w, destination_rect.h }; - //don't play a frame too early - if(dCurPts > 0) - { - if(dCurPts * 1000.0 > dCurTime) - { - return; - } - } + if(!movie_picture_buffer->empty()) + { + double dCurTime = SDL_GetTicks() - current_sync_pts_system_time + current_sync_pts * 1000.0; + double dNextPts = movie_picture_buffer->get_next_pts(); - //if we have another frame and it's time has already passed, drop the current frame - if(dNextPts > 0 && dNextPts * 1000.0 < dCurTime) + if(dNextPts > 0 && dNextPts * 1000.0 <= dCurTime) { - m_pMoviePictureBuffer->advance(); + movie_picture_buffer->advance(); } - m_pMoviePictureBuffer->draw(); - m_pMoviePictureBuffer->advance(); + movie_picture_buffer->draw(renderer, dest_rect); } } -void THMovie::allocatePictureBuffer() +void movie_player::allocate_picture_buffer() { - m_pMoviePictureBuffer->allocate(m_iX, m_iY, m_iWidth, m_iHeight); + if(!video_codec_context) + { + return; + } + movie_picture_buffer->allocate(renderer, get_native_width(), get_native_height()); } -void THMovie::deallocatePictureBuffer() +void movie_player::deallocate_picture_buffer() { - m_pMoviePictureBuffer->deallocate(); + movie_picture_buffer->deallocate(); } -void THMovie::readStreams() +void movie_player::read_streams() { AVPacket packet; int iError; - while(!m_fAborting) + while(!aborting) { - iError = av_read_frame(m_pFormatContext, &packet); + iError = av_read_frame(format_context, &packet); if(iError < 0) { - if(iError == AVERROR_EOF || m_pFormatContext->pb->error || m_pFormatContext->pb->eof_reached) + if(iError == AVERROR_EOF || format_context->pb->error || format_context->pb->eof_reached) { break; } } else { - if(packet.stream_index == m_iVideoStream) + if(packet.stream_index == video_stream_index) { - m_pVideoQueue->push(&packet); + video_queue->push(&packet); } - else if (packet.stream_index == m_iAudioStream) + else if (packet.stream_index == audio_stream_index) { - m_pAudioQueue->push(&packet); + audio_queue->push(&packet); } else { - av_free_packet(&packet); + av_packet_unref(&packet); } } } - while(!m_fAborting) + while(!aborting) { - if(m_pVideoQueue->getCount() == 0 && m_pAudioQueue->getCount() == 0 && m_pMoviePictureBuffer->empty()) + if(video_queue->get_count() == 0 && audio_queue->get_count() == 0 && movie_picture_buffer->get_next_pts() == 0) { break; } - SDL_Delay(10); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } SDL_Event endEvent; endEvent.type = SDL_USEREVENT_MOVIE_OVER; SDL_PushEvent(&endEvent); - m_fAborting = true; + aborting = true; } -void THMovie::runVideo() +void movie_player::run_video() { - AVFrame *pFrame = avcodec_alloc_frame(); - int64_t iStreamPts = AV_NOPTS_VALUE; + AVFrame *pFrame = av_frame_alloc(); double dClockPts; int iError; - while(!m_fAborting) + while(!aborting) { - avcodec_get_frame_defaults(pFrame); + av_frame_unref(pFrame); + +#ifdef CORSIX_TH_MOVIE_USE_SEND_PACKET_API + iError = get_frame(video_stream_index, pFrame); - iError = getVideoFrame(pFrame, &iStreamPts); + if (iError == AVERROR_EOF) + { + break; + } + else if (iError < 0) + { + std::cerr << "Unexpected error " << iError << " while decoding video packet" << std::endl; + break; + } +#else + iError = get_video_frame(pFrame); if(iError < 0) { break; @@ -804,9 +820,10 @@ { continue; } +#endif - dClockPts = iStreamPts * av_q2d(m_pVideoCodecContext->time_base); - iError = m_pMoviePictureBuffer->write(pFrame, dClockPts); + dClockPts = get_presentation_time_for_frame(pFrame, video_stream_index); + iError = movie_picture_buffer->write(pFrame, dClockPts); if(iError < 0) { @@ -814,30 +831,103 @@ } } - avcodec_flush_buffers(m_pVideoCodecContext); - av_free(pFrame); + avcodec_flush_buffers(video_codec_context); + av_frame_free(&pFrame); } -int THMovie::getVideoFrame(AVFrame *pFrame, int64_t *piPts) +double movie_player::get_presentation_time_for_frame(AVFrame* frame, int streamIndex) const +{ + int64_t pts; +#ifdef CORSIX_TH_USE_LIBAV + pts = frame->pts; + if (pts == AV_NOPTS_VALUE) + { + pts = frame->pkt_dts; + } +#else +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 18, 100) + pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(), frame, "best_effort_timestamp"); +#elif LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 18, 100) + pts = av_frame_get_best_effort_timestamp(frame); +#else + pts = frame->best_effort_timestamp; +#endif //LIBAVCODEC_VERSION_INT +#endif //CORSIX_T_USE_LIBAV + + if (pts == AV_NOPTS_VALUE) + { + pts = 0; + } + + return pts * av_q2d(format_context->streams[streamIndex]->time_base); +} + +#ifdef CORSIX_TH_MOVIE_USE_SEND_PACKET_API +int movie_player::get_frame(int stream, AVFrame* pFrame) +{ + int iError = AVERROR(EAGAIN); + AVCodecContext* ctx; + av_packet_queue* pq; + + if (stream == video_stream_index) + { + ctx = video_codec_context; + pq = video_queue; + } + else if (stream == audio_stream_index) + { + ctx = audio_codec_context; + pq = audio_queue; + } + else + { + throw std::invalid_argument("Invalid value provided for stream"); + } + + while (iError == AVERROR(EAGAIN)) + { + iError = avcodec_receive_frame(ctx, pFrame); + + if (iError == AVERROR(EAGAIN)) + { + AVPacket* pkt = pq->pull(true); + int res = avcodec_send_packet(ctx, pkt); + if (pkt != nullptr) { + av_packet_unref(pkt); + av_free(pkt); + } + + if (res == AVERROR(EAGAIN)) + { + throw std::runtime_error("avcodec_receive_frame and avcodec_send_packet should not return EAGAIN at the same time"); + } + } + } + + return iError; +} + +#else +int movie_player::get_video_frame(AVFrame *pFrame) { int iGotPicture = 0; int iError; - AVPacket *pPacket = m_pVideoQueue->pull(true); - if(pPacket == NULL) + AVPacket *pPacket = video_queue->pull(true); + if(pPacket == nullptr) { return -1; } - if(pPacket->data == m_flushPacket->data) + if(pPacket->data == flush_packet->data) { //TODO: Flush return 0; } - iError = avcodec_decode_video2(m_pVideoCodecContext, pFrame, &iGotPicture, pPacket); - av_free_packet(pPacket); + iError = avcodec_decode_video2(video_codec_context, pFrame, &iGotPicture, pPacket); + av_packet_unref(pPacket); av_free(pPacket); if(iError < 0) @@ -848,123 +938,134 @@ if(iGotPicture) { iError = 1; - -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 18, 100) - *piPts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(), pFrame, "best_effort_timestamp"); -#else - *piPts = av_frame_get_best_effort_timestamp(pFrame); -#endif - - if(*piPts == AV_NOPTS_VALUE) - { - *piPts = 0; - } return iError; } + return 0; } +#endif -void THMovie::copyAudioToStream(uint8_t *pbStream, int iStreamSize) +void movie_player::copy_audio_to_stream(uint8_t *pbStream, int iStreamSize) { - int iAudioSize; - int iCopyLength; - bool fFirst = true; + std::lock_guard audioLock(decoding_audio_mutex); - while(iStreamSize > 0) + bool fFirst = true; + while(iStreamSize > 0 && !aborting) { - if(m_iAudioBufferIndex >= m_iAudioBufferSize) + if(audio_buffer_index >= audio_buffer_size) { - iAudioSize = decodeAudioFrame(fFirst); + int iAudioSize = decode_audio_frame(fFirst); fFirst = false; if(iAudioSize <= 0) { - memset(m_pbAudioBuffer, 0, m_iAudioBufferSize); + std::memset(audio_buffer, 0, audio_buffer_size); } else { - m_iAudioBufferSize = iAudioSize; + audio_buffer_size = iAudioSize; } - m_iAudioBufferIndex = 0; + audio_buffer_index = 0; } - iCopyLength = m_iAudioBufferSize - m_iAudioBufferIndex; + int iCopyLength = audio_buffer_size - audio_buffer_index; if(iCopyLength > iStreamSize) { iCopyLength = iStreamSize; } - memcpy(pbStream, (uint8_t *)m_pbAudioBuffer + m_iAudioBufferIndex, iCopyLength); + std::memcpy(pbStream, (uint8_t *)audio_buffer + audio_buffer_index, iCopyLength); iStreamSize -= iCopyLength; pbStream += iCopyLength; - m_iAudioBufferIndex += iCopyLength; + audio_buffer_index += iCopyLength; } } -int THMovie::decodeAudioFrame(bool fFirst) +int movie_player::decode_audio_frame(bool fFirst) { - int iBytesConsumed = 0; - int iSampleSize = 0; - int iOutSamples; +#ifdef CORSIX_TH_MOVIE_USE_SEND_PACKET_API + if (!audio_frame) + { + audio_frame = av_frame_alloc(); + } + else + { + av_frame_unref(audio_frame); + } + + int iError = get_frame(audio_stream_index, audio_frame); + + if (iError == AVERROR_EOF) + { + return 0; + } + else if (iError < 0) + { + std::cerr << "Unexpected error " << iError << " while decoding audio packet" << std::endl; + return 0; + } + + double dClockPts = get_presentation_time_for_frame(audio_frame, audio_stream_index); + current_sync_pts = dClockPts; + current_sync_pts_system_time = SDL_GetTicks(); +#else int iGotFrame = 0; bool fNewPacket = false; bool fFlushComplete = false; - double dClockPts; - int64_t iStreamPts; - while(!iGotFrame && !m_fAborting) + while(!iGotFrame && !aborting) { - if(!m_pAudioPacket || m_pAudioPacket->size == 0) + if(!audio_packet || audio_packet->size == 0) { - if(m_pAudioPacket) + if(audio_packet) { - m_pAudioPacket->data = m_pbAudioPacketData; - m_pAudioPacket->size = m_iAudioPacketSize; - av_free_packet(m_pAudioPacket); - av_free(m_pAudioPacket); - m_pAudioPacket = NULL; + audio_packet->data = audio_packet_data; + audio_packet->size = audio_packet_size; + av_packet_unref(audio_packet); + av_free(audio_packet); + audio_packet = nullptr; } - m_pAudioPacket = m_pAudioQueue->pull(true); - if(m_fAborting) + audio_packet = audio_queue->pull(true); + if(aborting) { break; } - m_pbAudioPacketData = m_pAudioPacket->data; - m_iAudioPacketSize = m_pAudioPacket->size; + audio_packet_data = audio_packet->data; + audio_packet_size = audio_packet->size; - if(m_pAudioPacket == NULL) + if(audio_packet == nullptr) { fNewPacket = false; return -1; } fNewPacket = true; - if(m_pAudioPacket->data == m_flushPacket->data) + if(audio_packet->data == flush_packet->data) { - avcodec_flush_buffers(m_pAudioCodecContext); + avcodec_flush_buffers(audio_codec_context); fFlushComplete = false; } } if(fFirst) { - iStreamPts = m_pAudioPacket->pts; + int64_t iStreamPts = audio_packet->pts; if(iStreamPts != AV_NOPTS_VALUE) { - //There is a time_base in m_pAudioCodecContext too, but that one is wrong. - dClockPts = iStreamPts * av_q2d(m_pFormatContext->streams[m_iAudioStream]->time_base); - m_iCurSyncPts = dClockPts; - m_iCurSyncPtsSystemTime = SDL_GetTicks(); + //There is a time_base in audio_codec_context too, but that one is wrong. + double dClockPts = iStreamPts * av_q2d(format_context->streams[audio_stream_index]->time_base); + current_sync_pts = dClockPts; + current_sync_pts_system_time = SDL_GetTicks(); } fFirst = false; } - while(m_pAudioPacket->size > 0 || (!m_pAudioPacket->data && fNewPacket)) + while(audio_packet->size > 0 || (!audio_packet->data && fNewPacket)) { - if(!m_frame) + if(!audio_frame) { - m_frame = avcodec_alloc_frame(); + audio_frame = av_frame_alloc(); } else { - avcodec_get_frame_defaults(m_frame); + av_frame_unref(audio_frame); } if(fFlushComplete) @@ -974,91 +1075,72 @@ fNewPacket = false; - iBytesConsumed = avcodec_decode_audio4(m_pAudioCodecContext, m_frame, &iGotFrame, m_pAudioPacket); + int iBytesConsumed = avcodec_decode_audio4(audio_codec_context, audio_frame, &iGotFrame, audio_packet); if(iBytesConsumed < 0) { - m_pAudioPacket->size = 0; + audio_packet->size = 0; break; } - m_pAudioPacket->data += iBytesConsumed; - m_pAudioPacket->size -= iBytesConsumed; + audio_packet->data += iBytesConsumed; + audio_packet->size -= iBytesConsumed; if(!iGotFrame) { - if(m_pAudioPacket->data && m_pAudioCodecContext->codec->capabilities & CODEC_CAP_DELAY) + if(audio_packet->data && (audio_codec_context->codec->capabilities & CODEC_CAP_DELAY)) { fFlushComplete = true; } } } } - -#if LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(0, 12, 100) +#endif //over-estimate output samples - iOutSamples = (int)av_rescale_rnd(m_frame->nb_samples, m_iMixerFrequency, m_pAudioCodecContext->sample_rate, AV_ROUND_UP); - iSampleSize = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * iOutSamples * m_iMixerChannels; + int iOutSamples = (int)av_rescale_rnd(audio_frame->nb_samples, mixer_frequency, audio_codec_context->sample_rate, AV_ROUND_UP); + int iSampleSize = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * iOutSamples * mixer_channels; - if(iSampleSize > m_iAudioBufferMaxSize) + if(iSampleSize > audio_buffer_max_size) { - if(m_iAudioBufferMaxSize > 0) + if(audio_buffer_max_size > 0) { - av_free(m_pbAudioBuffer); + av_free(audio_buffer); } - m_pbAudioBuffer = (uint8_t*)av_malloc(iSampleSize); - m_iAudioBufferMaxSize = iSampleSize; + audio_buffer = (uint8_t*)av_malloc(iSampleSize); + audio_buffer_max_size = iSampleSize; } -#else - //output samples = (input samples + delay) * output rate / input rate - iOutSamples = (int)av_rescale_rnd( - swr_get_delay( - m_pSwrContext, - m_pAudioCodecContext->sample_rate) + m_frame->nb_samples, - m_iMixerFrequency, - m_pAudioCodecContext->sample_rate, - AV_ROUND_UP); - iSampleSize = av_samples_get_buffer_size(NULL, m_iMixerChannels, iOutSamples, AV_SAMPLE_FMT_S16, 0); - if(iSampleSize > m_iAudioBufferMaxSize) - { - if(m_iAudioBufferMaxSize > 0) - { - av_free(m_pbAudioBuffer); - } - av_samples_alloc(&m_pbAudioBuffer, NULL, m_iMixerChannels, iOutSamples, AV_SAMPLE_FMT_S16, 0); - m_iAudioBufferMaxSize = iSampleSize; - } +#ifdef CORSIX_TH_USE_FFMPEG + swr_convert(audio_resample_context, &audio_buffer, iOutSamples, (const uint8_t**)&audio_frame->data[0], audio_frame->nb_samples); +#elif defined(CORSIX_TH_USE_LIBAV) + avresample_convert(audio_resample_context, &audio_buffer, 0, iOutSamples, (uint8_t**)&audio_frame->data[0], 0, audio_frame->nb_samples); #endif - - swr_convert(m_pSwrContext, &m_pbAudioBuffer, iOutSamples, (const uint8_t**)&m_frame->data[0], m_frame->nb_samples); - return iSampleSize; } -#else //CORSIX_TH_USE_FFMPEG -THMovie::THMovie() {} -THMovie::~THMovie() {} -bool THMovie::moviesEnabled() { return false; } -bool THMovie::load(const char* filepath) { return true; } -void THMovie::unload() {} -void THMovie::play(int iX, int iY, int iWidth, int iHeight, int iChannel) +#else //CORSIX_TH_USE_FFMPEG || CORSIX_TH_USE_LIBAV +movie_player::movie_player() {} +movie_player::~movie_player() {} +void movie_player::set_renderer(SDL_Renderer *renderer) {} +bool movie_player::movies_enabled() const { return false; } +bool movie_player::load(const char* file_path) { return true; } +void movie_player::unload() {} +void movie_player::play(int iChannel) { SDL_Event endEvent; endEvent.type = SDL_USEREVENT_MOVIE_OVER; SDL_PushEvent(&endEvent); } -void THMovie::stop() {} -int THMovie::getNativeHeight() { return 0; } -int THMovie::getNativeWidth() { return 0; } -bool THMovie::hasAudioTrack() { return false; } -bool THMovie::requiresVideoReset() { return false; } -const char* THMovie::getLastError() { return NULL; } -void THMovie::clearLastError() {} -void THMovie::refresh() {} -void THMovie::allocatePictureBuffer() {} -void THMovie::deallocatePictureBuffer() {} -void THMovie::readStreams() {} -void THMovie::runVideo() {} -void THMovie::copyAudioToStream(uint8_t *stream, int length) {} +void movie_player::stop() {} +int movie_player::get_native_height() const { return 0; } +int movie_player::get_native_width() const { return 0; } +bool movie_player::has_audio_track() const { return false; } +const char* movie_player::get_last_error() const { return nullptr; } +void movie_player::clear_last_error() {} +void movie_player::refresh(const SDL_Rect &destination_rect) {} +void movie_player::allocate_picture_buffer() {} +void movie_player::deallocate_picture_buffer() {} +void movie_player::read_streams() {} +void movie_player::run_video() {} +void movie_player::copy_audio_to_stream(uint8_t *stream, int length) {} #endif //CORSIX_TH_USE_FFMPEG diff -Nru corsix-th-0.30/CorsixTH/Src/th_movie.h corsix-th-0.62/CorsixTH/Src/th_movie.h --- corsix-th-0.30/CorsixTH/Src/th_movie.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_movie.h 2018-07-21 11:13:17.000000000 +0000 @@ -22,14 +22,17 @@ #ifndef TH_VIDEO_H #define TH_VIDEO_H -#define PICTURE_BUFFER_SIZE 4 -#define MOVIE_ERROR_BUFFER_SIZE 128 #include #include +#include +#include +#include +#include +#include "SDL.h" #include "config.h" -#ifdef CORSIX_TH_USE_FFMPEG +#if (defined(CORSIX_TH_USE_FFMPEG) || defined(CORSIX_TH_USE_LIBAV)) && defined(CORSIX_TH_USE_SDL_MIXER) #include "SDL_mixer.h" extern "C" @@ -40,176 +43,350 @@ #endif #include #include -#include #include +#ifdef CORSIX_TH_USE_FFMPEG +#include +#elif defined(CORSIX_TH_USE_LIBAV) +#include +#endif } -class SDL_Overlay; -class SDL_Surface; -struct SDL_mutex; -struct SDL_cond; +#if (defined(CORSIX_TH_USE_FFMEPG) && LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 74, 100)) || \ + (defined(CORSIX_TH_USE_LIBAV) && LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 42, 0)) +#define AVPixelFormat PixelFormat +#define AV_PIX_FMT_RBG24 PIX_FMT_RGB24 +#endif -class THMoviePicture +#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 16, 0)) || \ + (defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100)) +#define CORSIX_TH_MOVIE_USE_SEND_PACKET_API +#endif + + +//! \brief A picture in movie_picture_buffer +//! +//! Stores the picture from a frame in the movie from the time that it is +//! processed until it should be drawn. +class movie_picture { public: - THMoviePicture(); - ~THMoviePicture(); + movie_picture(); + ~movie_picture(); - void allocate(int iX, int iY, int iWidth, int iHeight); + //! Allocate the buffer to hold a picture of the given size + void allocate(int iWidth, int iHeight); + + //! Delete the buffer void deallocate(); - void draw(); - SDL_Overlay *m_pOverlay; - PixelFormat m_pixelFormat; - SDL_Surface *m_pSurface; - int m_iX, m_iY, m_iWidth, m_iHeight; - double m_dPts; - SDL_mutex *m_pMutex; - SDL_cond *m_pCond; + uint8_t* buffer; ///< Pixel data in #m_pixelFormat + const AVPixelFormat pixel_format; ///< The format of pixels to output + int width; ///< Picture width + int height; ///< Picture height + double pts; ///< Presentation time stamp + std::mutex mutex; ///< Mutex protecting this picture }; -class THMoviePictureBuffer +//! A buffer for holding movie pictures and drawing them to the renderer +class movie_picture_buffer { public: - THMoviePictureBuffer(); - ~THMoviePictureBuffer(); + movie_picture_buffer(); + ~movie_picture_buffer(); //NB: The following functions are called by the main program thread + + //! Indicate that processing should stop and the movie aborted void abort(); + + //! Resume after having aborted void reset(); - void allocate(int iX, int iY, int iWidth, int iHeight); + + //! Ready the picture buffer for a new renderer or new picture dimensions + //! by allocating each movie_picture in the queue, resetting the read + //! index and allocating a new texture. + //! + //! \remark Must be run on the program's graphics thread + void allocate(SDL_Renderer *pRenderer, int iWidth, int iHeight); + + //! Destroy the associated texture and deallocate each of the + //! movie_pictures in the queue so that the program can release + //! the renderer + //! + //! \remark Must be run on the program's graphics thread void deallocate(); + + //! Advance the read index bool advance(); - void draw(); - double getCurrentPts(); - double getNextPts(); + + //! Draw the movie_picture at the current read index + //! + //! \param pRenderer The renderer to draw the picture to + //! \param dstrect The rectangle on the renderer to draw to + //! + //! \remark Must be run on the program's graphics thread + void draw(SDL_Renderer *pRenderer, const SDL_Rect &dstrect); + + //! Get the next presentation time stamp + double get_next_pts(); + + //! Return whether there are any pictures left to draw in the picture queue + //! + //! \remark If the movie_picture_buffer is not allocated it cannot be read from + //! or written to. Consequently it is both full and empty. bool empty(); //NB: These functions are called by a second thread + + //! Return whether there is space to add any more frame data to the queue + //! + //! \remark If the movie_picture_buffer is not allocated it cannot be read from + //! or written to. Consequently it is both full and empty. bool full(); + + //! Write the given frame (and presentation time stamp) to the picture + //! queue + //! + //! \retval 0 Success + //! \retval -1 Abort is in progress + //! \retval 1 An error writing the frame int write(AVFrame* pFrame, double dPts); -protected: - bool m_fAborting; - bool m_fAllocated; - int m_iCount; - int m_iReadIndex; - int m_iWriteIndex; - SwsContext* m_pSwsContext; - SDL_mutex *m_pMutex; - SDL_cond *m_pCond; - THMoviePicture m_aPictureQueue[PICTURE_BUFFER_SIZE]; +private: + //! Return whether there is space to add any more frame data to the queue + //! + //! \remark Requires external locking + bool unsafe_full(); + + static const size_t picture_buffer_size = 4; ///< The number of elements to allocate in the picture queue + std::atomic aborting; ///< Whether we are in the process of aborting + bool allocated; ///< Whether the picture buffer has been allocated (and hasn't since been deallocated) + int picture_count; ///< The number of elements currently written to the picture queue + int read_index; ///< The position in the picture queue to be read next + int write_index; ///< The position in the picture queue to be written to next + SwsContext* sws_context; ///< The context for software scaling and pixel conversion when writing to the picture queue + SDL_Texture *texture; ///< The (potentially hardware) texture to draw the picture to. In OpenGL this should only be accessed on the main thread + std::mutex mutex; ///< A mutex for restricting access to the picture buffer to a single thread + std::condition_variable cond; ///< A condition for indicating access to the picture buffer + movie_picture picture_queue[picture_buffer_size]; ///< The picture queue, a looping FIFO queue of movie_pictures }; -class THAVPacketQueue +//! The AVPacketQueue is a thread safe queue of movie packets +class av_packet_queue { public: - THAVPacketQueue(); - ~THAVPacketQueue(); + //! Construct a new empty packet queue + av_packet_queue(); + + //! Destroy the packet queue. + //! + //! \remarks Does not free the included packets. The packet queue should be + //! flushed before it is destroyed. + ~av_packet_queue(); + + //! Push a new packet on the back of the queue void push(AVPacket *packet); + + //! Pull the packet from the front of the queue + //! + //! \param block Whether to block if the queue is empty or immediately + //! return a nullptr AVPacket* pull(bool block); - int getCount(); + + //! Return the number of packets in the queue + int get_count() const; + + //! Release a blocking pull without writing a new packet to the queue. void release(); private: - AVPacketList *m_pFirstPacket, *m_pLastPacket; - int iCount; - SDL_mutex *m_pMutex; - SDL_cond *m_pCond; + AVPacketList *first_packet; ///< The packet at the front of the queue + AVPacketList *last_packet; ///< The packet at the end of the queue + int count; ///< The number of packets in the queue + std::mutex mutex; ///< A mutex restricting access to the packet queue to a single thread + std::condition_variable cond; ///< A condition to wait on for signaling the packet queue }; -#endif //CORSIX_TH_USE_FFMPEG +#endif //CORSIX_TH_USE_FFMPEG || CORSIX_TH_USE_LIBAV -class THMovie +//! Movie player for CorsixTH +//! +//! The movie player is designed to be preinitialized and used for multiple +//! movies. After initializing the movie player, call movie_player::set_renderer +//! to assign the current SDL renderer to the movie player. Then movie_player::load +//! the desired movie and finally movie_player::play it. +class movie_player { public: - THMovie(); - ~THMovie(); + //! Construct a new movie_player + movie_player(); + + //! Destroy the movie_player + ~movie_player(); - bool moviesEnabled(); + //! Assign the renderer on which to draw the movie + void set_renderer(SDL_Renderer *pRenderer); + //! Return whether movies were compiled into CorsixTH + bool movies_enabled() const; + + //! Load the movie with the given file name bool load(const char* szFilepath); + + //! Unload and free the currently loaded movie. + //! + //! \remark This is called by load before loading a new movie so it is + //! unnecessary to explicitly call this method. There is no harm either. void unload(); - void play(int iX, int iY, int iWidth, int iHeight, int iChannel); + //! Play the currently loaded movie + //! + //! \param iChannel The audio channel to use + void play(int iChannel); + + //! Stop the currently playing movie void stop(); - int getNativeHeight(); - int getNativeWidth(); - bool hasAudioTrack(); - bool requiresVideoReset(); - - const char* getLastError(); - void clearLastError(); - - void refresh(); - void deallocatePictureBuffer(); - void allocatePictureBuffer(); - - void readStreams(); - void runVideo(); - void copyAudioToStream(uint8_t *pbStream, int iStreamSize); -protected: -#ifdef CORSIX_TH_USE_FFMPEG - int decodeAudioFrame(bool fFirst); - int getVideoFrame(AVFrame *pFrame, int64_t *piPts); + //! Return the original height of the movie + int get_native_height() const; + + //! Return the original width of the movie + int get_native_width() const; + + //! Return whether the movie has an audio stream + bool has_audio_track() const; - //last error - std::string m_sLastError; - char m_szErrorBuffer[MOVIE_ERROR_BUFFER_SIZE]; - - //abort playing movie - bool m_fAborting; - - //current movie dimensions and placement - int m_iX, m_iY, m_iWidth, m_iHeight; - - //ffmpeg movie information - AVFormatContext* m_pFormatContext; - int m_iVideoStream; - int m_iAudioStream; - AVCodecContext* m_pVideoCodecContext; - AVCodecContext* m_pAudioCodecContext; - - //queues for transfering data between threads - THAVPacketQueue *m_pVideoQueue; - THAVPacketQueue *m_pAudioQueue; - THMoviePictureBuffer *m_pMoviePictureBuffer; + //! Return a text description of the last error encountered + const char* get_last_error() const; + + //! Clear the last error so that if there is no more errors before the next + //! call to movie_player::get_last_error() it will return an empty string. + void clear_last_error(); + + //! Draw the next frame if it is time to do so + //! + //! \param destination_rect The location and dimensions in the renderer on + //! which to draw the movie + void refresh(const SDL_Rect &destination_rect); + + //! Deallocate the picture buffer and free any resources associated with it. + //! + //! \remark This destroys the textures and other resources that may lock + //! the renderer from being deleted. If the target changes you would call + //! this, then free and switch renderers in the outside program, then call + //! movie_player::set_renderer and finally movie_player::allocate_picture_buffer. + //! \remark Up to the size of the picture buffer frames may be lost during + //! this process. + void deallocate_picture_buffer(); + + //! Allocate the picture buffer for the current renderer + void allocate_picture_buffer(); + + //! Read packets from the movie and allocate them to the appropriate stream + //! packet queues. Signal if we have reached the end of the movie. + //! + //! \remark This should not be called externally. It is public as it is the + //! entry point of a thread. + void read_streams(); + + //! Read video frames from the video packet queue and write them to the + //! picture queue. + //! + //! \remark This should not be called externally. It is public as it is the + //! entry point of a thread. + void run_video(); + + //! Read audio from the audio packet queue, and copy it into the audio + //! buffer for playback + void copy_audio_to_stream(uint8_t *pbStream, int iStreamSize); + +private: +#if (defined(CORSIX_TH_USE_FFMPEG) || defined(CORSIX_TH_USE_LIBAV)) && defined(CORSIX_TH_USE_SDL_MIXER) + static const size_t movie_error_buffer_capacity = 128; ///< Buffer to hold last error description + static const size_t audio_chunk_buffer_capacity = 1024; ///< Buffer for audio playback + + //! Get the AVCodecContext associated with a given stream + AVCodecContext* get_codec_context_for_stream(AVCodec* codec, AVStream* stream) const; + + //! Get the time the given frame should be played (from the start of the stream) + //! + //! \param frame The video or audio frame + //! \param streamIndex The position of the stream in m_pFormatContexts streams array + double get_presentation_time_for_frame(AVFrame* frame, int streamIndex) const; + + //! Decode audio from the movie into a format suitable for playback + int decode_audio_frame(bool fFirst); + +#ifdef CORSIX_TH_MOVIE_USE_SEND_PACKET_API + //! Convert packet data into frames + //! + //! \param stream The index of the stream to get the frame for + //! \param pFrame An empty frame which gets populated by the data in the + //! packet queue. + //! \returns FFMPEG result of avcodec_recieve_frame + int get_frame(int stream, AVFrame* pFrame); +#else + //! Convert video packet data into a frame. + //! + //! \param pFrame An empty frame which gets populated by the data in the + //! video packet queue. + //! \returns 1 if the frame was received, 0 if it was not, and < 0 on error + int get_video_frame(AVFrame *pFrame); +#endif + + SDL_Renderer *renderer; ///< The renderer to draw to + + //! A description of the last error + std::string last_error; + + //! A buffer for passing to ffmpeg to get error details + char error_buffer[movie_error_buffer_capacity]; + + // TODO: Should be atomic + bool aborting; ///< Indicate that we are in process of aborting playback + + std::mutex decoding_audio_mutex; ///< Synchronize access to #m_pAudioBuffer + + AVFormatContext* format_context; ///< Information related to the loaded movie and all of its streams + int video_stream_index; ///< The index of the video stream + int audio_stream_index; ///< The index of the audio stream + AVCodecContext *video_codec_context; ///< The video codec and information related to video + AVCodecContext *audio_codec_context; ///< The audio codec and information related to audio + + //queues for transferring data between threads + av_packet_queue *video_queue; ///< Packets from the video stream + av_packet_queue *audio_queue; ///< Packets from the audio stream + ::movie_picture_buffer *movie_picture_buffer; ///< Buffer of processed video //clock sync parameters - int m_iCurSyncPtsSystemTime; - double m_iCurSyncPts; + int current_sync_pts_system_time; ///< System time matching #m_iCurSyncPts + double current_sync_pts; ///< The current presentation time stamp (from the audio stream) - //audio resample context - SwrContext* m_pSwrContext; +#ifdef CORSIX_TH_USE_FFMPEG + SwrContext* audio_resample_context; ///< Context for resampling audio for playback with ffmpeg +#elif defined(CORSIX_TH_USE_LIBAV) + AVAudioResampleContext* audio_resample_context; ///< Context for resampling audio for playback with libav +#endif - //decoded audio buffer - int m_iAudioBufferSize; - int m_iAudioBufferIndex; - int m_iAudioBufferMaxSize; - uint8_t* m_pbAudioBuffer; - - //decoding audio packet - AVPacket* m_pAudioPacket; - int m_iAudioPacketSize; - uint8_t *m_pbAudioPacketData; - - //decoding audio frame - AVFrame* m_frame; - - //empty raw chunk for SDL_mixer - Mix_Chunk* m_pChunk; - uint8_t* m_pbChunkBuffer; - - //SDL_mixer parameters - int m_iChannel; - int m_iMixerChannels; - int m_iMixerFrequency; - - //signal packet indicating flush - AVPacket* m_flushPacket; - - //threads - SDL_Thread* m_pStreamThread; - SDL_Thread* m_pVideoThread; -#endif //CORSIX_TH_USE_FFMPEG + int audio_buffer_size; ///< The current size of audio data in #m_pbAudioBuffer + int audio_buffer_index; ///< The current position for writing in #m_pbAudioBuffer + int audio_buffer_max_size; ///< The capacity of #m_pbAudioBuffer (allocated size) + uint8_t* audio_buffer; ///< An audio buffer for playback + + AVPacket* audio_packet; ///< The current audio packet being decoded (audio frames don't necessarily line up with packets) + int audio_packet_size; ///< The size of #m_pbAudioPacketData + uint8_t *audio_packet_data; ///< Original data for #m_pAudioPacket, kept so that it can be freed after the packet is processed + AVFrame* audio_frame; ///< The frame we are decoding audio into + + Mix_Chunk* empty_audio_chunk; ///< Empty chunk needed for SDL_mixer + uint8_t* audio_chunk_buffer; ///< 0'd out buffer for the SDL_Mixer chunk + + int audio_channel; ///< The channel to play audio on, -1 for none + int mixer_channels; ///< How many channels to play on (1 - mono, 2 - stereo) + int mixer_frequency; ///< The frequency of audio expected by SDL_Mixer + + AVPacket* flush_packet; ///< A representative packet indicating a flush is required. + + std::thread stream_thread; ///< The thread responsible for reading the movie streams + std::thread video_thread; ///< The thread responsible for decoding the video stream +#endif //CORSIX_TH_USE_FFMPEG || CORSIX_TH_USE_LIBAV }; #endif // TH_VIDEO_H diff -Nru corsix-th-0.30/CorsixTH/Src/th_pathfind.cpp corsix-th-0.62/CorsixTH/Src/th_pathfind.cpp --- corsix-th-0.30/CorsixTH/Src/th_pathfind.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_pathfind.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -24,221 +24,253 @@ #include "th_pathfind.h" #include "persist_lua.h" #include "lua.hpp" -#include +#include #include -#include +#include +#include -THPathfinder::THPathfinder() +abstract_pathfinder::abstract_pathfinder(pathfinder *pf) : parent(pf) +{ } + +path_node *abstract_pathfinder::init(const level_map *pMap, int iStartX, int iStartY) { - m_pNodes = NULL; - m_ppDirtyList = NULL; - m_ppOpenHeap = (node_t**)malloc(sizeof(node_t*) * 8); - m_pDestination = NULL; - m_pDefaultMap = NULL; - m_iNodeCacheWidth = 0; - m_iNodeCacheHeight = 0; - m_iDirtyCount = 0; - m_iOpenCount = 0; - m_iOpenSize = 8; -} - -THPathfinder::~THPathfinder() -{ - if(m_ppOpenHeap) - { - free(m_ppOpenHeap); - m_ppOpenHeap = NULL; - } - if(m_pNodes) - { - delete[] m_pNodes; - m_pNodes = NULL; - } - if(m_ppDirtyList) - { - delete[] m_ppDirtyList; - m_ppDirtyList = NULL; - } -} - -void THPathfinder::setDefaultMap(const THMap *pMap) -{ - m_pDefaultMap = pMap; -} - -#define Pathing_Init() \ - int iWidth = pMap->getWidth(); \ - m_pDestination = NULL; \ - _allocNodeCache(iWidth, pMap->getHeight()); \ - node_t *pNode = m_pNodes + iStartY * iWidth + iStartX; \ - pNode->prev = NULL; \ - pNode->distance = 0; \ - MakeGuess(pNode); \ - m_ppDirtyList[0] = pNode; \ - m_iDirtyCount = 1; \ - m_iOpenCount = 0; - - /* No need to check for the node being on the map edge, as the N/E/S/W - flags are set as to prevent travelling off the map (as well as to - prevent walking through walls). */ -#define Pathing_Neighbours() \ - uint32_t iPassable = iFlags & THMN_Passable; \ - if(iFlags & THMN_CanTravelW) \ - { \ - TryNode(pNode - 1, 3); \ - } \ - if(iFlags & THMN_CanTravelE) \ - { \ - TryNode(pNode + 1, 1); \ - } \ - if(iFlags & THMN_CanTravelN) \ - { \ - TryNode(pNode - iWidth, 0); \ - } \ - if(iFlags & THMN_CanTravelS) \ - { \ - TryNode(pNode + iWidth, 2); \ - } \ - -#define Pathing_TryNode() \ - if(iNFlags & THMN_Passable || iPassable == 0) \ - { \ - if(pNeighbour->prev == pNeighbour) \ - { \ - pNeighbour->prev = pNode; \ - pNeighbour->distance = pNode->distance + 1; \ - MakeGuess(pNeighbour); \ - m_ppDirtyList[m_iDirtyCount++] = pNeighbour; \ - _openHeapPush(pNeighbour); \ - } \ - else if((pNode->distance + 1) < pNeighbour->distance) \ - { \ - pNeighbour->prev = pNode; \ - pNeighbour->distance = pNode->distance + 1; \ - /* guess doesn't change, and already in the dirty list */ \ - _openHeapPromote(pNeighbour); \ - } \ - } - -#define Pathing_Next() \ - if(m_iOpenCount == 0) \ - { \ - m_pDestination = NULL; \ - break; \ - } \ - else \ - pNode = _openHeapPop() - -bool THPathfinder::findPath(const THMap *pMap, int iStartX, int iStartY, int iEndX, int iEndY) -{ - if(pMap == NULL) - pMap = m_pDefaultMap; - if(pMap == NULL || pMap->getNode(iEndX, iEndY) == NULL - || (pMap->getNodeUnchecked(iEndX, iEndY)->iFlags & THMN_Passable) == 0) + int iWidth = pMap->get_width(); + parent->destination = nullptr; + parent->allocate_node_cache(iWidth, pMap->get_height()); + path_node *pNode = parent->nodes + iStartY * iWidth + iStartX; + pNode->prev = nullptr; + pNode->distance = 0; + pNode->guess = guess_distance(pNode); + parent->dirty_node_list[0] = pNode; + parent->dirty_node_count = 1; + parent->open_heap.clear(); + return pNode; +} + +/*! No need to check for the node being on the map edge, as the N/E/S/W + flags are set as to prevent travelling off the map (as well as to + prevent walking through walls). + */ +bool abstract_pathfinder::search_neighbours(path_node *pNode, map_tile_flags flags, int iWidth) +{ + if(flags.can_travel_w) + if(try_node(pNode, flags, pNode - 1, travel_direction::west)) return true; + + if(flags.can_travel_e) + if (try_node(pNode, flags, pNode + 1, travel_direction::east)) return true; + + if(flags.can_travel_n) + if (try_node(pNode, flags, pNode - iWidth, travel_direction::north)) return true; + + if(flags.can_travel_s) + if (try_node(pNode, flags, pNode + iWidth, travel_direction::south)) return true; + + return false; +} + +void abstract_pathfinder::record_neighbour_if_passable(path_node *pNode, map_tile_flags neighbour_flags, bool passable, path_node *pNeighbour) +{ + if(neighbour_flags.passable || !passable) { - m_pDestination = NULL; - return false; + if(pNeighbour->prev == pNeighbour) + { + pNeighbour->prev = pNode; + pNeighbour->distance = pNode->distance + 1; + pNeighbour->guess = guess_distance(pNeighbour); + parent->dirty_node_list[parent->dirty_node_count++] = pNeighbour; + parent->push_to_open_heap(pNeighbour); + } + else if(pNode->distance + 1 < pNeighbour->distance) + { + pNeighbour->prev = pNode; + pNeighbour->distance = pNode->distance + 1; + /* guess doesn't change, and already in the dirty list */ + parent->open_heap_promote(pNeighbour); + } } +} +int basic_pathfinder::guess_distance(path_node *pNode) +{ // As diagonal movement is not allowed, the minimum distance between two - // points is the sum of the distance in X and the distance in Y. Provided - // that the compiler generates clever assembly for abs(), this means that - // guesses can be calculated without branching and without sqrt(). -#define MakeGuess(pNode) \ - pNode->guess = abs(pNode->x - iEndX) + abs(pNode->y - iEndY) + // points is the sum of the distance in X and the distance in Y. + return abs(pNode->x - destination_x) + abs(pNode->y - destination_y); +} - Pathing_Init(); - node_t *pTarget = m_pNodes + iEndY * iWidth + iEndX; +bool basic_pathfinder::try_node(path_node *pNode, map_tile_flags flags, + path_node *pNeighbour, travel_direction direction) +{ + map_tile_flags neighbour_flags = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags; + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + return false; +} + +bool basic_pathfinder::find_path(const level_map *pMap, int iStartX, int iStartY, int iEndX, int iEndY) +{ + if(pMap == nullptr) + pMap = parent->default_map; + if(pMap == nullptr || pMap->get_tile(iEndX, iEndY) == nullptr + || !pMap->get_tile_unchecked(iEndX, iEndY)->flags.passable) + { + parent->destination = nullptr; + return false; + } + + map = pMap; + destination_x = iEndX; + destination_y = iEndY; + + path_node *pNode = init(pMap, iStartX, iStartY); + int iWidth = pMap->get_width(); + path_node *pTarget = parent->nodes + iEndY * iWidth + iEndX; while(true) { if(pNode == pTarget) { - m_pDestination = pTarget; + parent->destination = pTarget; return true; } - uint32_t iFlags = pMap->getNodeUnchecked(pNode->x, pNode->y)->iFlags; - -#define TryNode(n, d) \ - node_t *pNeighbour = n; \ - uint32_t iNFlags = pMap->getNodeUnchecked(pNeighbour->x, pNeighbour->y)->iFlags; \ - Pathing_TryNode() + map_tile_flags flags = pMap->get_tile_unchecked(pNode->x, pNode->y)->flags; + if (search_neighbours(pNode, flags, iWidth)) return true; - Pathing_Neighbours(); - Pathing_Next(); + if (parent->open_heap.empty()) { + parent->destination = nullptr; + break; + } else { + pNode = parent->pop_from_open_heap(); + } } return false; +} -#undef MakeGuess -#undef TryNode +int hospital_finder::guess_distance(path_node *pNode) +{ + return 0; +} + +bool hospital_finder::try_node(path_node *pNode, map_tile_flags flags, + path_node *pNeighbour, travel_direction direction) +{ + map_tile_flags neighbour_flags = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags; + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + return false; } -bool THPathfinder::findPathToHospital(const THMap *pMap, int iStartX, int iStartY) +bool hospital_finder::find_path_to_hospital(const level_map *pMap, int iStartX, int iStartY) { - if(pMap == NULL) - pMap = m_pDefaultMap; - if(pMap == NULL || pMap->getNode(iStartX, iStartY) == NULL - || (pMap->getNodeUnchecked(iStartX, iStartY)->iFlags & THMN_Passable) == 0) + if(pMap == nullptr) + pMap = parent->default_map; + if(pMap == nullptr || pMap->get_tile(iStartX, iStartY) == nullptr + || !pMap->get_tile_unchecked(iStartX, iStartY)->flags.passable) { - m_pDestination = NULL; + parent->destination = nullptr; return false; } -#define MakeGuess(pNode) pNode->guess = 0 + map = pMap; - Pathing_Init(); + path_node *pNode = init(pMap, iStartX, iStartY); + int iWidth = pMap->get_width(); while(true) { - uint32_t iFlags = pMap->getNodeUnchecked(pNode->x, pNode->y)->iFlags; + map_tile_flags flags = pMap->get_tile_unchecked(pNode->x, pNode->y)->flags; - if(iFlags & THMN_Hospital) + if(flags.hospital) { - m_pDestination = pNode; + parent->destination = pNode; return true; } -#define TryNode(n, d) \ - node_t *pNeighbour = n; \ - uint32_t iNFlags = pMap->getNodeUnchecked(pNeighbour->x, pNeighbour->y)->iFlags; \ - Pathing_TryNode() + if (search_neighbours(pNode, flags, iWidth)) return true; - Pathing_Neighbours(); - Pathing_Next(); + if (parent->open_heap.empty()) { + parent->destination = nullptr; + break; + } else { + pNode = parent->pop_from_open_heap(); + } } return false; +} -#undef MakeGuess -#undef TryNode +int idle_tile_finder::guess_distance(path_node *pNode) +{ + return 0; } -bool THPathfinder::findIdleTile(const THMap *pMap, int iStartX, int iStartY, int iN) +bool idle_tile_finder::try_node(path_node *pNode, map_tile_flags flags, + path_node *pNeighbour, travel_direction direction) { - if(pMap == NULL) - pMap = m_pDefaultMap; - if(pMap == NULL) + map_tile_flags neighbour_flags = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags; + /* When finding an idle tile, do not navigate through doors */ + switch(direction) { - m_pDestination = NULL; - return false; + case travel_direction::north: + if(!flags.door_north) + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + break; + + case travel_direction::east: + if(!neighbour_flags.door_west) + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + break; + + case travel_direction::south: + if(!neighbour_flags.door_north) + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + break; + + case travel_direction::west: + if(!flags.door_west) + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + break; } -#define MakeGuess(pNode) \ - pNode->guess = 0 + /* Identify the neighbour in the open list nearest to the start */ + if(pNeighbour->prev != pNeighbour && pNeighbour->open_idx != -1) + { + int iDX = pNeighbour->x - start_x; + int iDY = pNeighbour->y - start_y; + double fDistance = sqrt((double)(iDX * iDX + iDY * iDY)); + if(best_next_node == nullptr || fDistance < best_distance) + { + best_next_node = pNeighbour; best_distance = fDistance; + } + } + return false; +} + +bool idle_tile_finder::find_idle_tile(const level_map *pMap, int iStartX, int iStartY, int iN) +{ + if(pMap == nullptr) + pMap = parent->default_map; + if(pMap == nullptr) + { + parent->destination = nullptr; + return false; + } - Pathing_Init(); - node_t *pPossibleResult = NULL; + start_x = iStartX; + start_y = iStartY; + map = pMap; + + path_node *pNode = init(pMap, iStartX, iStartY); + int iWidth = pMap->get_width(); + path_node *pPossibleResult = nullptr; while(true) { pNode->open_idx = -1; - uint32_t iFlags = pMap->getNodeUnchecked(pNode->x, pNode->y)->iFlags; + map_tile_flags flags = pMap->get_tile_unchecked(pNode->x, pNode->y)->flags; - if((iFlags & THMN_DoNotIdle) == 0 && (iFlags & THMN_Passable) && (iFlags & THMN_Hospital)) + if(!flags.do_not_idle && flags.passable && flags.hospital) { if(iN == 0) { - m_pDestination = pNode; + parent->destination = pNode; return true; } else @@ -248,167 +280,171 @@ } } - node_t* pBestNext = NULL; - double fBestDistance = 0.0; + best_next_node = nullptr; + best_distance = 0.0; -#define TryNode(n, d) \ - node_t *pNeighbour = n; \ - uint32_t iNFlags = pMap->getNodeUnchecked(pNeighbour->x, pNeighbour->y)->iFlags; \ - /* When finding an idle tile, do not navigate through doors */ \ - switch(d) \ - { \ - case 0: \ - if((iFlags & THMN_DoorNorth) == 0) {Pathing_TryNode()} \ - break; \ - case 1: \ - if((iNFlags & THMN_DoorWest) == 0) {Pathing_TryNode()} \ - break; \ - case 2: \ - if((iNFlags & THMN_DoorNorth) == 0) {Pathing_TryNode()} \ - break; \ - case 3: \ - if((iFlags & THMN_DoorWest) == 0) {Pathing_TryNode()} \ - break; \ - } \ - /* Identify the neighbour in the open list nearest to the start */ \ - if(pNeighbour->prev != pNeighbour && pNeighbour->open_idx != -1) \ - { \ - int iDX = pNeighbour->x - iStartX; \ - int iDY = pNeighbour->y - iStartY; \ - double fDistance = sqrt((double)(iDX * iDX + iDY * iDY)); \ - if(pBestNext == NULL || fDistance < fBestDistance) \ - pBestNext = pNeighbour, fBestDistance = fDistance; \ - } - - Pathing_Neighbours(); + if (search_neighbours(pNode, flags, iWidth)) return true; - if(m_iOpenCount == 0) - { - m_pDestination = NULL; + if (parent->open_heap.empty()) { + parent->destination = nullptr; break; } - if(pBestNext) + + if(best_next_node) { // Promote the best neighbour to the front of the open list // This causes sequential iN to give neighbouring results for most iN - pBestNext->guess = -pBestNext->distance; - _openHeapPromote(pBestNext); + best_next_node->guess = -best_next_node->distance; + parent->open_heap_promote(best_next_node); } - pNode = _openHeapPop(); + pNode = parent->pop_from_open_heap(); } if(pPossibleResult) { - m_pDestination = pPossibleResult; + parent->destination = pPossibleResult; return true; } return false; +} -#undef MakeGuess -#undef TryNode +int object_visitor::guess_distance(path_node *pNode) +{ + return 0; } -bool THPathfinder::visitObjects(const THMap *pMap, int iStartX, int iStartY, - THObjectType eTHOB, int iMaxDistance, - lua_State *L, int iVisitFunction, bool anyObjectType) +bool object_visitor::try_node(path_node *pNode, map_tile_flags flags, path_node *pNeighbour, travel_direction direction) { - if(pMap == NULL) - pMap = m_pDefaultMap; - if(pMap == NULL) + int iObjectNumber = 0; + const map_tile *pMapNode = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y); + map_tile_flags neighbour_flags = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags; + for(auto thob : pMapNode->objects) + { + if(thob == target) + iObjectNumber++; + } + if(target_any_object_type) + iObjectNumber = 1; + bool bSucces = false; + for(int i = 0; i < iObjectNumber; i++) + { + /* call the given Lua function, passing four arguments: */ + /* The x and y position of the object (Lua tile co-ords) */ + /* The direction which was last travelled in to reach (x,y); */ + /* 0 (north), 1 (east), 2 (south), 3 (west) */ + /* The distance to the object from the search starting point */ + lua_pushvalue(L, visit_function_index); + lua_pushinteger(L, pNeighbour->x + 1); + lua_pushinteger(L, pNeighbour->y + 1); + lua_pushinteger(L, static_cast(direction)); + lua_pushinteger(L, pNode->distance); + lua_call(L, 4, 1); + if(lua_toboolean(L, -1) != 0) + { + bSucces = true; + } + lua_pop(L, 1); + } + if(bSucces) + return true; + + if(pNode->distance < max_distance) + { + switch(direction) + { + case travel_direction::north: + if(!flags.door_north) + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + break; + + case travel_direction::east: + if(!neighbour_flags.door_west) + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + break; + + case travel_direction::south: + if(!neighbour_flags.door_north) + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + break; + + case travel_direction::west: + if(!flags.door_west) + record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour); + break; + } + } + return false; +} + +bool object_visitor::visit_objects(const level_map *pMap, int iStartX, int iStartY, + object_type eTHOB, int iMaxDistance, + lua_State *L, int iVisitFunction, bool anyObjectType) +{ + if(pMap == nullptr) + pMap = parent->default_map; + if(pMap == nullptr) { - m_pDestination = NULL; + parent->destination = nullptr; return false; } -#define MakeGuess(pNode) \ - pNode->guess = 0 + this->L = L; + visit_function_index = iVisitFunction; + max_distance = iMaxDistance; + target_any_object_type = anyObjectType; + target = eTHOB; + map = pMap; - Pathing_Init(); - uint32_t iTHOB = static_cast(eTHOB) << 24; + path_node *pNode = init(pMap, iStartX, iStartY); + int iWidth = pMap->get_width(); while(true) { - uint32_t iFlags = pMap->getNodeUnchecked(pNode->x, pNode->y)->iFlags; + map_tile_flags flags = pMap->get_tile_unchecked(pNode->x, pNode->y)->flags; + if (search_neighbours(pNode, flags, iWidth)) return true; -#define TryNode(n, d) \ - node_t *pNeighbour = n; \ - int iObjectNumber = 0; \ - const THMapNode *pMapNode = pMap->getNodeUnchecked(pNeighbour->x, pNeighbour->y);\ - uint32_t iNFlags = pMap->getNodeUnchecked(pNeighbour->x, pNeighbour->y)->iFlags; \ - if ((iNFlags & 0xFF000000) == iTHOB) \ - iObjectNumber = 1; \ - if(pMapNode->pExtendedObjectList != NULL)\ - {\ - int count = *pMapNode->pExtendedObjectList & 7;\ - for(int i = 0; i < count; i++) \ - { \ - int thob = (*pMapNode->pExtendedObjectList & (255 << (3 + (i << 3)))) >> (3 + (i << 3)); \ - if(thob == eTHOB)\ - iObjectNumber++; \ - } \ - } \ - if(anyObjectType) \ - iObjectNumber = 1; \ - bool bSucces = false; \ - for(int i = 0; i < iObjectNumber; i++) \ - { \ - /* call the given Lua function, passing four arguments: */ \ - /* The x and y position of the object (Lua tile co-ords) */ \ - /* The direction which was last travelled in to reach (x,y); */ \ - /* 0 (north), 1 (east), 2 (south), 3 (west) */ \ - /* The distance to the object from the search starting point */ \ - lua_pushvalue(L, iVisitFunction); \ - lua_pushinteger(L, pNeighbour->x + 1); \ - lua_pushinteger(L, pNeighbour->y + 1); \ - lua_pushinteger(L, d); \ - lua_pushinteger(L, pNode->distance); \ - lua_call(L, 4, 1); \ - if(lua_toboolean(L, -1) != 0) \ - { \ - bSucces = true; \ - } \ - lua_pop(L, 1); \ - } \ - if(bSucces) \ - return true; \ - if(pNode->distance < iMaxDistance) \ - { \ - switch(d) \ - { \ - case 0: \ - if((iFlags & THMN_DoorNorth) == 0) {Pathing_TryNode()} \ - break; \ - case 1: \ - if((iNFlags & THMN_DoorWest) == 0) {Pathing_TryNode()} \ - break; \ - case 2: \ - if((iNFlags & THMN_DoorNorth) == 0) {Pathing_TryNode()} \ - break; \ - case 3: \ - if((iFlags & THMN_DoorWest) == 0) {Pathing_TryNode()} \ - break; \ - } \ + if (parent->open_heap.empty()) { + parent->destination = nullptr; + break; + } else { + pNode = parent->pop_from_open_heap(); } - - Pathing_Neighbours(); - Pathing_Next(); } return false; +} + +pathfinder::pathfinder() : basic_pathfinder(this), hospital_finder(this), + idle_tile_finder(this), object_visitor(this), + open_heap() +{ + nodes = nullptr; + dirty_node_list = nullptr; + destination = nullptr; + default_map = nullptr; + node_cache_width = 0; + node_cache_height = 0; + dirty_node_count = 0; +} + +pathfinder::~pathfinder() +{ + delete[] nodes; + delete[] dirty_node_list; +} -#undef MakeGuess -#undef TryNode +void pathfinder::set_default_map(const level_map *pMap) +{ + default_map = pMap; } -#undef Pathing_Init -#undef Pathing_TryNode -#undef Pathing_NeighboursAndNext -void THPathfinder::_allocNodeCache(int iWidth, int iHeight) + +void pathfinder::allocate_node_cache(int iWidth, int iHeight) { - if(m_iNodeCacheWidth != iWidth || m_iNodeCacheHeight != iHeight) + if(node_cache_width != iWidth || node_cache_height != iHeight) { - delete[] m_pNodes; - m_pNodes = new node_t[iWidth * iHeight]; - node_t *pNode = m_pNodes; + delete[] nodes; + nodes = new path_node[iWidth * iHeight]; + path_node *pNode = nodes; for(int iY = 0; iY < iHeight; ++iY) { for(int iX = 0; iX < iWidth; ++iX, ++pNode) @@ -420,34 +456,34 @@ // path, and thus can be left uninitialised. } } - delete[] m_ppDirtyList; - m_ppDirtyList = new node_t*[iWidth * iHeight]; - m_iNodeCacheWidth = iWidth; - m_iNodeCacheHeight = iHeight; + delete[] dirty_node_list; + dirty_node_list = new path_node*[iWidth * iHeight]; + node_cache_width = iWidth; + node_cache_height = iHeight; } else { - for(int i = 0; i < m_iDirtyCount; ++i) + for(int i = 0; i < dirty_node_count; ++i) { - m_ppDirtyList[i]->prev = m_ppDirtyList[i]; + dirty_node_list[i]->prev = dirty_node_list[i]; // Other fields are undefined as the node is not part of a path, // and thus can keep their old values. } } - m_iDirtyCount = 0; + dirty_node_count = 0; } -int THPathfinder::getPathLength() const +int pathfinder::get_path_length() const { - if(m_pDestination != NULL) - return m_pDestination->distance; + if(destination != nullptr) + return destination->distance; else return -1; } -bool THPathfinder::getPathEnd(int* pX, int* pY) const +bool pathfinder::get_path_end(int* pX, int* pY) const { - if(m_pDestination == NULL) + if(destination == nullptr) { if(pX) *pX = -1; @@ -456,28 +492,28 @@ return false; } if(pX) - *pX = m_pDestination->x; + *pX = destination->x; if(pY) - *pY = m_pDestination->y; + *pY = destination->y; return true; } -void THPathfinder::pushResult(lua_State *L) const +void pathfinder::push_result(lua_State *L) const { lua_checkstack(L, 3); - if(m_pDestination == NULL) + if(destination == nullptr) { lua_pushnil(L); lua_pushliteral(L, "no path"); return; } - int iLength = m_pDestination->distance; + int iLength = destination->distance; lua_createtable(L, iLength + 1, 0); lua_createtable(L, iLength + 1, 0); - for(const node_t* pNode = m_pDestination; pNode; pNode = pNode->prev) + for(const path_node* pNode = destination; pNode; pNode = pNode->prev) { lua_pushinteger(L, pNode->x + 1); lua_rawseti(L, -3, pNode->distance + 1); @@ -486,57 +522,57 @@ } } -void THPathfinder::_openHeapPush(THPathfinder::node_t* pNode) +void pathfinder::push_to_open_heap(path_node* pNode) { - if(m_iOpenCount == m_iOpenSize) - { - m_iOpenSize = (m_iOpenSize + 1) * 2; - m_ppOpenHeap = (node_t**)realloc(m_ppOpenHeap, sizeof(node_t*) * m_iOpenSize); - } - int i = m_iOpenCount++; - m_ppOpenHeap[i] = pNode; - pNode->open_idx = i; - _openHeapPromote(pNode); + pNode->open_idx = open_heap.size(); + open_heap.push_back(pNode); + open_heap_promote(pNode); } -void THPathfinder::_openHeapPromote(THPathfinder::node_t* pNode) +void pathfinder::open_heap_promote(path_node* pNode) { int i = pNode->open_idx; while(i > 0) { int parent = (i - 1) / 2; - node_t *pParent = m_ppOpenHeap[parent]; + path_node *pParent = open_heap[parent]; if(pParent->value() <= pNode->value()) break; pParent->open_idx = i; - m_ppOpenHeap[i] = pParent; - m_ppOpenHeap[parent] = pNode; + open_heap[i] = pParent; + open_heap[parent] = pNode; i = parent; } pNode->open_idx = i; } -THPathfinder::node_t* THPathfinder::_openHeapPop() +path_node* pathfinder::pop_from_open_heap() { - node_t *pResult = m_ppOpenHeap[0]; - node_t *pNode = m_ppOpenHeap[--m_iOpenCount]; - m_ppOpenHeap[0] = pNode; + path_node *pResult = open_heap[0]; + path_node *pNode = open_heap.back(); + open_heap.pop_back(); + + if (open_heap.empty()) { + return pResult; + } + + open_heap[0] = pNode; int i = 0; int min = 0; int left = i * 2 + 1; const int value = pNode->value(); - while(left < m_iOpenCount) + while(left < open_heap.size()) { min = i; const int right = (i + 1) * 2; int minvalue = value; - node_t *pSwap = NULL; - node_t *pTest = m_ppOpenHeap[left]; + path_node *pSwap = nullptr; + path_node *pTest = open_heap[left]; if(pTest->value() < minvalue) min = left, minvalue = pTest->value(), pSwap = pTest; - if(right < m_iOpenCount) + if(right < open_heap.size()) { - pTest = m_ppOpenHeap[right]; + pTest = open_heap[right]; if(pTest->value() < minvalue) min = right, pSwap = pTest; } @@ -544,8 +580,8 @@ break; pSwap->open_idx = i; - m_ppOpenHeap[i] = pSwap; - m_ppOpenHeap[min] = pNode; + open_heap[i] = pSwap; + open_heap[min] = pNode; i = min; left = i * 2 + 1; } @@ -553,52 +589,52 @@ return pResult; } -void THPathfinder::persist(LuaPersistWriter *pWriter) const +void pathfinder::persist(lua_persist_writer *pWriter) const { - if(m_pDestination == NULL) + if(destination == nullptr) { - pWriter->writeVUInt(0); + pWriter->write_uint(0); return; } - pWriter->writeVUInt(getPathLength() + 1); - pWriter->writeVUInt(m_iNodeCacheWidth); - pWriter->writeVUInt(m_iNodeCacheHeight); - for(const node_t* pNode = m_pDestination; pNode; pNode = pNode->prev) + pWriter->write_uint(get_path_length() + 1); + pWriter->write_uint(node_cache_width); + pWriter->write_uint(node_cache_height); + for(const path_node* pNode = destination; pNode; pNode = pNode->prev) { - pWriter->writeVUInt(pNode->x); - pWriter->writeVUInt(pNode->y); + pWriter->write_uint(pNode->x); + pWriter->write_uint(pNode->y); } } -void THPathfinder::depersist(LuaPersistReader *pReader) +void pathfinder::depersist(lua_persist_reader *pReader) { - new (this) THPathfinder; // Call constructor + new (this) pathfinder; // Call constructor int iLength; - if(!pReader->readVUInt(iLength)) + if(!pReader->read_uint(iLength)) return; if(iLength == 0) return; int iWidth, iHeight; - if(!pReader->readVUInt(iWidth) || !pReader->readVUInt(iHeight)) + if(!pReader->read_uint(iWidth) || !pReader->read_uint(iHeight)) return; - _allocNodeCache(iWidth, iHeight); + allocate_node_cache(iWidth, iHeight); int iX, iY; - if(!pReader->readVUInt(iX) || !pReader->readVUInt(iY)) + if(!pReader->read_uint(iX) || !pReader->read_uint(iY)) return; - node_t *pNode = m_pNodes + iY * iWidth + iX; - m_pDestination = pNode; + path_node *pNode = nodes + iY * iWidth + iX; + destination = pNode; for(int i = 0; i <= iLength - 2; ++i) { - if(!pReader->readVUInt(iX) || !pReader->readVUInt(iY)) + if(!pReader->read_uint(iX) || !pReader->read_uint(iY)) return; - node_t *pPrevNode = m_pNodes + iY * iWidth + iX; + path_node *pPrevNode = nodes + iY * iWidth + iX; pNode->distance = iLength - 1 - i; pNode->prev = pPrevNode; - m_ppDirtyList[m_iDirtyCount++] = pNode; + dirty_node_list[dirty_node_count++] = pNode; pNode = pPrevNode; } pNode->distance = 0; - pNode->prev = NULL; - m_ppDirtyList[m_iDirtyCount++] = pNode; + pNode->prev = nullptr; + dirty_node_list[dirty_node_count++] = pNode; } diff -Nru corsix-th-0.30/CorsixTH/Src/th_pathfind.h corsix-th-0.62/CorsixTH/Src/th_pathfind.h --- corsix-th-0.30/CorsixTH/Src/th_pathfind.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_pathfind.h 2018-07-21 11:13:17.000000000 +0000 @@ -24,103 +24,252 @@ #define CORSIX_TH_TH_PATHFIND_H_ #include "th_map.h" -class LuaPersistReader; -class LuaPersistWriter; +class lua_persist_reader; +class lua_persist_writer; +class pathfinder; + +/** Directions of movement. */ +enum class travel_direction { + north = 0, ///< Move to the north. + east = 1, ///< Move to the east. + south = 2, ///< Move to the south. + west = 3 ///< Move to the west. +}; + +/** Node in the path finder routines. */ +struct path_node +{ + //! Pointer to the previous node in the path to this cell. + /*! + Points to nullptr if this is the first cell in the path, or points to + itself if it is not part of a path. + */ + const path_node* prev; + + //! X-position of this cell (constant) + int x; + + //! Y-position of this cell (constant) + int y; + + //! Current shortest distance to this cell + /*! + Defined as prev->distance + 1 (or 0 if prev == nullptr). + Value is undefined if not part of a path. + */ + int distance; + + //! Minimum distance from this cell to the goal + /*! + Value is only dependant upon the cell position and the goal + position, and is undefined if not part of a path. + */ + int guess; + + //! Index of this cell in the open heap + /*! + If the cell is not in the open heap, then this value is undefined. + */ + int open_idx; + + //! Total cost of this node. + /*! + @return Total cost of the node, traveled distance and guess to the destination. + */ + inline int value() const { return distance + guess; } +}; + +/** Base class of the path finders. */ +class abstract_pathfinder +{ +public: + abstract_pathfinder(pathfinder *pf); + virtual ~abstract_pathfinder() = default; + + //! Initialize the path finder. + /*! + @param pMap Map to search on. + @param iStartX X coordinate of the start position. + @param iStarty Y coordinate of the start position. + @return The initial node to expand. + */ + path_node *init(const level_map *pMap, int iStartX, int iStarty); + + //! Expand the \a pNode to its neighbours. + /*! + @param pNode Node to expand. + @param iFlags Flags of the node. + @param iWidth Width of the map. + @return Whether the search is done. + */ + bool search_neighbours(path_node *pNode, map_tile_flags flags, int iWidth); + + void record_neighbour_if_passable(path_node *pNode, map_tile_flags neighbour_flags, + bool passable, path_node *pNeighbour); + + //! Guess distance to the destination for \a pNode. + /*! + @param pNode Node to fill. + */ + virtual int guess_distance(path_node *pNode) = 0; + + //! Try the \a pNeighbour node. + /*! + @param pNode Source node. + @param flags Flags of the node. + @param pNeighbour Neighbour of \a pNode to try. + @param direction Direction of travel. + @return Whether the search is done. + */ + virtual bool try_node(path_node *pNode, map_tile_flags flags, + path_node *pNeighbour, travel_direction direction) = 0; + +protected: + pathfinder *parent; ///< Path finder parent object, containing shared data. + const level_map *map; ///< Map being searched. +}; + +class basic_pathfinder : public abstract_pathfinder +{ +public: + basic_pathfinder(pathfinder *pf) : abstract_pathfinder(pf) { } + + int guess_distance(path_node *pNode) override; + bool try_node(path_node *pNode, map_tile_flags flags, + path_node *pNeighbour, travel_direction direction) override; + + bool find_path(const level_map *pMap, int iStartX, int iStartY, int iEndX, int iEndY); + + int destination_x; ///< X coordinate of the destination of the path. + int destination_y; ///< Y coordinate of the destination of the path. +}; + +class hospital_finder : public abstract_pathfinder +{ +public: + hospital_finder(pathfinder *pf) : abstract_pathfinder(pf) { } + + int guess_distance(path_node *pNode) override; + bool try_node(path_node *pNode, map_tile_flags flags, + path_node *pNeighbour, travel_direction direction) override; + + bool find_path_to_hospital(const level_map *pMap, int iStartX, int iStartY); +}; + +class idle_tile_finder : public abstract_pathfinder +{ +public: + idle_tile_finder(pathfinder *pf) : abstract_pathfinder(pf) { } + + int guess_distance(path_node *pNode) override; + bool try_node(path_node *pNode, map_tile_flags flags, + path_node *pNeighbour, travel_direction direction) override; + + bool find_idle_tile(const level_map *pMap, int iStartX, int iStartY, int iN); + + path_node *best_next_node; + double best_distance; + int start_x; ///< X coordinate of the start position. + int start_y; ///< Y coordinate of the start position. +}; + +class object_visitor : public abstract_pathfinder +{ +public: + object_visitor(pathfinder *pf) : abstract_pathfinder(pf) { } + + int guess_distance(path_node *pNode) override; + bool try_node(path_node *pNode, map_tile_flags flags, + path_node *pNeighbour, travel_direction direction) override; + + bool visit_objects(const level_map *pMap, int iStartX, int iStartY, + object_type eTHOB, int iMaxDistance, + lua_State *L, int iVisitFunction, bool anyObjectType); + + lua_State *L; + int visit_function_index; + int max_distance; + bool target_any_object_type; + object_type target; +}; //! Finds paths through maps /*! A pathfinder is used for finding a path through a map. A single pathfinder instance is not reentrant, but separate instances are. Users of the class - should call findPath() to test if there is a path between two points on a - map, and then use getPathLength() and/or pushResult() to get the actual + should call find_path() to test if there is a path between two points on a + map, and then use get_path_length() and/or push_result() to get the actual path. Internally, the A* search algorithm is used. The open set is implemented as - a heap in m_ppOpenHeap, and there is no explicit closed set. For each cell - of the map, a node_t structure is created (and cached between searches if + a heap in open_heap, and there is no explicit closed set. For each cell + of the map, a path_node structure is created (and cached between searches if the map size is constant), which holds information about said map cell in the current search. The algorithm is implemented in such a way that most path find operations do not need to allocate (or free) any memory. */ -class THPathfinder +class pathfinder { public: - THPathfinder(); - ~THPathfinder(); + pathfinder(); + ~pathfinder(); - void setDefaultMap(const THMap *pMap); + void set_default_map(const level_map *pMap); - bool findPath(const THMap *pMap, int iStartX, int iStartY, int iEndX, - int iEndY); - bool findIdleTile(const THMap *pMap, int iStartX, int iStartY, int iN); - bool findPathToHospital(const THMap *pMap, int iStartX, int iStartY); - bool visitObjects(const THMap *pMap, int iStartX, int iStartY, - THObjectType eTHOB, int iMaxDistance, lua_State *L, - int iVisitFunction, bool anyObjectType); + inline bool find_path(const level_map *pMap, int iStartX, int iStartY, int iEndX, + int iEndY) + { + return basic_pathfinder.find_path(pMap, iStartX, iStartY, iEndX, iEndY); + } - int getPathLength() const; - bool getPathEnd(int* pX, int* pY) const; - void pushResult(lua_State *L) const; + inline bool find_idle_tile(const level_map *pMap, int iStartX, int iStartY, int iN) + { + return idle_tile_finder.find_idle_tile(pMap, iStartX, iStartY, iN); + } - void persist(LuaPersistWriter *pWriter) const; - void depersist(LuaPersistReader *pReader); + inline bool find_path_to_hospital(const level_map *pMap, int iStartX, int iStartY) + { + return hospital_finder.find_path_to_hospital(pMap, iStartX, iStartY); + } -protected: - struct node_t + inline bool visit_objects(const level_map *pMap, int iStartX, int iStartY, + object_type eTHOB, int iMaxDistance, lua_State *L, + int iVisitFunction, bool anyObjectType) { - //! Pointer to the previous node in the path to this cell. - /*! - Points to NULL if this is the first cell in the path, or points to - itself if it is not part of a path. - */ - const node_t* prev; - - //! X-position of this cell (constant) - int x; - - //! Y-position of this cell (constant) - int y; - - //! Current shortest distance to this cell - /*! - Defined as prev->distance + 1 (or 0 if prev == NULL). - Value is undefined if not part of a path. - */ - int distance; - - //! Minimum distance from this cell to the goal - /*! - Value is only dependant upon the cell position and the goal - position, and is undefined if not part of a path. - */ - int guess; - - //! Index of this cell in the open heap - /*! - If the cell is not in the open heap, then this value is undefined. - */ - int open_idx; - - inline int value() const {return distance + guess;} - }; - - void _allocNodeCache(int iWidth, int iHeight); - - node_t* _openHeapPop(); - void _openHeapPush(node_t* pNode); - void _openHeapPromote(node_t* pNode); + return object_visitor.visit_objects( + pMap, iStartX, iStartY, eTHOB, iMaxDistance, + L, iVisitFunction, anyObjectType); + } + + int get_path_length() const; + bool get_path_end(int* pX, int* pY) const; + void push_result(lua_State *L) const; - const THMap *m_pDefaultMap; + void persist(lua_persist_writer *pWriter) const; + void depersist(lua_persist_reader *pReader); + + //! Allocate node cache for all tiles of the map. + /*! + @param iWidth Width of the map. + @param iHeight Height of the map. + */ + void allocate_node_cache(int iWidth, int iHeight); + + path_node* pop_from_open_heap(); + void push_to_open_heap(path_node* pNode); + void open_heap_promote(path_node* pNode); + + const level_map *default_map; //! 2D array of nodes, one for each map cell - node_t *m_pNodes; + path_node *nodes; //! Array of "dirty" nodes which need to be reset before the next path find /*! This array is always large enough to hold every single node, and - m_iDirtyCount holds the number of items currently in the array. + #dirty_node_count holds the number of items currently in the array. */ - node_t **m_ppDirtyList; + path_node **dirty_node_list; //! Heap of not yet evaluated nodes as a 0-based array /*! @@ -128,18 +277,19 @@ value(i) <= value(i * 2 + 1) value(i) <= value(i * 2 + 2) This causes the array to be a minimum binary heap. - - Note that unlike the dirty list, there is only space for m_iOpenSize - items (with m_iOpenCount being the current number of items). */ - node_t **m_ppOpenHeap; + std::vector open_heap; - node_t *m_pDestination; - int m_iNodeCacheWidth; - int m_iNodeCacheHeight; - int m_iDirtyCount; - int m_iOpenCount; - int m_iOpenSize; + path_node *destination; + int node_cache_width; + int node_cache_height; + int dirty_node_count; + +private: + ::basic_pathfinder basic_pathfinder; + ::hospital_finder hospital_finder; + ::idle_tile_finder idle_tile_finder; + ::object_visitor object_visitor; }; #endif // CORSIX_TH_TH_PATHFIND_H_ diff -Nru corsix-th-0.30/CorsixTH/Src/th_sound.cpp corsix-th-0.62/CorsixTH/Src/th_sound.cpp --- corsix-th-0.30/CorsixTH/Src/th_sound.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_sound.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -22,52 +22,53 @@ #include "config.h" #include "th_sound.h" -#include +#include #include +#include -THSoundArchive::THSoundArchive() +sound_archive::sound_archive() { - m_pFiles = NULL; - m_pData = NULL; + sound_files = nullptr; + data = nullptr; } -THSoundArchive::~THSoundArchive() +sound_archive::~sound_archive() { - delete[] m_pData; + delete[] data; } -bool THSoundArchive::loadFromTHFile(const unsigned char* pData, size_t iDataLength) +bool sound_archive::load_from_th_file(const uint8_t* pData, size_t iDataLength) { - if(iDataLength < sizeof(uint32_t) + sizeof(th_header_t)) + if(iDataLength < sizeof(uint32_t) + sizeof(sound_dat_file_header)) return false; uint32_t iHeaderPosition = reinterpret_cast(pData + iDataLength)[-1]; - if(static_cast(iHeaderPosition) >= iDataLength - sizeof(th_header_t)) + if(static_cast(iHeaderPosition) >= iDataLength - sizeof(sound_dat_file_header)) return false; - m_oHeader = *reinterpret_cast(pData + iHeaderPosition); + header = *reinterpret_cast(pData + iHeaderPosition); - delete[] m_pData; - m_pData = new (std::nothrow) unsigned char[iDataLength]; - if(m_pData == NULL) + delete[] data; + data = new (std::nothrow) uint8_t[iDataLength]; + if(data == nullptr) return false; - memcpy(m_pData, pData, iDataLength); + std::memcpy(data, pData, iDataLength); - m_pFiles = reinterpret_cast(m_pData + m_oHeader.table_position); - m_iFileCount = m_oHeader.table_length / sizeof(th_fileinfo_t); + sound_files = reinterpret_cast(data + header.table_position); + sound_file_count = header.table_length / sizeof(sound_dat_sound_info); return true; } -size_t THSoundArchive::getSoundCount() const +size_t sound_archive::get_number_of_sounds() const { - return m_iFileCount; + return sound_file_count; } -const char* THSoundArchive::getSoundFilename(size_t iIndex) const +const char* sound_archive::get_sound_name(size_t iIndex) const { - if(iIndex >= m_iFileCount) - return NULL; - return m_pFiles[iIndex].filename; + if(iIndex >= sound_file_count) + return nullptr; + return sound_files[iIndex].sound_name; } #define FOURCC(c1, c2, c3, c4) \ @@ -76,9 +77,9 @@ | static_cast(static_cast(c3) << 16) \ | static_cast(static_cast(c4) << 24) ) -size_t THSoundArchive::getSoundDuration(size_t iIndex) +size_t sound_archive::get_sound_duration(size_t iIndex) { - SDL_RWops *pFile = loadSound(iIndex); + SDL_RWops *pFile = load_sound(iIndex); if(!pFile) return 0; @@ -125,12 +126,15 @@ break; iChunkLength -= 16; } + //Finally: if(iFourCC == FOURCC('d','a','t','a')) { iWaveDataLength = iChunkLength; + break; } - if(SDL_RWseek(pFile, iChunkLength + (iChunkLength & 1), SEEK_CUR) == -1) + if(SDL_RWseek(pFile, iChunkLength + (iChunkLength & 1), RW_SEEK_CUR) == -1) { break; + } } SDL_RWclose(pFile); if(iWaveAudioFormat != 1 || iWaveChannelCount == 0 || iWaveSampleRate == 0 @@ -146,179 +150,179 @@ #undef FOURCC -SDL_RWops* THSoundArchive::loadSound(size_t iIndex) +SDL_RWops* sound_archive::load_sound(size_t iIndex) { - if(iIndex >= m_iFileCount) - return NULL; + if(iIndex >= sound_file_count) + return nullptr; - th_fileinfo_t *pFile = m_pFiles + iIndex; - return SDL_RWFromConstMem(m_pData + pFile->position, pFile->length); + sound_dat_sound_info *pFile = sound_files + iIndex; + return SDL_RWFromConstMem(data + pFile->position, pFile->length); } #ifdef CORSIX_TH_USE_SDL_MIXER -THSoundEffects* THSoundEffects::ms_pSingleton = NULL; +sound_player* sound_player::singleton = nullptr; -THSoundEffects::THSoundEffects() +sound_player::sound_player() { - m_ppSounds = NULL; - m_iSoundCount = 0; - ms_pSingleton = this; - m_iCameraX = 0; - m_iCameraY = 0; - m_fCameraRadius = 1.0; - m_fMasterVolume = 1.0; - m_fSoundEffectsVolume = 0.5; - m_iPostionlessVolume = MIX_MAX_VOLUME; - m_bSoundEffectsOn = true; + sounds = nullptr; + sound_count = 0; + singleton = this; + camera_x = 0; + camera_y = 0; + camera_radius = 1.0; + master_volume = 1.0; + sound_effect_volume = 0.5; + positionless_volume = MIX_MAX_VOLUME; + sound_effects_enabled = true; #define NUM_CHANNELS 32 #if NUM_CHANNELS >= 32 - m_iChannelStatus = ~0; + available_channels_bitmap = ~0; Mix_AllocateChannels(32); #else - m_iChannelStatus = (1 << NUM_CHANNELS) - 1; + channels_in_use_bitmap = (1 << NUM_CHANNELS) - 1; Mix_AllocateChannels(NUM_CHANNELS); #endif #undef NUM_CHANNELS - Mix_ChannelFinished(_onChannelFinish); + Mix_ChannelFinished(on_channel_finished); } -THSoundEffects::~THSoundEffects() +sound_player::~sound_player() { - setSoundArchive(NULL); - if(ms_pSingleton == this) - ms_pSingleton = NULL; + populate_from(nullptr); + if(singleton == this) + singleton = nullptr; } -void THSoundEffects::_onChannelFinish(int iChannel) +void sound_player::on_channel_finished(int iChannel) { - THSoundEffects *pThis = getSingleton(); - if(pThis == NULL) + sound_player *pThis = get_singleton(); + if(pThis == nullptr) return; - pThis->releaseChannel(iChannel); + pThis->release_channel(iChannel); } -THSoundEffects* THSoundEffects::getSingleton() +sound_player* sound_player::get_singleton() { - return ms_pSingleton; + return singleton; } -void THSoundEffects::setSoundArchive(THSoundArchive *pArchive) +void sound_player::populate_from(sound_archive *pArchive) { - for(size_t i = 0; i < m_iSoundCount; ++i) + for(size_t i = 0; i < sound_count; ++i) { - Mix_FreeChunk(m_ppSounds[i]); + Mix_FreeChunk(sounds[i]); } - delete[] m_ppSounds; - m_ppSounds = NULL; - m_iSoundCount = 0; + delete[] sounds; + sounds = nullptr; + sound_count = 0; - if(pArchive == NULL) + if(pArchive == nullptr) return; - m_ppSounds = new Mix_Chunk*[pArchive->getSoundCount()]; - for(; m_iSoundCount < pArchive->getSoundCount(); ++m_iSoundCount) + sounds = new Mix_Chunk*[pArchive->get_number_of_sounds()]; + for(; sound_count < pArchive->get_number_of_sounds(); ++sound_count) { - m_ppSounds[m_iSoundCount] = NULL; - SDL_RWops *pRwop = pArchive->loadSound(m_iSoundCount); + sounds[sound_count] = nullptr; + SDL_RWops *pRwop = pArchive->load_sound(sound_count); if(pRwop) { - m_ppSounds[m_iSoundCount] = Mix_LoadWAV_RW(pRwop, 1); - if(m_ppSounds[m_iSoundCount]) - Mix_VolumeChunk(m_ppSounds[m_iSoundCount], MIX_MAX_VOLUME); + sounds[sound_count] = Mix_LoadWAV_RW(pRwop, 1); + if(sounds[sound_count]) + Mix_VolumeChunk(sounds[sound_count], MIX_MAX_VOLUME); } } } -void THSoundEffects::playSound(size_t iIndex, double dVolume) +void sound_player::play(size_t iIndex, double dVolume) { - if(m_iChannelStatus == 0 || iIndex >= m_iSoundCount || !m_ppSounds[iIndex]) + if(available_channels_bitmap == 0 || iIndex >= sound_count || !sounds[iIndex]) return; - _playRaw(iIndex, (int)(m_iPostionlessVolume*dVolume)); + play_raw(iIndex, (int)(positionless_volume * dVolume)); } -void THSoundEffects::playSoundAt(size_t iIndex, int iX, int iY) +void sound_player::play_at(size_t iIndex, int iX, int iY) { - if(m_bSoundEffectsOn) - playSoundAt(iIndex, m_fSoundEffectsVolume, iX, iY); + if(sound_effects_enabled) + play_at(iIndex, sound_effect_volume, iX, iY); } -void THSoundEffects::playSoundAt(size_t iIndex, double dVolume, int iX, int iY) +void sound_player::play_at(size_t iIndex, double dVolume, int iX, int iY) { - if(m_iChannelStatus == 0 || iIndex >= m_iSoundCount || !m_ppSounds[iIndex]) + if(available_channels_bitmap == 0 || iIndex >= sound_count || !sounds[iIndex]) return; - double fDX = (double)(iX - m_iCameraX); - double fDY = (double)(iY - m_iCameraY); + double fDX = (double)(iX - camera_x); + double fDY = (double)(iY - camera_y); double fDistance = sqrt(fDX * fDX + fDY * fDY); - if(fDistance > m_fCameraRadius) + if(fDistance > camera_radius) return; - fDistance = fDistance / m_fCameraRadius; + fDistance = fDistance / camera_radius; - double fVolume = m_fMasterVolume * (1.0 - fDistance * 0.8) * (double)MIX_MAX_VOLUME * dVolume; + double fVolume = master_volume * (1.0 - fDistance * 0.8) * (double)MIX_MAX_VOLUME * dVolume; - _playRaw(iIndex, (int)(fVolume + 0.5)); + play_raw(iIndex, (int)(fVolume + 0.5)); } -void THSoundEffects::setSoundEffectsVolume(double dVolume) +void sound_player::set_sound_effect_volume(double dVolume) { - m_fSoundEffectsVolume = dVolume; + sound_effect_volume = dVolume; } -void THSoundEffects::setSoundEffectsOn(bool bOn) +void sound_player::set_sound_effects_enabled(bool bOn) { - m_bSoundEffectsOn = bOn; + sound_effects_enabled = bOn; } -int THSoundEffects::reserveChannel() +int sound_player::reserve_channel() { // NB: Callers ensure that m_iChannelStatus != 0 int iChannel = 0; - for(; (m_iChannelStatus & (1 << iChannel)) == 0; ++iChannel) {} - m_iChannelStatus &=~ (1 << iChannel); + for(; (available_channels_bitmap & (1 << iChannel)) == 0; ++iChannel) {} + available_channels_bitmap &=~ (1 << iChannel); return iChannel; } -void THSoundEffects::releaseChannel(int iChannel) +void sound_player::release_channel(int iChannel) { - m_iChannelStatus |= (1 << iChannel); + available_channels_bitmap |= (1 << iChannel); } -void THSoundEffects::_playRaw(size_t iIndex, int iVolume) +void sound_player::play_raw(size_t iIndex, int iVolume) { - int iChannel = reserveChannel(); + int iChannel = reserve_channel(); Mix_Volume(iChannel, iVolume); - Mix_PlayChannelTimed(iChannel, m_ppSounds[iIndex], 0, -1); + Mix_PlayChannelTimed(iChannel, sounds[iIndex], 0, -1); } -void THSoundEffects::setCamera(int iX, int iY, int iRadius) +void sound_player::set_camera(int iX, int iY, int iRadius) { - m_iCameraX = iX; - m_iCameraY = iY; - m_fCameraRadius = (double)iRadius; - if(m_fCameraRadius < 0.001) - m_fCameraRadius = 0.001; + camera_x = iX; + camera_y = iY; + camera_radius = (double)iRadius; + if(camera_radius < 0.001) + camera_radius = 0.001; } #else // CORSIX_TH_USE_SDL_MIXER -THSoundEffects::THSoundEffects() {} -THSoundEffects::~THSoundEffects() {} -THSoundEffects* THSoundEffects::getSingleton() {return NULL;} -void THSoundEffects::setSoundArchive(THSoundArchive *pArchive) {} -void THSoundEffects::playSound(size_t iIndex, double dVolume) {} -void THSoundEffects::playSoundAt(size_t iIndex, int iX, int iY) {} -void THSoundEffects::playSoundAt(size_t iIndex, double dVolume, int iX, int iY) {} -int THSoundEffects::reserveChannel() { return 0; } -void THSoundEffects::releaseChannel(int iChannel) {} -void THSoundEffects::setCamera(int iX, int iY, int iRadius) {} -void THSoundEffects::setSoundEffectsVolume(double dVolume) {} -void THSoundEffects::setSoundEffectsOn(bool iOn) {} +sound_effect_player::sound_effect_player() {} +sound_effect_player::~sound_effect_player() {} +sound_effect_player* sound_effect_player::get_singleton() {return nullptr;} +void sound_effect_player::set_sound_archive(THSoundArchive *pArchive) {} +void sound_effect_player::play(size_t iIndex, double dVolume) {} +void sound_effect_player::play_at(size_t iIndex, int iX, int iY) {} +void sound_effect_player::play_at(size_t iIndex, double dVolume, int iX, int iY) {} +int sound_effect_player::reserve_channel() { return 0; } +void sound_effect_player::release_channel(int iChannel) {} +void sound_effect_player::set_camera(int iX, int iY, int iRadius) {} +void sound_effect_player::set_sound_effect_volume(double dVolume) {} +void sound_effect_player::set_sound_effects_enabled(bool iOn) {} #endif // CORSIX_TH_USE_SDL_MIXER diff -Nru corsix-th-0.30/CorsixTH/Src/th_sound.h corsix-th-0.62/CorsixTH/Src/th_sound.h --- corsix-th-0.30/CorsixTH/Src/th_sound.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/th_sound.h 2018-07-21 11:13:17.000000000 +0000 @@ -28,35 +28,35 @@ #endif //! Utility class for accessing Theme Hospital's SOUND-0.DAT -class THSoundArchive +class sound_archive { public: - THSoundArchive(); - ~THSoundArchive(); + sound_archive(); + ~sound_archive(); - bool loadFromTHFile(const unsigned char* pData, size_t iDataLength); + bool load_from_th_file(const uint8_t* pData, size_t iDataLength); //! Returns the number of sounds present in the archive - size_t getSoundCount() const; + size_t get_number_of_sounds() const; //! Gets the name of the sound at a given index - const char* getSoundFilename(size_t iIndex) const; + const char *get_sound_name(size_t iIndex) const; //! Gets the duration (in miliseconds) of the sound at a given index - size_t getSoundDuration(size_t iIndex); + size_t get_sound_duration(size_t iIndex); //! Opens the sound at a given index into an SDL_RWops structure /*! The caller is responsible for closing/freeing the result. */ - SDL_RWops* loadSound(size_t iIndex); + SDL_RWops* load_sound(size_t iIndex); -protected: +private: #if CORSIX_TH_USE_PACK_PRAGMAS #pragma pack(push) #pragma pack(1) #endif - struct th_header_t + struct sound_dat_file_header { uint8_t unknown1[50]; uint32_t table_position; @@ -69,9 +69,9 @@ uint8_t unknown4[48]; } CORSIX_TH_PACKED_FLAGS; - struct th_fileinfo_t + struct sound_dat_sound_info { - char filename[18]; + char sound_name[18]; uint32_t position; uint32_t unknown1; uint32_t length; @@ -81,48 +81,49 @@ #pragma pack(pop) #endif - th_header_t m_oHeader; - th_fileinfo_t* m_pFiles; - unsigned char* m_pData; - size_t m_iFileCount; + // TODO: header is only used in one function, should not be class variable. + sound_dat_file_header header; + sound_dat_sound_info* sound_files; + uint8_t* data; + size_t sound_file_count; }; -class THSoundEffects +class sound_player { public: - THSoundEffects(); - ~THSoundEffects(); + sound_player(); + ~sound_player(); - static THSoundEffects* getSingleton(); + static sound_player* get_singleton(); - void setSoundArchive(THSoundArchive *pArchive); + void populate_from(sound_archive *pArchive); - void playSound(size_t iIndex, double dVolume); - void playSoundAt(size_t iIndex, int iX, int iY); - void playSoundAt(size_t iIndex, double dVolume, int iX, int iY); - void setSoundEffectsVolume(double dVolume); - void setSoundEffectsOn(bool bOn); - void setCamera(int iX, int iY, int iRadius); - int reserveChannel(); - void releaseChannel(int iChannel); + void play(size_t iIndex, double dVolume); + void play_at(size_t iIndex, int iX, int iY); + void play_at(size_t iIndex, double dVolume, int iX, int iY); + void set_sound_effect_volume(double dVolume); + void set_sound_effects_enabled(bool bOn); + void set_camera(int iX, int iY, int iRadius); + int reserve_channel(); + void release_channel(int iChannel); -protected: +private: #ifdef CORSIX_TH_USE_SDL_MIXER - static THSoundEffects* ms_pSingleton; - static void _onChannelFinish(int iChannel); + static sound_player* singleton; + static void on_channel_finished(int iChannel); - inline void _playRaw(size_t iIndex, int iVolume); + inline void play_raw(size_t iIndex, int iVolume); - Mix_Chunk **m_ppSounds; - size_t m_iSoundCount; - uint32_t m_iChannelStatus; - int m_iCameraX; - int m_iCameraY; - double m_fCameraRadius; - double m_fMasterVolume; - double m_fSoundEffectsVolume; - int m_iPostionlessVolume; - bool m_bSoundEffectsOn; + Mix_Chunk **sounds; + size_t sound_count; + uint32_t available_channels_bitmap; ///< The bit index corresponding to a channel is 1 if the channel is available and 0 if it is reserved or in use. + int camera_x; + int camera_y; + double camera_radius; + double master_volume; + double sound_effect_volume; + int positionless_volume; + bool sound_effects_enabled; #endif // CORSIX_TH_USE_SDL_MIXER }; diff -Nru corsix-th-0.30/CorsixTH/Src/xmi2mid.cpp corsix-th-0.62/CorsixTH/Src/xmi2mid.cpp --- corsix-th-0.30/CorsixTH/Src/xmi2mid.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/xmi2mid.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -22,7 +22,7 @@ #include "config.h" #ifdef CORSIX_TH_USE_SDL_MIXER -#include +#include #include #include #include @@ -31,49 +31,49 @@ /*! Utility class for reading or writing to memory as if it were a file. */ -class MemoryBuffer +class memory_buffer { public: - MemoryBuffer() - : m_pData(NULL), m_pPointer(NULL), m_pEnd(NULL), m_pBufferEnd(NULL) + memory_buffer() + : data(nullptr), pointer(nullptr), data_end(nullptr), buffer_end(nullptr) { } - MemoryBuffer(const unsigned char* pData, size_t iLength) + memory_buffer(const uint8_t* pData, size_t iLength) { - m_pData = m_pPointer = (char*)pData; - m_pEnd = m_pData + iLength; - m_pBufferEnd = NULL; + data = pointer = (char*)pData; + data_end = data + iLength; + buffer_end = nullptr; } - ~MemoryBuffer() + ~memory_buffer() { - if(m_pBufferEnd != NULL) - delete[] m_pData; + if(buffer_end != nullptr) + delete[] data; } - unsigned char* takeData(size_t *pLength) + uint8_t* take_data(size_t *pLength) { if(pLength) - *pLength = m_pEnd - m_pData; - unsigned char* pResult = (unsigned char*)m_pData; - m_pData = m_pPointer = m_pEnd = m_pBufferEnd = NULL; + *pLength = data_end - data; + uint8_t* pResult = (unsigned char*)data; + data = pointer = data_end = buffer_end = nullptr; return pResult; } size_t tell() const { - return m_pPointer - m_pData; + return pointer - data; } bool seek(size_t position) { - if(m_pData + position > m_pEnd) + if(data + position > data_end) { - if(!_realloc(position)) + if(!resize_buffer(position)) return false; } - m_pPointer = m_pData + position; + pointer = data + position; return true; } @@ -81,25 +81,25 @@ { if(distance < 0) { - if(m_pPointer + distance < m_pData) + if(pointer + distance < data) return false; } - return seek(m_pPointer - m_pData + distance); + return seek(pointer - data + distance); } - bool scanTo(const void* pData, size_t iLength) + bool scan_to(const void* pData, size_t iLength) { - for(; m_pPointer + iLength <= m_pEnd; ++m_pPointer) + for(; pointer + iLength <= data_end; ++pointer) { - if(memcmp(m_pPointer, pData, iLength) == 0) + if(std::memcmp(pointer, pData, iLength) == 0) return true; } return false; } - const char* getPointer() const + const char* get_pointer() const { - return m_pPointer; + return pointer; } template @@ -111,14 +111,14 @@ template bool read(T* values, size_t count) { - if(m_pPointer + sizeof(T) * count > m_pEnd) + if(pointer + sizeof(T) * count > data_end) return false; - memcpy(values, m_pPointer, sizeof(T) * count); - m_pPointer += sizeof(T) * count; + std::memcpy(values, pointer, sizeof(T) * count); + pointer += sizeof(T) * count; return true; } - unsigned int readBigEndianUInt24() + unsigned int read_big_endian_uint24() { uint8_t iByte0, iByte1, iByte2; if(read(iByte0) && read(iByte1) && read(iByte2)) @@ -127,7 +127,7 @@ return 0; } - unsigned int readUIntVar() + unsigned int read_variable_length_uint() { unsigned int iValue = 0; uint8_t iByte; @@ -153,21 +153,21 @@ { if(!skip(static_cast(sizeof(T) * count))) return false; - memcpy(m_pPointer - sizeof(T) * count, values, sizeof(T) * count); + std::memcpy(pointer - sizeof(T) * count, values, sizeof(T) * count); return true; } - bool writeBigEndianUInt16(uint16_t iValue) + bool write_big_endian_uint16(uint16_t iValue) { - return write(_byteSwap(iValue)); + return write(byte_swap(iValue)); } - bool writeBigEndianUInt32(uint32_t iValue) + bool write_big_endian_uint32(uint32_t iValue) { - return write(_byteSwap(iValue)); + return write(byte_swap(iValue)); } - bool writeUIntVar(unsigned int iValue) + bool write_variable_length_uint(unsigned int iValue) { int iByteCount = 1; unsigned int iBuffer = iValue & 0x7F; @@ -185,97 +185,97 @@ return true; } - bool isEOF() const + bool is_end_of_buffer() const { - return m_pPointer == m_pEnd; + return pointer == data_end; } -protected: +private: template - static T _byteSwap(T value) + static T byte_swap(T value) { T swapped = 0; for(int i = 0; i < static_cast(sizeof(T)) * 8; i += 8) { - swapped |= ((value >> i) & 0xFF) << (sizeof(T) * 8 - 8 - i); + swapped = static_cast(swapped | ((value >> i) & 0xFF) << (sizeof(T) * 8 - 8 - i)); } return swapped; } - bool _realloc(size_t size) + bool resize_buffer(size_t size) { - if(m_pData + size <= m_pBufferEnd) + if(data + size <= buffer_end) { - m_pEnd = m_pData + size; + data_end = data + size; return true; } char *pNewData = new (std::nothrow) char[size * 2]; - if(pNewData == NULL) + if(pNewData == nullptr) return false; - size_t iOldLength = m_pEnd - m_pData; - memcpy(pNewData, m_pData, size > iOldLength ? iOldLength : size); - m_pPointer = m_pPointer - m_pData + pNewData; - if(m_pBufferEnd != NULL) - delete[] m_pData; - m_pData = pNewData; - m_pEnd = pNewData + size; - m_pBufferEnd = pNewData + size * 2; + size_t iOldLength = data_end - data; + std::memcpy(pNewData, data, size > iOldLength ? iOldLength : size); + pointer = pointer - data + pNewData; + if(buffer_end != nullptr) + delete[] data; + data = pNewData; + data_end = pNewData + size; + buffer_end = pNewData + size * 2; return true; } - char *m_pData, *m_pPointer, *m_pEnd, *m_pBufferEnd; + char *data, *pointer, *data_end, *buffer_end; }; -struct midi_token_t +struct midi_token { - int iTime; - unsigned int iBufferLength; - const char *pBuffer; - uint8_t iType; - uint8_t iData; + int time; + unsigned int buffer_length; + const char *buffer; + uint8_t type; + uint8_t data; }; -static bool operator < (const midi_token_t& oLeft, const midi_token_t& oRight) +static bool operator < (const midi_token& oLeft, const midi_token& oRight) { - return oLeft.iTime < oRight.iTime; + return oLeft.time < oRight.time; } -struct midi_token_list_t : std::vector +struct midi_token_list : std::vector { - midi_token_t* append(int iTime, uint8_t iType) + midi_token* append(int iTime, uint8_t iType) { - push_back(midi_token_t()); - midi_token_t* pToken = &back(); - pToken->iTime = iTime; - pToken->iType = iType; + push_back(midi_token()); + midi_token* pToken = &back(); + pToken->time = iTime; + pToken->type = iType; return pToken; } }; -unsigned char* TranscodeXmiToMid(const unsigned char* pXmiData, - size_t iXmiLength, size_t* pMidLength) +uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data, + size_t xmi_length, size_t* midi_length) { - MemoryBuffer bufInput(pXmiData, iXmiLength); - MemoryBuffer bufOutput; + memory_buffer bufInput(xmi_data, xmi_length); + memory_buffer bufOutput; - if(!bufInput.scanTo("EVNT", 4) || !bufInput.skip(8)) - return NULL; + if(!bufInput.scan_to("EVNT", 4) || !bufInput.skip(8)) + return nullptr; - midi_token_list_t lstTokens; - midi_token_t* pToken; + midi_token_list lstTokens; + midi_token* pToken; int iTokenTime = 0; int iTempo = 500000; bool bTempoSet = false; bool bEnd = false; uint8_t iTokenType, iExtendedType; - while(!bufInput.isEOF() && !bEnd) + while(!bufInput.is_end_of_buffer() && !bEnd) { while(true) { if(!bufInput.read(iTokenType)) - return NULL; + return nullptr; if(iTokenType & 0x80) break; @@ -283,41 +283,41 @@ iTokenTime += static_cast(iTokenType) * 3; } pToken = lstTokens.append(iTokenTime, iTokenType); - pToken->pBuffer = bufInput.getPointer() + 1; + pToken->buffer = bufInput.get_pointer() + 1; switch(iTokenType & 0xF0) { case 0xC0: case 0xD0: - if(!bufInput.read(pToken->iData)) - return NULL; - pToken->pBuffer = NULL; + if(!bufInput.read(pToken->data)) + return nullptr; + pToken->buffer = nullptr; break; case 0x80: case 0xA0: case 0xB0: case 0xE0: - if(!bufInput.read(pToken->iData)) - return NULL; + if(!bufInput.read(pToken->data)) + return nullptr; if(!bufInput.skip(1)) - return NULL; + return nullptr; break; case 0x90: if(!bufInput.read(iExtendedType)) - return NULL; - pToken->iData = iExtendedType; + return nullptr; + pToken->data = iExtendedType; if(!bufInput.skip(1)) - return NULL; - pToken = lstTokens.append(iTokenTime + bufInput.readUIntVar() * 3, + return nullptr; + pToken = lstTokens.append(iTokenTime + bufInput.read_variable_length_uint() * 3, iTokenType); - pToken->iData = iExtendedType; - pToken->pBuffer = "\0"; + pToken->data = iExtendedType; + pToken->buffer = "\0"; break; case 0xF0: iExtendedType = 0; if(iTokenType == 0xFF) { if(!bufInput.read(iExtendedType)) - return NULL; + return nullptr; if(iExtendedType == 0x2F) bEnd = true; @@ -326,36 +326,36 @@ if(!bTempoSet) { bufInput.skip(1); - iTempo = bufInput.readBigEndianUInt24() * 3; + iTempo = bufInput.read_big_endian_uint24() * 3; bTempoSet = true; bufInput.skip(-4); } else { lstTokens.pop_back(); - if(!bufInput.skip(bufInput.readUIntVar())) - return NULL; + if(!bufInput.skip(bufInput.read_variable_length_uint())) + return nullptr; break; } } } - pToken->iData = iExtendedType; - pToken->iBufferLength = bufInput.readUIntVar(); - pToken->pBuffer = bufInput.getPointer(); - if(!bufInput.skip(pToken->iBufferLength)) - return NULL; + pToken->data = iExtendedType; + pToken->buffer_length = bufInput.read_variable_length_uint(); + pToken->buffer = bufInput.get_pointer(); + if(!bufInput.skip(pToken->buffer_length)) + return nullptr; break; } } if(lstTokens.empty()) - return NULL; + return nullptr; if(!bufOutput.write("MThd\0\0\0\x06\0\0\0\x01", 12)) - return NULL; - if(!bufOutput.writeBigEndianUInt16((iTempo * 3) / 25000)) - return NULL; + return nullptr; + if(!bufOutput.write_big_endian_uint16(static_cast((iTempo * 3) / 25000))) + return nullptr; if(!bufOutput.write("MTrk\xBA\xAD\xF0\x0D", 8)) - return NULL; + return nullptr; std::sort(lstTokens.begin(), lstTokens.end()); @@ -363,50 +363,50 @@ iTokenType = 0; bEnd = false; - for(midi_token_list_t::iterator itr = lstTokens.begin(), + for(midi_token_list::iterator itr = lstTokens.begin(), itrEnd = lstTokens.end(); itr != itrEnd && !bEnd; ++itr) { - if(!bufOutput.writeUIntVar(itr->iTime - iTokenTime)) - return NULL; - iTokenTime = itr->iTime; - if(itr->iType >= 0xF0) + if(!bufOutput.write_variable_length_uint(itr->time - iTokenTime)) + return nullptr; + iTokenTime = itr->time; + if(itr->type >= 0xF0) { - if(!bufOutput.write(iTokenType = itr->iType)) - return NULL; + if(!bufOutput.write(iTokenType = itr->type)) + return nullptr; if(iTokenType == 0xFF) { - if(!bufOutput.write(itr->iData)) - return NULL; - if(itr->iData == 0x2F) + if(!bufOutput.write(itr->data)) + return nullptr; + if(itr->data == 0x2F) bEnd = true; } - if(!bufOutput.writeUIntVar(itr->iBufferLength)) - return NULL; - if(!bufOutput.write(itr->pBuffer, itr->iBufferLength)) - return NULL; + if(!bufOutput.write_variable_length_uint(itr->buffer_length)) + return nullptr; + if(!bufOutput.write(itr->buffer, itr->buffer_length)) + return nullptr; } else { - if(itr->iType != iTokenType) + if(itr->type != iTokenType) { - if(!bufOutput.write(iTokenType = itr->iType)) - return NULL; + if(!bufOutput.write(iTokenType = itr->type)) + return nullptr; } - if(!bufOutput.write(itr->iData)) - return NULL; - if(itr->pBuffer) + if(!bufOutput.write(itr->data)) + return nullptr; + if(itr->buffer) { - if(!bufOutput.write(itr->pBuffer, 1)) - return NULL; + if(!bufOutput.write(itr->buffer, 1)) + return nullptr; } } } uint32_t iLength = static_cast(bufOutput.tell() - 22); bufOutput.seek(18); - bufOutput.writeBigEndianUInt32(iLength); + bufOutput.write_big_endian_uint32(iLength); - return bufOutput.takeData(pMidLength); + return bufOutput.take_data(midi_length); } #endif diff -Nru corsix-th-0.30/CorsixTH/Src/xmi2mid.h corsix-th-0.62/CorsixTH/Src/xmi2mid.h --- corsix-th-0.30/CorsixTH/Src/xmi2mid.h 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/Src/xmi2mid.h 2018-07-21 11:13:17.000000000 +0000 @@ -25,17 +25,17 @@ #include "config.h" #ifdef CORSIX_TH_USE_SDL_MIXER -unsigned char* TranscodeXmiToMid(const unsigned char* pXmiData, - size_t iXmiLength, size_t* pMidLength); +uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data, + size_t xmi_length, size_t* midi_length); #else // CORSIX_TH_USE_SDL_MIXER -inline unsigned char* TranscodeXmiToMid(const unsigned char* pXmiData, - size_t iXmiLength, size_t* pMidLength) +inline uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data, + size_t xmi_length, size_t* midi_length) { // When SDL_mixer isn't being used, there is no need to transocde XMI to // MIDI, so the function always fails. - return NULL; + return nullptr; } #endif // CORSIX_TH_USE_SDL_MIXER diff -Nru corsix-th-0.30/CorsixTH/SrcUnshared/main.cpp corsix-th-0.62/CorsixTH/SrcUnshared/main.cpp --- corsix-th-0.30/CorsixTH/SrcUnshared/main.cpp 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/SrcUnshared/main.cpp 2018-07-21 11:13:17.000000000 +0000 @@ -25,7 +25,9 @@ #include "../Src/bootstrap.h" #include #include - +#ifdef CORSIX_TH_USE_SDL_MIXER +#include +#endif // Template magic for checking type equality template struct types_equal{ enum{ @@ -37,12 +39,25 @@ result = 1, }; }; +static void cleanup(lua_State* L) +{ +#ifdef CORSIX_TH_USE_SDL_MIXER + while(Mix_QuerySpec(nullptr, nullptr, nullptr)) + { + Mix_CloseAudio(); + } +#endif + SDL_Quit(); + + lua_close(L); +} + //! Program entry point /*! - Prepares a Lua state for, and catches errors from, CorsixTH_lua_main(). By + Prepares a Lua state for, and catches errors from, lua_main(). By executing in Lua mode as soon as possible, errors can be nicely caught sooner, hence this function does as little as possible and leaves the rest - for CorsixTH_lua_main(). + for lua_main(). */ int main(int argc, char** argv) { @@ -69,11 +84,11 @@ "Cannot open Lua state.\n"); return 0; } - lua_atpanic(L, CorsixTH_lua_panic); + lua_atpanic(L, lua_panic); luaL_openlibs(L); lua_settop(L, 0); - lua_pushcfunction(L, CorsixTH_lua_stacktrace); - lua_pushcfunction(L, CorsixTH_lua_main); + lua_pushcfunction(L, lua_stacktrace); + lua_pushcfunction(L, lua_main); // Move command line parameters onto the Lua stack lua_checkstack(L, argc); @@ -91,10 +106,10 @@ } else { - fprintf(stderr, "An error has occured in CorsixTH:\n" + fprintf(stderr, "An error has occurred in CorsixTH:\n" "Uncaught non-string Lua error\n"); } - lua_pushcfunction(L, Bootstrap_lua_error_report); + lua_pushcfunction(L, bootstrap_lua_error_report); lua_insert(L, -2); if(lua_pcall(L, 1, 0, 0) != 0) { @@ -105,29 +120,7 @@ lua_getfield(L, LUA_REGISTRYINDEX, "_RESTART"); bRun = lua_toboolean(L, -1) != 0; - // Get cleanup functions out of the Lua state (but don't run them yet) - std::stack stkCleanup; - lua_getfield(L, LUA_REGISTRYINDEX, "_CLEANUP"); - if(lua_type(L, -1) == LUA_TTABLE) - { - for(unsigned int i = 1; i <= lua_objlen(L, -1); ++i) - { - lua_rawgeti(L, -1, (int)i); - stkCleanup.push((void(*)(void))lua_touserdata(L, -1)); - lua_pop(L, 1); - } - } - - lua_close(L); - - // The cleanup functions are executed _after_ the Lua state is fully - // closed, and in reserve order to that in which they were registered. - while(!stkCleanup.empty()) - { - if(stkCleanup.top() != NULL) - stkCleanup.top()(); - stkCleanup.pop(); - } + cleanup(L); if(bRun) { diff -Nru corsix-th-0.30/CorsixTH/SrcUnshared/SDL_main_win32.c corsix-th-0.62/CorsixTH/SrcUnshared/SDL_main_win32.c --- corsix-th-0.30/CorsixTH/SrcUnshared/SDL_main_win32.c 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/CorsixTH/SrcUnshared/SDL_main_win32.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,394 +0,0 @@ -/* - SDL_main.c, placed in the public domain by Sam Lantinga 4/13/98 - - The WinMain function -- calls your program's main() function -*/ -#ifdef _WIN32 -#define _CRT_SECURE_NO_WARNINGS -#include "config.h" -#ifndef CORSIX_TH_USE_INCLUDED_SDL_MAIN -#pragma comment(lib, "SDLmain") -#else -#include -#include - -#define WIN32_LEAN_AND_MEAN -#include - -#ifdef _WIN32_WCE -# define DIR_SEPERATOR TEXT("\\") -# undef _getcwd -# define _getcwd(str,len) wcscpy(str,TEXT("")) -# define setbuf(f,b) -# define setvbuf(w,x,y,z) -# define fopen _wfopen -# define freopen _wfreopen -# define remove(x) DeleteFile(x) -#else -# define DIR_SEPERATOR TEXT("/") -# include -#endif - -/* Include the SDL main definition header */ -#include "SDL.h" -#include "SDL_main.h" - -#ifdef main -# ifndef _WIN32_WCE_EMULATION -# undef main -# endif /* _WIN32_WCE_EMULATION */ -#endif /* main */ - -/* The standard output files */ -#define STDOUT_FILE TEXT("stdout.txt") -#define STDERR_FILE TEXT("stderr.txt") - -#ifndef NO_STDIO_REDIRECT -# ifdef _WIN32_WCE - static wchar_t stdoutPath[MAX_PATH]; - static wchar_t stderrPath[MAX_PATH]; -# else - static char stdoutPath[MAX_PATH]; - static char stderrPath[MAX_PATH]; -# endif -#endif - -#if defined(_WIN32_WCE) && _WIN32_WCE < 300 -/* seems to be undefined in Win CE although in online help */ -#define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t')) -#endif /* _WIN32_WCE < 300 */ - -static void UnEscapeQuotes( char *arg ) -{ - char *last = NULL; - - while( *arg ) { - if( *arg == '"' && *last == '\\' ) { - char *c_curr = arg; - char *c_last = last; - - while( *c_curr ) { - *c_last = *c_curr; - c_last = c_curr; - c_curr++; - } - *c_last = '\0'; - } - last = arg; - arg++; - } -} - -/* Parse a command line buffer into arguments */ -static int ParseCommandLine(char *cmdline, char **argv) -{ - char *bufp; - char *lastp = NULL; - int argc, last_argc; - - argc = last_argc = 0; - for ( bufp = cmdline; *bufp; ) { - /* Skip leading whitespace */ - while ( isspace(*bufp) ) { - ++bufp; - } - /* Skip over argument */ - if ( *bufp == '"' ) { - ++bufp; - if ( *bufp ) { - if ( argv ) { - argv[argc] = bufp; - } - ++argc; - } - /* Skip over word */ - while ( *bufp && ( *bufp != '"' || *lastp == '\\' ) ) { - lastp = bufp; - ++bufp; - } - } else { - if ( *bufp ) { - if ( argv ) { - argv[argc] = bufp; - } - ++argc; - } - /* Skip over word */ - while ( *bufp && ! isspace(*bufp) ) { - ++bufp; - } - } - if ( *bufp ) { - if ( argv ) { - *bufp = '\0'; - } - ++bufp; - } - - /* Strip out \ from \" sequences */ - if( argv && last_argc != argc ) { - UnEscapeQuotes( argv[last_argc] ); - } - last_argc = argc; - } - if ( argv ) { - argv[argc] = NULL; - } - return(argc); -} - -/* Show an error message */ -static void ShowError(const char *title, const char *message) -{ -/* If USE_MESSAGEBOX is defined, you need to link with user32.lib */ -#ifdef USE_MESSAGEBOX - MessageBox(NULL, message, title, MB_ICONEXCLAMATION|MB_OK); -#else - fprintf(stderr, "%s: %s\n", title, message); -#endif -} - -/* Pop up an out of memory message, returns to Windows */ -static BOOL OutOfMemory(void) -{ - ShowError("Fatal Error", "Out of memory - aborting"); - return FALSE; -} - -/* SDL_Quit() shouldn't be used with atexit() directly because - calling conventions may differ... */ -static void cleanup(void) -{ - SDL_Quit(); -} - -/* Remove the output files if there was no output written */ -static void cleanup_output(void) -{ -#ifndef NO_STDIO_REDIRECT - FILE *file; - int empty; -#endif - - /* Flush the output in case anything is queued */ - fclose(stdout); - fclose(stderr); - -#ifndef NO_STDIO_REDIRECT - /* See if the files have any output in them */ - if ( stdoutPath[0] ) { - file = fopen(stdoutPath, TEXT("rb")); - if ( file ) { - empty = (fgetc(file) == EOF) ? 1 : 0; - fclose(file); - if ( empty ) { - remove(stdoutPath); - } - } - } - if ( stderrPath[0] ) { - file = fopen(stderrPath, TEXT("rb")); - if ( file ) { - empty = (fgetc(file) == EOF) ? 1 : 0; - fclose(file); - if ( empty ) { - remove(stderrPath); - } - } - } -#endif -} - -#if defined(_MSC_VER) && !defined(_WIN32_WCE) -/* The VC++ compiler needs main defined */ -#define console_main main -#endif - -/* This is where execution begins [console apps] */ -int console_main(int argc, char *argv[]) -{ - size_t n; - char *bufp, *appname; - int status; - - /* Get the class name from argv[0] */ - appname = argv[0]; - if ( (bufp=SDL_strrchr(argv[0], '\\')) != NULL ) { - appname = bufp+1; - } else - if ( (bufp=SDL_strrchr(argv[0], '/')) != NULL ) { - appname = bufp+1; - } - - if ( (bufp=SDL_strrchr(appname, '.')) == NULL ) - n = SDL_strlen(appname); - else - n = (bufp-appname); - - bufp = SDL_stack_alloc(char, n+1); - if ( bufp == NULL ) { - return OutOfMemory(); - } - SDL_strlcpy(bufp, appname, n+1); - appname = bufp; - - /* Load SDL dynamic link library */ - if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) { - ShowError("WinMain() error", SDL_GetError()); - return(FALSE); - } - atexit(cleanup_output); - atexit(cleanup); - - /* Sam: - We still need to pass in the application handle so that - DirectInput will initialize properly when SDL_RegisterApp() - is called later in the video initialization. - */ - SDL_SetModuleHandle(GetModuleHandle(NULL)); - - /* Run the application main() code */ - status = SDL_main(argc, argv); - - /* Exit cleanly, calling atexit() functions */ - exit(status); - - /* Hush little compiler, don't you cry... */ - return 0; -} - -/* This is where execution begins [windowed apps] */ -#ifdef _WIN32_WCE -int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int sw) -#else -int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) -#endif -{ - HINSTANCE handle; - char **argv; - int argc; - char *cmdline; -#ifdef _WIN32_WCE - wchar_t *bufp; - int nLen; -#else - char *bufp; - size_t nLen; -#endif -#ifndef NO_STDIO_REDIRECT - DWORD pathlen; -#ifdef _WIN32_WCE - wchar_t path[MAX_PATH]; -#else - char path[MAX_PATH]; -#endif - FILE *newfp; -#endif - - /* Start up DDHELP.EXE before opening any files, so DDHELP doesn't - keep them open. This is a hack.. hopefully it will be fixed - someday. DDHELP.EXE starts up the first time DDRAW.DLL is loaded. - */ - handle = LoadLibrary(TEXT("DDRAW.DLL")); - if ( handle != NULL ) { - FreeLibrary(handle); - } - -#ifndef NO_STDIO_REDIRECT - pathlen = GetModuleFileName(NULL, path, SDL_arraysize(path)); - while ( pathlen > 0 && path[pathlen] != '\\' ) { - --pathlen; - } - path[pathlen] = '\0'; - -#ifdef _WIN32_WCE - wcsncpy( stdoutPath, path, SDL_arraysize(stdoutPath) ); - wcsncat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); -#else - SDL_strlcpy( stdoutPath, path, SDL_arraysize(stdoutPath) ); - SDL_strlcat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); -#endif - - /* Redirect standard input and standard output */ - newfp = freopen(stdoutPath, TEXT("w"), stdout); - -#ifndef _WIN32_WCE - if ( newfp == NULL ) { /* This happens on NT */ -#if !defined(stdout) - stdout = fopen(stdoutPath, TEXT("w")); -#else - newfp = fopen(stdoutPath, TEXT("w")); - if ( newfp ) { - *stdout = *newfp; - } -#endif - } -#endif /* _WIN32_WCE */ - -#ifdef _WIN32_WCE - wcsncpy( stderrPath, path, SDL_arraysize(stdoutPath) ); - wcsncat( stderrPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); -#else - SDL_strlcpy( stderrPath, path, SDL_arraysize(stderrPath) ); - SDL_strlcat( stderrPath, DIR_SEPERATOR STDERR_FILE, SDL_arraysize(stderrPath) ); -#endif - - newfp = freopen(stderrPath, TEXT("w"), stderr); -#ifndef _WIN32_WCE - if ( newfp == NULL ) { /* This happens on NT */ -#if !defined(stderr) - stderr = fopen(stderrPath, TEXT("w")); -#else - newfp = fopen(stderrPath, TEXT("w")); - if ( newfp ) { - *stderr = *newfp; - } -#endif - } -#endif /* _WIN32_WCE */ - - setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */ - setbuf(stderr, NULL); /* No buffering */ -#endif /* !NO_STDIO_REDIRECT */ - -#ifdef _WIN32_WCE - nLen = wcslen(szCmdLine)+128+1; - bufp = SDL_stack_alloc(wchar_t, nLen*2); - wcscpy (bufp, TEXT("\"")); - GetModuleFileName(NULL, bufp+1, 128-3); - wcscpy (bufp+wcslen(bufp), TEXT("\" ")); - wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp)); - nLen = wcslen(bufp)+1; - cmdline = SDL_stack_alloc(char, nLen); - if ( cmdline == NULL ) { - return OutOfMemory(); - } - WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL); -#else - /* Grab the command line */ - bufp = GetCommandLine(); - nLen = SDL_strlen(bufp)+1; - cmdline = SDL_stack_alloc(char, nLen); - if ( cmdline == NULL ) { - return OutOfMemory(); - } - SDL_strlcpy(cmdline, bufp, nLen); -#endif - - /* Parse it into argv and argc */ - argc = ParseCommandLine(cmdline, NULL); - argv = SDL_stack_alloc(char*, argc+1); - if ( argv == NULL ) { - return OutOfMemory(); - } - ParseCommandLine(cmdline, argv); - - /* Run the main program (after a little SDL initialization) */ - console_main(argc, argv); - - /* Hush little compiler, don't you cry... */ - return 0; -} - -#endif -#endif diff -Nru corsix-th-0.30/debian/bzr-builder.manifest corsix-th-0.62/debian/bzr-builder.manifest --- corsix-th-0.30/debian/bzr-builder.manifest 2014-04-04 19:57:41.000000000 +0000 +++ corsix-th-0.62/debian/bzr-builder.manifest 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -# bzr-builder format 0.3 deb-version 0.30-0~git201404041957 -lp:corsix-th revid:svn-v4:c39591fa-788f-11de-a72b-d90af8dea425:trunk:2693 -nest-part packaging lp:~kalon33/+junk/corsix-th-packaging debian debian revid:kalon33@ubuntu.com-20140121193703-04ufelbwfqfnie57 diff -Nru corsix-th-0.30/debian/changelog corsix-th-0.62/debian/changelog --- corsix-th-0.30/debian/changelog 2014-04-04 19:57:41.000000000 +0000 +++ corsix-th-0.62/debian/changelog 2018-12-23 10:34:14.000000000 +0000 @@ -1,24 +1,84 @@ -corsix-th (0.30-0~git201404041957~ubuntu12.04.1) precise; urgency=low +corsix-th (0.62-1~ppa12.04+1) precise; urgency=medium - * Auto build. + * Merge from Debian Unstable. - -- Nicolas DERIVE Fri, 04 Apr 2014 19:57:41 +0000 + -- Nicolas Derive Sun, 23 Dec 2018 11:34:14 +0100 -corsix-th (0.7) natty; urgency=low +corsix-th (0.62-1) unstable; urgency=medium - * New upstream svn snapshot. + [ Phil Morrell ] + * add gbp.conf + * add contrib disclaimer + * lintian testsuite fix, bump metadata + * allow more variety in signature files + * fix dh_auto_test nocheck indentation #902392 + * add more verbose flags for S-V 4.2 + * remove obsolete packaging + * convert manpage to markdown, build with pandoc - -- Nicolas Derive Wed, 14 Sep 2011 22:15:27 +0200 + [ Sebastian Ramacher ] + * New upstream version 0.62 + * debian/: Make cmake install files in correct location. + * debian/copyright: Update copyright info + * debian/control: + - Recommend timidity. (Closes: #904838) + - Update ffmpeg Build-Depends according to build system. -corsix-th (0.6+svn20110328~ppa10.10+1) maverick; urgency=low + -- Phil Morrell Mon, 13 Aug 2018 14:59:23 +0100 - * New upstream svn snapshot, to hopefully cure some annoying bugs. - * Include them as a patch (debian-changes) for now. +corsix-th (0.61-1) unstable; urgency=medium - -- Nicolas Derive Mon, 28 Mar 2011 23:48:54 +0200 + [ Alexandre Detiste ] + * New upstream version 0.61 -corsix-th (0.0.0~beta6-1~getdeb1) lucid; urgency=low + [ Phil Morrell ] + * add pedantic lintian overrides + * use https copyright-format url for policy v4.0.0 + * bump Standards-Version, no changes needed + * add upstream signature to verify releases + * drop patches released upstream + * update main copyright authors from LICENSE.txt + * Change Vcs-* to point to salsa.debian.org - * Initial release (LP: #700902) + -- Phil Morrell Thu, 11 Jan 2018 22:42:02 +0000 - -- Christoph Korn Sat, 26 Mar 2011 18:12:05 +0100 +corsix-th (0.60-2) unstable; urgency=medium + + * remove obsolete rnc.pp copyright comment. + Thanks to Alexandre Detiste + * enable unit tests with newly packaged lua-busted + * more flexible tag matching in debian/watch + * bump debhelper compat to 10 + + -- Phil Morrell Tue, 15 Nov 2016 18:08:55 +0000 + +corsix-th (0.60-1) unstable; urgency=medium + + [ Alexandre Detiste ] + * New upstream release. + + [ Phil Morrell ] + * drop all non-debian patches merged upstream + * backport include_campaigns.patch pushed upstream + * backport editor_drag_performance.patch for usability + * drop obsolete lintian-overrides + * bump Standards-Version + * add new project website URL + * add copyright for new campaign by ChrizmanTV + * update main copyright authors from LICENSE.txt + + -- Phil Morrell Wed, 22 Jun 2016 23:05:26 +0100 + +corsix-th (0.50-2) unstable; urgency=medium + + * backport upstream patch to build with ffmpeg 3.0 (Closes: #821415) + * use v4 watch file to include pre-releases + * wrap-and-sort -satb + + -- Phil Morrell Mon, 18 Apr 2016 19:20:40 +0100 + +corsix-th (0.50-1) unstable; urgency=medium + + * Initial release. (Closes: #610087) + + -- Alexandre Detiste Mon, 29 Feb 2016 15:05:38 +0100 diff -Nru corsix-th-0.30/debian/clean corsix-th-0.62/debian/clean --- corsix-th-0.30/debian/clean 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/clean 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1,9 @@ +CMakeCache.txt +CMakeFiles/ +CorsixTH/CMakeFiles/ +Makefile +cmake_install.cmake +CorsixTH/Makefile +CorsixTH/Src/config.h +CorsixTH/cmake_install.cmake +doc/index.html diff -Nru corsix-th-0.30/debian/compat corsix-th-0.62/debian/compat --- corsix-th-0.30/debian/compat 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/compat 2018-12-23 10:34:11.000000000 +0000 @@ -1 +1 @@ -7 +9 diff -Nru corsix-th-0.30/debian/control corsix-th-0.62/debian/control --- corsix-th-0.30/debian/control 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/control 2018-12-23 10:33:00.000000000 +0000 @@ -1,31 +1,62 @@ Source: corsix-th -Section: games +Section: contrib/games Priority: optional -Maintainer: Nicolas Derive -XSBC-Original-Maintainer: Christoph Korn -Build-Depends: debhelper (>= 7.0.50~), cmake, - libsdl1.2-dev, libsdl-mixer1.2-dev, liblua5.1-0-dev, libluajit-5.1-dev, - libfreetype6-dev, wx2.8-headers, libswscale-dev, libpostproc-dev, - libavformat-dev, libavdevice-dev, libavcodec-dev, libswresample-dev -Standards-Version: 3.9.1 -Homepage: https://code.google.com/p/corsix-th/ +Maintainer: Debian Games Team +Uploaders: + Alexandre Detiste , + Phil Morrell , +Build-Depends: + cmake, + debhelper (>= 9), + imagemagick, + libavcodec-dev (>= 7:2.8), + libavformat-dev (>= 7:2.8), + libfreetype6-dev, + liblua5.2-dev, + libsdl2-dev, + libsdl2-mixer-dev, + libswresample-dev (>= 7:2.8), + libswscale-dev (>= 7:2.8), + lua-busted, + lua5.2, + pandoc, +Standards-Version: 4.2.0 +Homepage: http://corsixth.com +Vcs-Git: https://salsa.debian.org/games-team/corsix-th.git +Vcs-Browser: https://salsa.debian.org/games-team/corsix-th Package: corsix-th Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} +Depends: + corsix-th-data (= ${source:Version}), + lua-filesystem, + lua-lpeg, + ${misc:Depends}, + ${shlibs:Depends}, +Recommends: + theme-hospital-data | theme-hospital-demo-data | game-data-packager, + timidity, Description: Open source clone of Theme Hospital - As computers evolve, we risk losing some classic games. - Bullfrog's Theme Hospital, published in 1997, is a - classic simulation game, but getting it to run - natively on modern operating systems is getting - progressively harder. + Theme Hospital was a simulation computer game developed by Bullfrog + Productions and published by Electronic Arts in 1997, in which the player + designs and operates a hospital. . - This project aims to reimplement the game engine - of Theme Hospital, and be able to load the original - game data files. This means that you will need a - purchased copy of Theme Hospital, or a copy of the - demo, in order to use CorsixTH. After most of the - original engine has been reimplemented in open - source code, the project will serve as a base from - which extensions and improvements to the original - game can be made. + The game currently requires the original graphics and tries to mimic the + original as closely as possible. Therefore you will need a copy of the + original game for this package to be useful. + +Package: corsix-th-data +Architecture: all +Multi-Arch: foreign +Depends: + ${misc:Depends}, +Description: Open source clone of Theme Hospital (data package) + Theme Hospital was a simulation computer game developed by Bullfrog + Productions and published by Electronic Arts in 1997, in which the player + designs and operates a hospital. + . + The game currently requires the original graphics and tries to mimic the + original as closely as possible. Therefore you will need a copy of the + original game for this package to be useful. + . + (This package contains the data files) diff -Nru corsix-th-0.30/debian/copyright corsix-th-0.62/debian/copyright --- corsix-th-0.30/debian/copyright 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/copyright 2018-08-13 01:26:00.000000000 +0000 @@ -1,46 +1,319 @@ -This work was packaged for Debian by: +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: CorsixTH +Upstream-Contact: Stephen E. Baker +Source: https://github.com/CorsixTH/CorsixTH +Disclaimer: This package is not part of Debian due to lack of Free assets. It + is only possible to run the free engine with the original proprietary assets. +License: Expat - Christoph Korn on Sat, 26 Mar 2011 18:12:05 +0100 - -It was downloaded from: - - https://code.google.com/p/corsix-th/downloads/list +Files: * +Copyright: + © 2009-2016 Peter "Corsix" Cawley + © 2009-2016 Edvin "Lego3" Linge, + © 2009-2013 Manuel "Roujin" Wolf + © 2009-2012,2014 Nicolas "MeV" Elie + © 2009 Haico "brainball" van Roeden + © 2009-2012 Darrel "redneon" Blake + © 2009 Manuel König + © 2010 M.Chalon + © 2010 Sjors Gielen + © 2010 Sam Wong + © 2010 Edwin "Dutchy" Smulders + © 2010 Miika-Petteri Matikainen + © 2010-2016 Erlend Mongstad + © 2010-2011 Ole "Froksen" Frandsen + © 2010 Robin "RobseRob" Madsen + © 2010 RAS + © 2010 Jukka Kauppinen + © 2010 "Fabiomsouto" + © 2010 Justin Pasher + © 2010 Wendell Misiedjan + © 2011 David "ChronosHD" Horváth + © 2011 Adam Kirk + © 2011 Ted "IntelOrca" John + © 2011 Chris James + © 2011 John Pirie + © 2011-2015 Mark Lawlor + © 2011-2016 William "Sadger" Gatens + © 2011-2017 Ola "Grimdoc" Skogrand + © 2011-2015 Jørgen P. Tjernø + © 2011-2012 Zbyněk "teh dude :D" Schwarz + © 2011 Rene "Kleeze" Bergfort + © 2011-2012 Sérgio "Get_It" Ribeiro + © 2011 Sergei Larionov + © 2011 Alexey Pinyagin + © 2012-2018 Stephen "TheCycoONE" Baker + © 2012 Alex Ghiran + © 2012-2013 Luis "Driver" Duarte + © 2012-2013 Ryan Hugh Dean + © 2012 Henrique Poyatos + © 2012 lwglwsss + © 2013 Koanxd aka Snowblind + © 2013 Chris "ChrizmanTV" Wilkinson + © 2013-2014 Alan Woolley + © 2013 YoungSeok Yoon + © 2013-2015 Maarten Peters + © 2013 nullstein + © 2013 BuTcHeR (extragry.pl) + © 2013-2017 Albert "Alberth" Hofkamp + © 2014-2015 Joseph "J-Shep" Sheppard + © 2014 Phillipp Röll + © 2014 Leonardo "LeonardoGamer" Malaman + © 2015 Víctor "mccunyao" González + © 2015 Josh Keegan + © 2016,2018 Toby Lane + © 2016 Phil Morrell + © 2017 Arne Zelasko + © 2017 Víctor "IlDucci" + © 2017 "wolfy1339" + © 2017 Fang Xianfu + © 2017 Steven Price + © 2017 Radomir Wojtera + © 2017 David Fairbrother + © 2017-2018 Altieres Lima + © 2017-2018 Justin "mugmuggy" Mugford + © 2018 Pavel Schoffer +License: Expat -Upstream Authors: +Files: debian/* +Copyright: + © 2011-2013 Chris Butler + © 2015-2018 Alexandre Detiste + © 2016-2018 Phil Morrell +License: Expat + +Files: + common/rnc.cpp +Copyright: 2009 Jon Skeet, Simon Tatham + 2011 Edvin "Lego3" Linge +License: Expat + +Files: CMake/CMakeFFmpegLibavMacros.cmake +Copyright: cmake project +License: BSD-3-Clause - Peter "Corsix" Cawley - Edvin "Lego3" Linge - Haico "brainball" van Roeden - Manuel "Roujin" Wolf, et al. +Files: CMake/FindFFmpeg.cmake + CMake/FindLibAV.cmake +Copyright: + © 2006, Matthias Kretz, + © 2008, Alexander Neundorf, + © 2011, Michael Jansen, + © 2013, Stephen Baker + © 2015, Alexander Bessman +License: BSD-3-Clause +Files: CMake/FindSDL2.cmake + CMake/FindSDL2_mixer.cmake Copyright: + © 2003-2009 Kitware, Inc. + © 2012 Benjamin Eikel +License: BSD-3-Clause + +Files: CMake/FindVLD.cmake +Copyright: © 2014 Stephen E. Baker +License: Public-Domain + +Files: CorsixTH/Campaigns/* +Copyright: © 2013 Chris "ChrizmanTV" Wilkinson +License: Expat - Copyright (C) 2009-2010 Peter "Corsix" Cawley, Edvin "Lego3" Linge, - Haico "brainball" van Roeden, Manuel "Roujin" Wolf, et al. +Files: CorsixTH/Lua/languages/brazilian_portuguese.lua +Copyright: + © 2010 Manuel "Roujin" Wolf + © 2012 Henrique Poyatos + © 2014 Leonardo Malaman (LeonardoGamer) +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/czech.lua +Copyright: © 2011-2012 +License: BSD-3-Clause -License: - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. +Files: CorsixTH/Lua/languages/danish.lua +Copyright: + © 2010 Robin Madsen (RobseRob) + © 2010-2011 Ole Frandsen (Froksen) + © 2011 Rene Bergfort (Kleeze) +License: BSD-3-Clause -The Debian packaging is: +Files: CorsixTH/Lua/languages/dutch.lua +Copyright: + © 2010 RAS + © 2011 FlyingBastard, L_konings, Nossah, KasperVld + © 2012-2013 Omni, Maarten +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/english.lua + CorsixTH/Lua/languages/original_strings.lua +Copyright: © 2010 Manuel "Roujin" Wolf +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/finnish.lua +Copyright: © 2010 Jukka Kauppinen +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/french.lua +Copyright: © 2010-2015 Nicolas "MeV" Elie +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/german.lua +Copyright: © 2010 Manuel "Roujin" Wolf +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/hungarian.lua +Copyright: © 2011 David "ChronosHD" Horváth & Adam Kirkósa +License: BSD-3-Clause - Copyright (C) 2011 Christoph Korn +Files: CorsixTH/Lua/languages/iberic_portuguese.lua +Copyright: + © 2010 Manuel "Roujin" Wolf, "Fabiomsouto" + © 2011 Sérgio "Get_It" Ribeiro + © 2012 +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/italian.lua +Copyright: © 2010 Manuel "Roujin" Wolf +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/korean.lua +Copyright: © 2013 nullstein +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/norwegian.lua +Copyright: © 2015 Erlend Mongstad, Ola Skogrand +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/polish.lua +Copyright: © 2013 BuTcHeR (extragry.pl) +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/russian.lua +Copyright: © 2011 Sergei Larionov, Alexey Pinyagin +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/simplified_chinese.lua + CorsixTH/Lua/languages/traditional_chinese.lua +Copyright: © 2012 lwglwsss +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/spanish.lua +Copyright: © 2010 Víctor González a.k.a. "mccunyao" +License: BSD-3-Clause + +Files: CorsixTH/Lua/languages/swedish.lua +Copyright: © 2010 Manuel "Roujin" Wolf, Edvin "Lego3" Linge +License: BSD-3-Clause -and is licensed under the GPL version 3, -see "/usr/share/common-licenses/GPL-3". +Files: CorsixTH/Src/random.c +Copyright: + © 1997-2002 Makoto Matsumoto and Takuji Nishimura + © 2005 Mutsuo Saito +License: BSD-3-Clause + +Files: LevelEdit/* +Copyright: 2013 Koanxd aka Snowblind +License: BSD-3-Clause + +Files: SpriteEncoder/* +Copyright: 2013 Albert "Alberth" Hofkamp +License: BSD-3-Clause + +Files: + SpriteEncoder/parser.cpp + SpriteEncoder/tokens.h +Copyright: 2013 Albert "Alberth" Hofkamp +License: GPL-3+-with-Bison-exception + 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 3 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. + . + As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. +Comment: + The source for these files is parser.y, which is BSD-3-Clause. + . + On Debian systems the GNU General Public License (GPL) + version 3 is located on the filesystem at + /usr/share/common-licenses/GPL-3. + +Files: WindowsInstaller/ReplaceInFile.nsh +Copyright: Datenbert +License: zlib + +Files: WindowsInstaller/StrRep.nsh +Copyright: dandaman32 +License: zlib + +License: Public-Domain + The contents of this file are placed in the public domain. + Feel free to make use of it in any way you like. + +License: BSD-3-Clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + . + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License: Expat + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +License: zlib + This software is provided 'as-is', without any express or implied warranty. + In no event will the authors be held liable for any damages arising from the + use of this software. + . + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it freely, + subject to the following restrictions: + . + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. + If you use this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. diff -Nru corsix-th-0.30/debian/corsix-th.6 corsix-th-0.62/debian/corsix-th.6 --- corsix-th-0.30/debian/corsix-th.6 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/corsix-th.6 2018-08-13 13:01:25.000000000 +0000 @@ -0,0 +1,61 @@ +.\" Automatically generated by Pandoc 1.17.2 +.\" +.TH "corsix\-th" "6" "2018\-08\-13" "" "Games Manual" +.hy +.SH NAME +.PP +corsix\-th \- A Theme Hospital engine reimplementation. +.SH SYNOPSIS +.PP +\f[B]corsix\-th\f[] [\-\-interpreter=\f[I]luafile\f[]] [\-\-config\-file +\f[I]configfile\f[]] [\-\-load= \f[I]savefile\f[]] [\-\-dump=strings] +.SH DESCRIPTION +.PP +Theme Hospital was a simulation computer game developed by Bullfrog +Productions and published by Electronic Arts in 1997, in which the +player designs and operates a hospital. +.PP +This project aims to reimplement the game engine of Theme Hospital, and +be able to load the original game data files. +This means that you will need a purchased copy of Theme Hospital, or a +copy of the demo, in order to use CorsixTH. +.PP +On Debian systems these data files can be packaged with +\f[I]game\-data\-packager\f[] +.SH OPTIONS +.PP +This is a list of the options accepted by \f[B]corsix\-th\f[] +.TP +.B \-\-interpreter=\f[I]luafile\f[] +Specify an alternative file to use as the main interpreter (bootstrap +code) +.RS +.RE +.TP +.B \-\-config\-file \f[I]configfile\f[] +Use an alternative configuration file +.RS +.RE +.TP +.B \-\-load=\f[I]savefile\f[] +If specified, loads the given save file immediately on start\-up +.RS +.RE +.TP +.B \-\-dump=strings +Turns on debugging mode +.RS +.RE +.SH FILES +.PP +The save files are stored in \f[I]~/.config/CorsixTH/Saves/\f[] +.SH SEE ALSO +.PP +\f[I]game\-data\-packager\f[](6) +.SH AUTHOR +.PP +CorsixTH was written by Peter "Corsix" Cawley et al. +.PP +Copyright © 2012 Chris Butler \f[I]\f[] Copyright © +2015 Alexandre Detiste \f[I]\f[] This man page was +written for the Debian project, but may be used by others. diff -Nru corsix-th-0.30/debian/corsix-th.6.md corsix-th-0.62/debian/corsix-th.6.md --- corsix-th-0.30/debian/corsix-th.6.md 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/corsix-th.6.md 2018-08-13 13:01:14.000000000 +0000 @@ -0,0 +1,56 @@ +% corsix-th(6) | Games Manual +% +% 2018-08-13 + +# NAME + +corsix-th - A Theme Hospital engine reimplementation. + +# SYNOPSIS + +**corsix-th** [--interpreter=*luafile*] [--config-file *configfile*] [--load= *savefile*] [--dump=strings] + +# DESCRIPTION + +Theme Hospital was a simulation computer game developed by Bullfrog +Productions and published by Electronic Arts in 1997, in which the player +designs and operates a hospital. + +This project aims to reimplement the game engine +of Theme Hospital, and be able to load the original +game data files. This means that you will need a +purchased copy of Theme Hospital, or a copy of the +demo, in order to use CorsixTH. + +On Debian systems these data files can be +packaged with *game-data-packager* + +# OPTIONS +This is a list of the options accepted by **corsix-th** + +--interpreter=*luafile* +: Specify an alternative file to use as the main interpreter (bootstrap code) + +--config-file *configfile* +: Use an alternative configuration file + +--load=*savefile* +: If specified, loads the given save file immediately on start-up + +--dump=strings +: Turns on debugging mode + +# FILES +The save files are stored in *~/.config/CorsixTH/Saves/* + +# SEE ALSO +*game-data-packager*(6) + +# AUTHOR + +CorsixTH was written by Peter "Corsix" Cawley et al. + +Copyright © 2012 Chris Butler ** +Copyright © 2015 Alexandre Detiste ** +This man page was written for the Debian project, +but may be used by others. diff -Nru corsix-th-0.30/debian/corsix-th-data.install corsix-th-0.62/debian/corsix-th-data.install --- corsix-th-0.30/debian/corsix-th-data.install 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/corsix-th-data.install 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1 @@ +usr/share/games/corsix-th diff -Nru corsix-th-0.30/debian/corsix-th.desktop corsix-th-0.62/debian/corsix-th.desktop --- corsix-th-0.30/debian/corsix-th.desktop 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/corsix-th.desktop 2018-08-13 01:26:00.000000000 +0000 @@ -1,9 +1,11 @@ [Desktop Entry] Name=CorsixTH -Exec=/usr/games/corsix-th +Exec=corsix-th Comment=A Theme Hospital Clone +Comment[de]=Ein Klon von Theme Hospital Icon=corsix-th Type=Application Terminal=false -StartupNotify=true -Categories=Game;StrategyGame; +StartupNotify=false +Categories=Game;Simulation; +Keywords=hospital;simulation;bullfrog; diff -Nru corsix-th-0.30/debian/corsix-th.dirs corsix-th-0.62/debian/corsix-th.dirs --- corsix-th-0.30/debian/corsix-th.dirs 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/corsix-th.dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -usr/share/games/corsix-th -usr/lib/games/corsix-th -usr/games diff -Nru corsix-th-0.30/debian/corsix-th.install corsix-th-0.62/debian/corsix-th.install --- corsix-th-0.30/debian/corsix-th.install 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/corsix-th.install 2018-08-13 01:26:00.000000000 +0000 @@ -1,3 +1,2 @@ -debian/scripts/corsix-th usr/games -debian/corsix-th.png usr/share/pixmaps debian/corsix-th.desktop usr/share/applications +usr/games diff -Nru corsix-th-0.30/debian/corsix-th.links corsix-th-0.62/debian/corsix-th.links --- corsix-th-0.30/debian/corsix-th.links 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/corsix-th.links 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/games/corsix-th/CorsixTH usr/share/games/corsix-th/CorsixTH diff -Nru corsix-th-0.30/debian/corsix-th.manpages corsix-th-0.62/debian/corsix-th.manpages --- corsix-th-0.30/debian/corsix-th.manpages 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/corsix-th.manpages 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1 @@ +debian/corsix-th.6 Binary files /tmp/tmpsy5MKU/6eL2TJiqrY/corsix-th-0.30/debian/corsix-th.png and /tmp/tmpsy5MKU/IfX2nixj1n/corsix-th-0.62/debian/corsix-th.png differ diff -Nru corsix-th-0.30/debian/gbp.conf corsix-th-0.62/debian/gbp.conf --- corsix-th-0.30/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/gbp.conf 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1,7 @@ +[buildpackage] +pristine-tar = True +pristine-tar-commit = True + +[import-orig] +pristine-tar = True +uscan = True diff -Nru corsix-th-0.30/debian/patches/default_config.patch corsix-th-0.62/debian/patches/default_config.patch --- corsix-th-0.30/debian/patches/default_config.patch 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/patches/default_config.patch 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1,27 @@ +Subject: default options +Author: Alexandre Detiste +Forwarded: not needed + +The path match the one used by G-D-P. +check_for_update enabled by default is a privacy breach. + +--- a/CorsixTH/Lua/config_finder.lua ++++ b/CorsixTH/Lua/config_finder.lua +@@ -120,7 +120,7 @@ + audio_frequency = 22050, + audio_channels = 2, + audio_buffer_size = 2048, +- theme_hospital_install = [[F:\ThemeHospital\hospital]], ++ theme_hospital_install = [[/usr/share/games/theme-hospital]], + debug = false, + DBGp_client_idehost = nil, + DBGp_client_ideport = nil, +@@ -134,7 +134,7 @@ + shift_scroll_speed = 4, + new_graphics_folder = nil, + use_new_graphics = false, +- check_for_updates = true ++ check_for_updates = false + } + fi = io.open(config_filename, "r") + local config_values = {} diff -Nru corsix-th-0.30/debian/patches/series corsix-th-0.62/debian/patches/series --- corsix-th-0.30/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/patches/series 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1 @@ +default_config.patch diff -Nru corsix-th-0.30/debian/rules corsix-th-0.62/debian/rules --- corsix-th-0.30/debian/rules 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/rules 2018-08-13 12:35:37.000000000 +0000 @@ -1,17 +1,36 @@ #!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + %: dh $@ -override_dh_clean: - dh_clean - find $1 -name .svn -exec rm -rf {} \; &> /dev/null + override_dh_auto_configure: - dh_auto_configure -- -DWITH_FREETYPE2:string="ON" - cp /build/buildd/corsix-th-0.30/LICENSE.txt /build/buildd/corsix-th-0.30/CorsixTH/LICENSE.txt + dh_auto_configure -- -DCMAKE_INSTALL_BINDIR=/usr/games/ -DCMAKE_INSTALL_DATADIR=/usr/share/games/ override_dh_auto_install: dh_auto_install - mv debian/corsix-th/usr/CorsixTH/CorsixTH debian/corsix-th/usr/lib/games/corsix-th/ - #rm debian/corsix-th/usr/CorsixTH/LICENSE.txt - rm debian/corsix-th/usr/CorsixTH/CorsixTH.ico - mv debian/corsix-th/usr/CorsixTH/* debian/corsix-th/usr/share/games/corsix-th - rmdir debian/corsix-th/usr/CorsixTH + rm -v debian/tmp/usr/share/games/corsix-th/LICENSE.txt + + for size in $$(identify ico:CorsixTH/CorsixTH.ico | awk '{print $$3}'); \ + do \ + mkdir -vp debian/corsix-th/usr/share/icons/hicolor/$$size/apps/ ; \ + convert ico:`identify ico:CorsixTH/CorsixTH.ico | sed -n "/ $$size /s/^.*=>\(CorsixTH\/CorsixTH.ico\[[0-9]\+]\) .*/\1/gp"` \ + -verbose debian/corsix-th/usr/share/icons/hicolor/$$size/apps/corsix-th.png ; \ + done + + mkdir -vp debian/corsix-th/usr/share/icons/hicolor/scalable/apps/ + install -vm0644 CorsixTH/Original_Logo.svg debian/corsix-th/usr/share/icons/hicolor/scalable/apps/corsix-th.svg + +override_dh_auto_test: +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) + dh_auto_test + busted -C CorsixTH/Luatest --verbose +endif + +ifeq (,$(filter nodoc,$(DEB_BUILD_OPTIONS))) +build: debian/corsix-th.6 +endif + +%.6: %.6.md + pandoc --verbose --standalone $< --to man --output $@ diff -Nru corsix-th-0.30/debian/scripts/corsix-th corsix-th-0.62/debian/scripts/corsix-th --- corsix-th-0.30/debian/scripts/corsix-th 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/scripts/corsix-th 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -#!/bin/sh -cd /usr/share/games/corsix-th -./CorsixTH $@ diff -Nru corsix-th-0.30/debian/source/format corsix-th-0.62/debian/source/format --- corsix-th-0.30/debian/source/format 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/source/format 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1 @@ +3.0 (quilt) diff -Nru corsix-th-0.30/debian/source/include-binaries corsix-th-0.62/debian/source/include-binaries --- corsix-th-0.30/debian/source/include-binaries 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/source/include-binaries 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -debian/corsix-th.png diff -Nru corsix-th-0.30/debian/source/lintian-overrides corsix-th-0.62/debian/source/lintian-overrides --- corsix-th-0.30/debian/source/lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/source/lintian-overrides 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1,4 @@ +# not worth repacking for 3 unused files +source-contains-autogenerated-visual-c++-file AnimView/AnimView.rc +source-contains-autogenerated-visual-c++-file CorsixTH/CorsixTH.rc +source-contains-autogenerated-visual-c++-file CorsixTH/resource.h diff -Nru corsix-th-0.30/debian/upstream/signing-key.asc corsix-th-0.62/debian/upstream/signing-key.asc --- corsix-th-0.30/debian/upstream/signing-key.asc 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/debian/upstream/signing-key.asc 2018-08-13 01:26:00.000000000 +0000 @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFoM/rcBEADsMX3sL1Z5g4E4DSJEFvt/AJzhcgUf0ou3L9UdvzRhbDr1sWHv ++XReP1Y49xUx0PUViVliUwO9y30axaXjZ/308PcqisCMjlaOWV3rwO0ks25DlTbN +w+fQp+IP6dGY7VbeFtLEF2brTox4/Qi9O9Oad/0oxfgl4JoRS/o5nYSKYV40t2BL +VKBhXMZ37VnQyzPCOhnBJ77r2FjpZsl1dsYxvDz7tzPRXAaUVSxg7k77k8DYQ/Jm +ZwUCIfebhUMud7rE6kUSGtxkI9H2VE2j5Ii1UN55BaKSzrwxNbzAfjGdkHZfsS+Z +cgxafinh3R/vBo+kwqFdy42HCx6Ar5I0LDVV+ufM5YplZ3rHBnFxWCu5yV232GU6 +wD2oy6QmDzvsPPaMBI07TiDKzHuz1nm1Yf2Zus+8qa7cc/kNxMVC9eZwDsTAPAt0 +XE/zOJbRHoySl33GKGlJFGDT/3W6rxDlDh2J6EvO3Qw+lrvZ5y7x9ar12ClKc82r +75yOMtIq3nUX2E8p3C84eWygq7ViIJwiWhiascvAfyrponpH5GnG29wznXRqWksK +n/7TL6yrXpmw+fXz+JgGzVAIhWEWtx/IdunTCJx40F5fdqH3OnxHEBKiVCFENMBk +4ontL+w1ztPpgQ3ZKXOKrc3ovaq1Kfw1ytdOo4qHV3MRu6WSTeRtgYgyqQARAQAB +tCxTdGVwaGVuIEUuIEJha2VyIDxiYWtlci5zdGVwaGVuLmVAZ21haWwuY29tPokC +TgQTAQgAOBYhBNsUfYzWc300IQ0gI1wlGZIDPT18BQJaDP63AhsDBQsJCAcCBhUI +CQoLAgQWAgMBAh4BAheAAAoJEFwlGZIDPT18tQ8QAN44cpG53VmJKAiyPiulC2gx +fg9cv4Wd5pYAJ8rsDO5f7dhzYZ/uZOJD3PCity4VzZQW2tNkUKvMQxsOFLMQ8TZR ++Yi+jqxdinxz8OAdXsZv0rimz4CuNXZiBbgpcvxMx99cQIf2E7C64L7ntBTY4iO2 +OdehZhJ73iFuvVnKFdaz1UQtzIiDvoB71gOtmUJgXL+HPlU2A3lEunfzLZvjuaVn +QCamhj3fE5y9tdbInTF2ciGuPaAekOldLDwgCcdDLQwoJhOZq9RkWcqJFHT3iVad +/h5Q6ahlPmZ7QpnMQg67H8Es9lLEDmq5RauprqWEq/ALt9Z/QaIfkvXy6tigDn72 +uaqWlQchKrkR++HCYZKs0KbXgzmNsB/Y80MTgSvLdldkNxrAhEkDkRcHk6m+b7N2 +V1XyABEvXcAaScDyeZYAO9lg/1NPXU/2NGR33zjOxZtJhNlG5vpVP9N/9yA9qtnh +UZoXNGi9Qt5LtRG2aaBMqAYZhP/yhS9btAzugWUKAUsqqyD7yOWv2vg0zCBXw+Ii +0fBucUo2WfYxWTCz0pXIned5051eV/L90q4L7nylMkHJrA3iMmApcWvjkOSsZmuF +76jqhSINkC9x/DI0uYNzR4002KbAiV/6S/Ys4ws2ehtUh5f02VpaTRGiaGslVn3o +Z45KHeoSd0KJM5i0S7YjuQINBFoM/rcBEAC6OHzglx0RRdSPVaFbYXLOkjywl5r4 +kSYIplChnYzon3FtYeTr//136Hu8LpkHyooj41fcE6B6bxLUelE4JgS2+sKAveLJ +J5Sa5H1wf4G6O9zrLfvdF388ecAahCQDUWD0gykd9MHgY7F/vJz1YKQvkSNpmmxx +3SXDtTdF3ocSyuFRm75ZEoUDf8vP5lDtQT+jQaVG8RsUX5VdI6EvZLFZeix+y+EI +y+paPu64R9Ol+ahdBbwoNmkP/msxkww4oU+W0XtRcGrHVxV3udXhMv6WQbdStSMk +BUTmdp8yz6i8LQqKB05utby7+sXILLZUuplXepTl08bkFeQqmr1JRtYEHVx09Ewn +40W8LCdyxGV2eJy4ct4+EcZj8KI7cNCtyAZjVQpmDX6AtLXRpmOMDQjwD6gC21e0 +7vPMR1jJ0ewRCT6T/WEBwOPuUP9czoTl16mJk/O/g6RghqfJseYfSlscuixJT9fX +ozIQk4/0Xw5sAImbvhqEG49JLM/aEfNU30LaGmz2GdwogiXZTYu7/EBSHFFt6C5s +Osz8g6P57PcRZ4pYZC6B3lvwl9wqtpI7DNxl6GFJTAyPSE33o+xJVeEGPbUp597X +hjlYsC0nnR3LVFW82qN0Mp7BLANbK6mqp9rTD9hVElshT0T9+agNRsu9FMwArF8+ +W1FB4+VMYE+qfwARAQABiQI2BBgBCAAgFiEE2xR9jNZzfTQhDSAjXCUZkgM9PXwF +AloM/rcCGwwACgkQXCUZkgM9PXyujQ//arXdQDAdRPNPtqkAGvpJfnq43ayV96Sv +eJEz4Y6TRYeHw4YzyfaTtLA5NCQS3BPQ+AVQA8pIpBihrc4SSw4Tv8Jd0KjAJLRN +qC5zFxj7ZsAEhozLNtZWRS4hdP+YsvsKqPW5LodI+lKP2hiDZJHsKWSeLlMGYdWL +0uBGWs5taBKP4whHWv6Qz3hCoCduwHMjN9UJJnj6qBbKYKs4OJqChJzNsrlvt3qm +yl+WU0lSb13Y6szV/uBlc3U83x/wY54DFjN9PZ3inS/Gqe7N9/0+1+BByKVX0emQ +VS5UqfEfYayJLceIRN8nakaNypbh1ycf6SYfBK2LEMvKhXNxgQ6qp9q2evAzfsgM +FIxV52KCdSCCM+7zDttd+KWE1+nUfYgTabqGG46919s6yZLUHBouuoCNKHurfIqO +4OZJ4VQ56K4bsxfsuRIARMLIzYKQC0FEXHVRlX0/ppqFn7jsgENxCP80w2zNuUlC +VGWVkNm9t8CIKgxMOLJJh3krtXqiyV1VWlvaklfd8q3ark9jt5NzGI3rlAwG213X +5cIFzCfnx/2uUPtfWXDtYroMLUM7yr7ZtF78zNKc4e8xW60qU9y+514VL0C0bbMV +ysXbejos5RGbzaWGgFoOn9YVUTIivibAjckyYBBWP5C4GjN5+IKRQKnvsvRz8pId +FgMwJilHq38= +=BKam +-----END PGP PUBLIC KEY BLOCK----- diff -Nru corsix-th-0.30/debian/watch corsix-th-0.62/debian/watch --- corsix-th-0.30/debian/watch 2014-04-04 19:57:40.000000000 +0000 +++ corsix-th-0.62/debian/watch 2018-08-13 01:26:00.000000000 +0000 @@ -1,3 +1,10 @@ -version=3 -opts="dversionmangle=s/0\.0\.0~beta/Beta/,uversionmangle=s/Playable//" \ -http://googlecode.debian.net/p/corsix-th/CorsixTH-([^-]+)-Source\.tar\.gz +version=4 + +opts="pgpmode=next,uversionmangle=s/-/~/" \ + https://github.com/CorsixTH/CorsixTH/releases \ + (?:.*/)?v?@ANY_VERSION@@ARCHIVE_EXT@ + +opts="pgpmode=previous,uversionmangle=s/-/~/" \ + https://github.com/CorsixTH/CorsixTH/releases \ + (?:.*/)?(?:CorsixTH)?v?@ANY_VERSION@@SIGNATURE_EXT@ \ + previous diff -Nru corsix-th-0.30/DebianPackage/control corsix-th-0.62/DebianPackage/control --- corsix-th-0.30/DebianPackage/control 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/DebianPackage/control 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -Package: corsix-th -Version: 0.41-r1078 -Installed-Size: 13320 -Source: https://github.com/CorsixTH/CorsixTH -Maintainer: CorsixTH developers -Homepage: https://github.com/CorsixTH/CorsixTH -Priority: optional -Architecture: i386 -Depends: timidity, liblua5.1-0, libsdl-mixer1.2, libsdl1.2debian -Description: A clone of the classic Bullfrog game Theme Hospital - The game uses the original graphics and tries to mimic the original as closely as possible. Note that the game is still in beta, and all features are not yet present. - - - diff -Nru corsix-th-0.30/DebianPackage/debian-binary corsix-th-0.62/DebianPackage/debian-binary --- corsix-th-0.30/DebianPackage/debian-binary 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/DebianPackage/debian-binary 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2.0 diff -Nru corsix-th-0.30/DebianPackage/postinst corsix-th-0.62/DebianPackage/postinst --- corsix-th-0.30/DebianPackage/postinst 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/DebianPackage/postinst 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -#! /bin/bash -e - -ln -fs "/usr/games/CorsixTH/CorsixTH" "/usr/bin/CorsixTH" - -ln -fs "/usr/games/CorsixTH/MapEdit" "/usr/bin/MapEdit" diff -Nru corsix-th-0.30/DebianPackage/prerm corsix-th-0.62/DebianPackage/prerm --- corsix-th-0.30/DebianPackage/prerm 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/DebianPackage/prerm 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -#! /bin/bash -e - -rm "/usr/bin/CorsixTH" - -rm "/usr/bin/MapEdit" diff -Nru corsix-th-0.30/DebianPackage/readme.txt corsix-th-0.62/DebianPackage/readme.txt --- corsix-th-0.30/DebianPackage/readme.txt 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/DebianPackage/readme.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -How to create a debian package in ubuntu: -(should work on other distributions as well, but has not been tested) - -1. Compile the game, if desired the map editor and install them with "make install". For the map editor, make sure wxWidgets has been compiled as static libraries. - -2. Update the file "control" with a new version number. In the same way edit the menu shortcuts in "usr/share/applications". - -3. Create these tarballs in the current directory: - -tar --exclude-vcs -chzf data.tar.gz usr/ -tar -czf control.tar.gz control prerm postinst - -4. Create the package with ar: - -ar rcv corsix-th__.deb debian-binary control.data.gz data.tar.gz - -where should be the same as specified in "control" and either i386 for 32-bit or amd64 for 64-bit packaging. diff -Nru corsix-th-0.30/DebianPackage/usr/share/applications/CorsixTH.desktop corsix-th-0.62/DebianPackage/usr/share/applications/CorsixTH.desktop --- corsix-th-0.30/DebianPackage/usr/share/applications/CorsixTH.desktop 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/DebianPackage/usr/share/applications/CorsixTH.desktop 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -[Desktop Entry] -Name=CorsixTH -Version=0.41-r1078 -Exec=/usr/games/CorsixTH/CorsixTH -Comment=A Theme Hospital Clone -Icon=/usr/games/CorsixTH/CorsixTH.ico -Type=Application -Terminal=false -StartupNotify=true -Encoding=UTF-8 -Categories=Game;StrategyGame; diff -Nru corsix-th-0.30/DebianPackage/usr/share/applications/MapEdit.desktop corsix-th-0.62/DebianPackage/usr/share/applications/MapEdit.desktop --- corsix-th-0.30/DebianPackage/usr/share/applications/MapEdit.desktop 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/DebianPackage/usr/share/applications/MapEdit.desktop 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -[Desktop Entry] -Name=MapEdit -Version=0.41-r1078 -Exec=/usr/games/CorsixTH/MapEdit -Comment=A Map Editor for the Theme Hospital Clone -Icon=/usr/games/CorsixTH/CorsixTH.ico -Type=Application -Terminal=false -StartupNotify=true -Encoding=UTF-8 -Categories=Game;StrategyGame; diff -Nru corsix-th-0.30/DebianPackage/usr/share/doc/corsix-th/copyright corsix-th-0.62/DebianPackage/usr/share/doc/corsix-th/copyright --- corsix-th-0.30/DebianPackage/usr/share/doc/corsix-th/copyright 2014-04-04 19:57:35.000000000 +0000 +++ corsix-th-0.62/DebianPackage/usr/share/doc/corsix-th/copyright 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Copyright (c) 2010 Peter "Corsix" Cawley et al. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff -Nru corsix-th-0.30/DoxyGen/animview.doxygen.in corsix-th-0.62/DoxyGen/animview.doxygen.in --- corsix-th-0.30/DoxyGen/animview.doxygen.in 1970-01-01 00:00:00.000000000 +0000 +++ corsix-th-0.62/DoxyGen/animview.doxygen.in 2018-07-21 11:13:17.000000000 +0000 @@ -0,0 +1,2291 @@ +# Doxyfile 1.8.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "Anim View" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "TH Animation Viewer" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = animview + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = "@CMAKE_SOURCE_DIR@/AnimView" + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /